web-dev-qa-db-ja.com

Hibernate Envers:アサーションエラーが発生しました(これはHibernateのバグを示している可能性がありますが、セッションの安全でない使用が原因である可能性が高いです)

私のJavaアプリでは、HibernateEnversを使用して永続イベントをリッスンしています。リスナークラスは次のようになります。

_@Component
public class DataCreationListener extends EnversPostInsertEventListenerImpl {

    private static final long serialVersionUID = 1L;

    @Autowired
    DataService DataService;

    public DataCreationListener() {
        super(null);
    }

    @Override
    public void onPostInsert(PostInsertEvent event) {

        if (event.getEntity() instanceof DataDAO) {
            Data Data = DataService.fromDao((DataDAO) event.getEntity());
            // other stuff
        }
    }

}
_

fromDAOメソッドで、DAO(エンティティタイプ)オブジェクトをAPIタイプオブジェクトに変換します。これはfromDAOメソッドです

_@Override
    public Data fromDao(DataDAO data) {
        if (data == null) {
            return null;
        }
        Data api = new Data();
        api.setId(data.getIdUser());
        api.setAddress(data.getAddress());
        api.setCity(data.getCity());
        api.setCountry(getCountryFromId(data.getId()));

        return api;
    }
_

getCountryFromId(data.getId())を実行するとエラーが発生します

このメソッドには、エラーが発生したSpring DataJPAリポジトリー呼び出しが含まれます。リポジトリ呼び出しは次のようになります

_repository.findByCountry_Id(dataId);
_

デバッグ時に、dataIdの値がnull以外であり、リポジトリがnull以外であり、クエリで有効な結果が得られるはずです。しかし、どういうわけかこのエラーが発生します

_04:15:10.504 [http-nio-8080-exec-2] ERROR org.hibernate.AssertionFailure - HHH000099: an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session): org.hibernate.AssertionFailure: null id in my.app.dbAccess.models.DataDAO entry (don't flush the Session after an exception occurs)
org.hibernate.AssertionFailure: null id in my.app.dbAccess.models.DataDAO entry (don't flush the Session after an exception occurs)
    at org.hibernate.event.internal.DefaultFlushEntityEventListener.checkId(DefaultFlushEntityEventListener.Java:60)
    at org.hibernate.event.internal.DefaultFlushEntityEventListener.getValues(DefaultFlushEntityEventListener.Java:175)
    at org.hibernate.event.internal.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.Java:135)
    at org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.Java:216)
    at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.Java:85)
    at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.Java:44)
    at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.Java:1251)
    at org.hibernate.internal.SessionImpl.list(SessionImpl.Java:1319)
    at org.hibernate.internal.QueryImpl.list(QueryImpl.Java:87)
    at org.hibernate.jpa.internal.QueryImpl.list(QueryImpl.Java:606)
    at org.hibernate.jpa.internal.QueryImpl.getSingleResult(QueryImpl.Java:529)
    at org.springframework.data.jpa.repository.support.SimpleJpaRepository.count(SimpleJpaRepository.Java:486)
    at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:62)
    at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43)
    at Java.lang.reflect.Method.invoke(Method.Java:498)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.Java:503)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.Java:488)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.Java:460)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.Java:179)
    at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.Java:61)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.Java:179)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.Java:99)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.Java:280)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.Java:96)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.Java:179)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.Java:136)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.Java:179)
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.Java:133)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.Java:179)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.Java:92)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.Java:179)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.Java:213)
    at com.Sun.proxy.$Proxy137.count(Unknown Source)
    at my.app.dbAccess.generated.proxy.CountryRepositoryImpl.findByCountry_Id(CountryRepositoryImpl.Java:800)
    at my.app.services.DataServiceImpl.getCountryFromId(DataServiceImpl.Java:131)
    at my.app.services.DataServiceImpl.fromDao(DataServiceImpl.Java:109)
    at my.app.services.DataServiceImpl.fromDao(DataServiceImpl.Java:1)
    at my.app.services.DataServiceImpl.fromDao(DataServiceImpl.Java:118)
    at my.app.services.DataServiceImpl.fromDao(DataServiceImpl.Java:1)
    at my.app.services.DataServiceImpl$$FastClassBySpringCGLIB$$72be48ea.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.Java:204)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.Java:651)
    at my.app.services.DataServiceImpl$$EnhancerBySpringCGLIB$$c0525c49.fromDao(<generated>)
    at my.app.event.consumers.DataCreationListener.onPostInsert(DataCreationListener.Java:40)
    at org.hibernate.action.internal.EntityIdentityInsertAction.postInsert(EntityIdentityInsertAction.Java:156)
    at org.hibernate.action.internal.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.Java:102)
    at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.Java:597)
_

OnPostInsertメソッドからクエリを実行しているためですか?このメソッドからクエリを実行するのは安全ではありませんか?データに問題はありません。HibernateEnversと関係があるのではないかと思いますが、理解できません。誰かが私を正しい方向に向けてくれませんか。ありがとう!

6
varunkr

OnPostInsertメソッドからクエリを実行しているためですか?

可能性が高い。私が見たところ、事前にフラッシュがクエリからトリガーされました。
Hibernateで生成されたIDを使用している可能性が高いです(ほとんどの場合、dbで生成されています)。

このメソッドからクエリを実行するのは安全ではありませんか?

特定のケースに応じて、それは可能性があります安全ではありません。
確かに、バルク/バッチインサートを壊し、パフォーマンスを大幅に低下させます。

現在のトランザクションを一時停止してフラッシュを防ぎ、外部でクエリを実行してみてください。
古い結果が得られる場合がありますが、この場合、これは問題ではないようです。

春にそれを行う方法がわからない。JavaEEでは、次のようなEJBメソッドを呼び出すことができます。

@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED) // alternatively use REQUIRES_NEW
public Country getCountryFromId(Object id) {
    ....
}

春に相当するものがあると確信しています。

データに問題はありません。HibernateEnversと関係があるのではないかと思いますが、理解できません。

データに問題があります:IDがnullです-まだ割り当てられていません。
このカテゴリの問題を回避するために、アプリケーションで生成されたID(通常はUUIDまたはSUID)を使用します。

Enversはリスナーに対しても監査を実行しますが、STには証拠がなく、どちらのリスナーが最初に実行されるか(yoursまたはEnvers)はありません。

どちらの場合も、これは無関係のようです。最初に他のことをチェックします(自動フラッシュを防ぎます)。

2