Common Hibernate mistakes - accessing objects outside of a transaction
Hibernate does require the same EntityManager to be available in order to lazily load objects. If you have no EntityManager, then you have no knowledge of the datastore. Once the transaction is commited the objects become detached, and you can't lazy load detached objects. So, you need to lazily load your objects within the same transaction in your service layer.
For example: Account has one-to-many relationship with AccountAttributes. The AccountAttributes are lazily loaded via getAccountAttributes() method invocation.
The DAO class
@Repository("portfolioDao") public class PortfolioDaoImpl implements PortfolioDao { @PersistenceContext private EntityManager em; @Override public Portfolio getAccountById(Long accountId) { Query query = em.createQuery("from Portfolio as pf where pf.portfolioId = :portfolioId"); query.setParameter("accId", accountId); return (Account) query.getSingleResult(); } }
Wrong:
public class AccountServiceImpl implemnts AccountService { public void processAcoount(Long accountId) { Account account = accountDao.getSccountById(accountId); //good // exception is thrown List<AccountAttributes> accountAttributes = account.getAccountAttributes(); } }
Right: as it is lazily loaded within the same transaction
public class AccountServiceImpl implemnts AccountService { @Transactional public void processAcoount(Long accountId) { Account account = accountDao.getSccountById(accountId); //good // fine, as it is within the same txn, and the EntityManager will still be open. List<AccountAttributes> accountAttributes = account.getAccountAttributes(); } }
Eager fetching is often not a good solution. Having said this there are downsides to lazy loading. The developer has to be aware of his/her fetching strategy and must be capable of differentiating when and where each strategy is most applicable. Otherwise you can end up with serious performance issues like the N+1 Select Problem.
Fetching too much will run into the opposite problem, the cartesian product issue: instead of executing to many SQL statements, you may end up creating statements that retrieve too much data.
Tips:
- Firstly, activate SQL logging at Hibernate's level by turning show_sql to true.
- Run the critical use cases to identify suspicious queries and optimize the fetch plan. Check if indices are used appropriately, etc
Also, watch-out for other pitfalls like
Labels: Hibernate, TransactionMgmt
0 Comments:
Post a Comment
Subscribe to Post Comments [Atom]
<< Home