I have a problem to lock some row when I use a projection to get entity count ,and occur nullPointerException ! I stepped through the hibernate code in the debugger. This is a BUG!!There is a long BUG!!
Hibernate version:5.1.0.Final
Code between sessionFactory.openSession() and session.close():
/***********************CODE*****************************/ Criteria criteria = getSession().createCriteria(TbGenerateRecord.class); criteria.setLockMode(LockMode.PESSIMISTIC_WRITE); criteria.setProjection(Projections.rowCount()).uniqueResult(); /***********************CODE*****************************/
soon after,I stepped through the hibernate code in the debugger. The NullPointerException in CriteriaLoader.applyLocks happens because its local "entityAliases" array is null; that array is null because the "aliases" field (defined in OuterJoinLoader) is null. So the question is, where did (or should) OuterJoinLoader.aliases come from? Well, it comes from a method called initFromWalker(JoinWalker walker), which calls walker.getAliases().
So now the question is, what's up with this JoinWalker? In this case, it is a CriteriaJoinWalker, which extends AbstractEntityJoinWalker.
Where, then, does (or should) JoinWalker.aliases get initalized? It happens in a method called initPersisters. This method, in turn, is called by the AbstractEntityJoinWalker.initAll method.
Why isn't CriteriaJoinWalker calling that initAll method? Here's the relevant code in the CriteriaJoinWalker constructor:
/***********************CODE*****************************/ if ( translator.hasProjection() ) {
initProjection(translator.getSelect(),translator.getWhereCondition(),translator.getOrderBy(),translator.getGroupBy(),LockOptions.NONE);
resultTypes = translator.getProjectedTypes();
userAliases = translator.getProjectedAliases();
includeInResultRow = new boolean[resultTypes.length];
Arrays.fill( includeInResultRow, true );
}else {
initAll( translator.getWhereCondition(), translator.getOrderBy(), LockOptions.NONE );
// root entity comes last userAliasList.add( criteria.getAlias() );
//root entity comes *last* resultTypeList.add( translator.getResultType( criteria ) );
includeInResultRowList.add( true );
userAliases = ArrayHelper.toStringArray( userAliasList );
resultTypes = ArrayHelper.toTypeArray( resultTypeList );
includeInResultRow = ArrayHelper.toBooleanArray( includeInResultRowList );
} /***********************CODE*****************************/ So, when there's a projection, we don't call the initAll method, and so the aliases field is never initialized. NPE is not a helpful error message.
If there are solutions, please contact me:2245089166@qq.com
Full stack trace of any exception that occurs: java.lang.NullPointerException at org.hibernate.loader.criteria.CriteriaLoader.applyLocks(CriteriaLoader.java:237) at org.hibernate.loader.Loader.preprocessSQL(Loader.java:234) at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1894) at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1874) at org.hibernate.loader.Loader.doQuery(Loader.java:919) at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:336) at org.hibernate.loader.Loader.doList(Loader.java:2610) at org.hibernate.loader.Loader.listUsingQueryCache(Loader.java:2452) at org.hibernate.loader.Loader.list(Loader.java:2414) at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:109) at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1787) at org.hibernate.internal.CriteriaImpl.list(CriteriaImpl.java:363) at org.hibernate.internal.CriteriaImpl.uniqueResult(CriteriaImpl.java:385) at net.yasion.common.utils.HibernateUtils.countByCriteria(HibernateUtils.java:274) at net.yasion.common.dao.impl.BaseDAOImpl.sourceListByCriteria(BaseDAOImpl.java:574) at net.yasion.common.dao.impl.BaseDAOImpl.listByCriteria(BaseDAOImpl.java:484) at net.yasion.shortlink.service.impl.LinkServiceImpl.shortLink(LinkServiceImpl.java:126) |
|