Slow performance releasing stateless session bean!
jaboj Apr 6, 2006 5:23 AMHI
This issue is about performance when releasing a stateless session bean on JBOSS 4.0.1SP1. The performance problem occurs when
returning from an method in a stateless session bean after selecting a large number of objects from the database. Actually the
same problem is happening after inserting a large number of objects into the database.
In our scenario we've a stateless session bean with a method to return branches for a given company. A company is an
objectwith an one-to-many relationship to branches. See sample code below
To retrieve the branchlist from a specifik company, the first step in the method (A) is to query the company and then
execute the method getBranches() on the company object. In our scenario the branchlist for the company
contains 1000 objects. Getting the branch list and building dto's is done in no time.
But, when the method returns the branchlist (or even just the number of branches) back to the client, then the
container (java.exe) process will take up 100% cpu-time for maybe a minut or more. It seems like the container is
doing some heavy calculations before control is passed back to the client.
If I change the way the method (B) retrieves the branches to an EJB query, then the problem is gone. The query will
still return the same list of 1000 objects and we'll still transform them into dto's. When changing the way to retrieve
the branches, the control is passed back to the client much more efficient - why that?
The main question is - why does the release of a stateless session beans perform very bad when using
one-to-many relations to retrive a large number of objects?
And question number 2. I we create a new CompanyPO and assosiating 1000 branches, then persisting of the CompanyPO
will take up a lot of time and cpu-power, before the control is passed back to the client. Why?
The client is part of the same ear-file and used local interfaces. The java-client is looking up the
stateless session bean like this:
InitialContext ctx = new InitialContext(); CompanyManagementLocal bean = (CompanyManagementLocal)ctx.lookup(CompanyManagementLocal.class.getName());
SAMPLE CODE!
Method A below has very bad performance. It retrieves branches through the getBranches() method on the company
object.
public List<IBranch> getCompanyBranchList(ICompanySimple companyTO) throws HvidvaskException { CompanyDAO dao = new CompanyDAO(em); List<IBranch> resultsList = null; try { CompanyPO company = dao.FindCompanyByCvrNo(companyTO.getCvrNo()); Collection<BranchPO> branches = company.getBranches(); resultsList = DTOBuilder.createBranchList(branches); } catch (DaoException daoEx) { throw new HvidvaskException("Unable to return branch list"); } return resultsList; }
Method B below has very good performance. It retrives branches through a EJB query.
public List<IBranch> getSignedBranchList(ICompanySimple companyTO) throws HvidvaskException { List<IBranch> branchList = null; try { CompanyPO company = em.find(CompanyPO.class, companyTO.getId()); Query q = QueryFactory.createSignedBranchQuery(em, company); Collection<BranchPO> resultList = q.getResultList(); if (resultList != null) { branchList = DTOBuilder.createBranchList(resultList); } } catch (Exception daoEx) { throw new HvidvaskException("Unable to return branch list"); } return branchList; }
CompanyPO and BranchPO persistence objects
@Entity(access=AccessType.FIELD) public class CompanyPO implements Serializable { @Id private int; private String cvrNo; @OneToMany(mappedBy = "company" ,fetch=FetchType.LAZY ,cascade = {CascadeType.PERSIST, CascadeType.MERGE}) private Collection<BranchPO> branches; public CompanyPO() { } ... } public class BranchPO implements StateObject, Serializable { @Id private int id; private String pNo; private String name; @ManyToOne(optional = false ,cascade = {CascadeType.PERSIST, CascadeType.MERGE} ,fetch=FetchType.LAZY) private CompanyPO company; @OneToOne(optional=false, fetch=FetchType.EAGER, cascade={CascadeType.PERSIST, CascadeType.MERGE}) @JoinColumn(name="ADDR_ID", unique=false, nullable=false) private AddressPO address; @OneToOne(optional=true, cascade={CascadeType.PERSIST, CascadeType.MERGE}) @JoinColumn(name="MANAGER_ID", unique=false) private BranchManagerPO manager; @Column(name="currency_exchange") private boolean currencyExchange; ... }