我在Hibernate的应用程序中使用JPA2.0。出于审计日志记录的目的,我使用的是Hibernate的' org.hibernate.EmptyInterceptor '。我的配置如下所示:
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:persistenceUnitName="EvolutionPU"
p:persistenceXmlLocation="classpath*:persistence.xml"
p:dataSource-ref="dataSource" p:jpaVendorAdapter-ref="jpaAdapter">
<property name="loadTimeWeaver">
<bean
class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.cache.provider_class">net.sf.ehcache.hibernate.SingletonEhCacheProvider</prop>
<prop key="net.sf.ehcache.configurationResourceName">/ehcache.xml</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.ejb.interceptor">com.xxx.audit.interceptor.AuditLogInterceptor</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactory" />
实现EmptyInterceptor的审计日志拦截器:
public class AuditLogInterceptor extends EmptyInterceptor {
public AuditLogInterceptor() {
}
@Override
public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) throws CallbackException {
//My code for audit logging
return false;
}
@Override
public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) {
//My code for audit logging
return false;
}
@Override
public void postFlush(Iterator iterator) throws CallbackException {
//My code for audit logging
return false;
}
}
我的服务方法如下所示:
@Service("mySerivceImpl")
public class MySerivceImpl{
@Transactional(readOnly = true, isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
public void saveEntity(EntityVO entityVO) {
}
}
请注意,我使用 @Transactional 注释了服务方法。
每当调用此方法时,我会在AuditLogInterceptor中捕获旧的和新的实体值,并尝试使用HistoryDAO将它们保存到我的History表中。
但是在使用AuditDAO在AuditLogInterceptor中保存审计数据时,我遇到了问题:
Caused by: javax.persistence.TransactionRequiredException: Executing an update/delete query
at org.hibernate.ejb.AbstractQueryImpl.executeUpdate(AbstractQueryImpl.java:96)
at com.adp.evolution.dao.audit.AuditDaoImpl.saveAuditData(AuditDaoImpl.java:436)
at sun.reflect.GeneratedMethodAccessor759.invoke(Unknown Source)
即使我在事务中(即存在服务方法),为什么这个AuditLogInterceptor需要另一个事务?有什么想法吗?