在查询周围使用 JPA 事务时,Hibernate Integrator 会导致刷新
Hibernate Integrator Causes Flush When Using JPA Transactions Around Queries
我正在为 Hibernate 开发 Integrator
(Integrators 的背景:https://docs.jboss.org/hibernate/orm/4.3/manual/en-US/html/ch14.html#objectstate-decl-security) that by using listeners is supposed to take my data from how it's stored in the DB and convert it into a different form for processing at runtime. This works great when saving the data using .persist()
however there's an odd behavior involving transactions. The following code is from Hibernate's own quickstart tutorial code:
// now lets pull events from the database and list them
entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
List<Event> result = entityManager.createQuery( "from Event", Event.class ).getResultList();
for ( Event event : result ) {
System.out.println( "Event (" + event.getDate() + ") : " + event.getTitle() );
}
entityManager.getTransaction().commit();
entityManager.close();
请注意异常事务 begin/commit 将查询包装到 select 数据。 运行 这会在查询完成后给出以下输出:
01:01:59.111 [main] DEBUG org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(175) - committing
01:01:59.112 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener.prepareEntityFlushes(149) - Processing flush-time cascades
01:01:59.112 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener.prepareCollectionFlushes(189) - Dirty checking collections
01:01:59.114 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener.logFlushResults(123) - Flushed: 0 insertions, 2 updates, 0 deletions to 2 objects
01:01:59.114 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener.logFlushResults(130) - Flushed: 0 (re)creations, 0 updates, 0 removals to 0 collections
01:01:59.114 [main] DEBUG org.hibernate.internal.util.EntityPrinter.toString(114) - Listing entities:
01:01:59.114 [main] DEBUG org.hibernate.internal.util.EntityPrinter.toString(121) - org.hibernate.tutorial.em.Event{date=2015-07-28 01:01:57.776, id=1, title=Our very first event!}
01:01:59.114 [main] DEBUG org.hibernate.internal.util.EntityPrinter.toString(121) - org.hibernate.tutorial.em.Event{date=2015-07-28 01:01:58.746, id=2, title=A follow up event}
01:01:59.115 [main] DEBUG org.hibernate.SQL.logStatement(109) - update EVENTS set EVENT_DATE=?, title=? where id=?
Hibernate: update EVENTS set EVENT_DATE=?, title=? where id=?
01:01:59.119 [main] DEBUG org.hibernate.SQL.logStatement(109) - update EVENTS set EVENT_DATE=?, title=? where id=?
Hibernate: update EVENTS set EVENT_DATE=?, title=? where id=?
01:01:59.120 [main] DEBUG org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doCommit(113) - committed JDBC Connection
01:01:59.120 [main] DEBUG org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.close(201) - HHH000420: Closing un-released batch
01:01:59.121 [main] DEBUG org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.releaseConnection(246) - Releasing JDBC connection
01:01:59.121 [main] DEBUG org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.releaseConnection(264) - Released JDBC connection
01:01:59.121 [main] DEBUG org.hibernate.internal.SessionFactoryImpl.close(1339) - HHH000031: Closing
似乎由于 Integrator
对相关实体进行了修改,它被标记为 "dirty" 并且在提交这个奇怪的事务时,它绕过了我的事件监听器并将值写回格式错误!我深入研究了代码,结果发现 org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(FlushEvent, PersistenceContext)
在上面被调用并试图为 EventType.FLUSH_ENTITY
获取监听器。不幸的是,为此 EventType
添加的侦听器从未在我的 Integrator
中调用。在这种情况下,我如何编写 Integrator
才能正确运行,以便我可以 "undo" 我的实体在运行时发生的转换,而不是清除错误的值?
最终问题是由于添加了 EventListenerRegistry
的事件侦听器的 EventType
引起的。有效的是将 EventType.POST_LOAD
用于所有读取操作,并结合 EventType.PRE_UPDATE
和 EventType.PRE_INSERT
用于调用辅助方法以相同方式处理两者的写入操作。
为防止在更新实体后进行不必要的写入,如果实体在 EntityEntry
中称为 loadedState
时重置用于跟踪的数据是个好主意。这是 Hibernate 4 中的私有字段,因此您需要使用反射,但在 Hibernate 5 中,它可以通过 getLoadedState()
方法使用。另一个问题是您需要更新 "state" 的值,这些值在实际通过 PreInsertEvent
和 PreUpdateEvent
将值刷新到数据库时使用,可以从 getState()
方法中检索每个都有定义。
我正在为 Hibernate 开发 Integrator
(Integrators 的背景:https://docs.jboss.org/hibernate/orm/4.3/manual/en-US/html/ch14.html#objectstate-decl-security) that by using listeners is supposed to take my data from how it's stored in the DB and convert it into a different form for processing at runtime. This works great when saving the data using .persist()
however there's an odd behavior involving transactions. The following code is from Hibernate's own quickstart tutorial code:
// now lets pull events from the database and list them
entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
List<Event> result = entityManager.createQuery( "from Event", Event.class ).getResultList();
for ( Event event : result ) {
System.out.println( "Event (" + event.getDate() + ") : " + event.getTitle() );
}
entityManager.getTransaction().commit();
entityManager.close();
请注意异常事务 begin/commit 将查询包装到 select 数据。 运行 这会在查询完成后给出以下输出:
01:01:59.111 [main] DEBUG org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(175) - committing
01:01:59.112 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener.prepareEntityFlushes(149) - Processing flush-time cascades
01:01:59.112 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener.prepareCollectionFlushes(189) - Dirty checking collections
01:01:59.114 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener.logFlushResults(123) - Flushed: 0 insertions, 2 updates, 0 deletions to 2 objects
01:01:59.114 [main] DEBUG org.hibernate.event.internal.AbstractFlushingEventListener.logFlushResults(130) - Flushed: 0 (re)creations, 0 updates, 0 removals to 0 collections
01:01:59.114 [main] DEBUG org.hibernate.internal.util.EntityPrinter.toString(114) - Listing entities:
01:01:59.114 [main] DEBUG org.hibernate.internal.util.EntityPrinter.toString(121) - org.hibernate.tutorial.em.Event{date=2015-07-28 01:01:57.776, id=1, title=Our very first event!}
01:01:59.114 [main] DEBUG org.hibernate.internal.util.EntityPrinter.toString(121) - org.hibernate.tutorial.em.Event{date=2015-07-28 01:01:58.746, id=2, title=A follow up event}
01:01:59.115 [main] DEBUG org.hibernate.SQL.logStatement(109) - update EVENTS set EVENT_DATE=?, title=? where id=?
Hibernate: update EVENTS set EVENT_DATE=?, title=? where id=?
01:01:59.119 [main] DEBUG org.hibernate.SQL.logStatement(109) - update EVENTS set EVENT_DATE=?, title=? where id=?
Hibernate: update EVENTS set EVENT_DATE=?, title=? where id=?
01:01:59.120 [main] DEBUG org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doCommit(113) - committed JDBC Connection
01:01:59.120 [main] DEBUG org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.close(201) - HHH000420: Closing un-released batch
01:01:59.121 [main] DEBUG org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.releaseConnection(246) - Releasing JDBC connection
01:01:59.121 [main] DEBUG org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.releaseConnection(264) - Released JDBC connection
01:01:59.121 [main] DEBUG org.hibernate.internal.SessionFactoryImpl.close(1339) - HHH000031: Closing
似乎由于 Integrator
对相关实体进行了修改,它被标记为 "dirty" 并且在提交这个奇怪的事务时,它绕过了我的事件监听器并将值写回格式错误!我深入研究了代码,结果发现 org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(FlushEvent, PersistenceContext)
在上面被调用并试图为 EventType.FLUSH_ENTITY
获取监听器。不幸的是,为此 EventType
添加的侦听器从未在我的 Integrator
中调用。在这种情况下,我如何编写 Integrator
才能正确运行,以便我可以 "undo" 我的实体在运行时发生的转换,而不是清除错误的值?
最终问题是由于添加了 EventListenerRegistry
的事件侦听器的 EventType
引起的。有效的是将 EventType.POST_LOAD
用于所有读取操作,并结合 EventType.PRE_UPDATE
和 EventType.PRE_INSERT
用于调用辅助方法以相同方式处理两者的写入操作。
为防止在更新实体后进行不必要的写入,如果实体在 EntityEntry
中称为 loadedState
时重置用于跟踪的数据是个好主意。这是 Hibernate 4 中的私有字段,因此您需要使用反射,但在 Hibernate 5 中,它可以通过 getLoadedState()
方法使用。另一个问题是您需要更新 "state" 的值,这些值在实际通过 PreInsertEvent
和 PreUpdateEvent
将值刷新到数据库时使用,可以从 getState()
方法中检索每个都有定义。