Spring 中使用 JPA 进行事务和回滚
StackOverflow 的朋友们大家好, 我不明白如何回滚我看了Spring的文档,但我还是不明白。基本上,我将一直在数据库中保留一个对象(手动使用主键),该对象将被插入到数据库中。但是,当您使用相同的主键再次保留该对象时,我导致了一个异常,而且确实违反了唯一性限制。在这种情况下,我会得到事务回滚并警告您存在问题并继续运行程序
这是我的类:
public class ServiceDaoImpl{
@PersistenceContext (unitName="fb-persistence")
protected EntityManager em;
public void setEntityManager(EntityManager entityManager) {
this.em = entityManager;
}
@Transactional(readOnly=false)
public void write(Service entity){
try {
em.persist(entity);
em.flush();
} catch(Exception ex) {
ex.printStackTrace();
}
}
/*
* .. other method
*/
}
这是错误堆栈:
javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1214)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1147)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1153)
at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:798)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
at $Proxy27.flush(Unknown Source)
at it.synclab.fb.jpa.dao.impl.GenericDaoImpl.write(GenericDaoImpl.java:236)
at it.synclab.fb.jpa.dao.impl.EnteDaoImpl.write(EnteDaoImpl.java:1)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at $Proxy34.write(Unknown Source)
at it.synclab.fb.jpa.test.ConfigTest.insertEnte(ConfigTest.java:47)
at it.synclab.fb.jpa.test.ConfigTest.main(ConfigTest.java:32)
Caused by: org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:268)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:184)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:795)
... 21 more
Caused by: java.sql.BatchUpdateException: ORA-00001: violata restrizione di unicità (FLUSSIBATCH.SYS_C008896)
我的配置文件是(persistence.xml 和 applicationContext.xml):
这是 applicationContext.xml: ...
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="fb-persistence" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean name="serviceDaoImpl" class="it.synclab.fb.jpa.dao.impl.ServiceDaoImpl" />
...
This is the persistence.xml:
<persistence>
<persistence-unit name="fb-persistence" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<mapping-file>META-INF/orm.xml</mapping-file>
<class>it.entity.Service</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"/>
<property name="hibernate.connection.driver_class" value="oracle.jdbc.driver.OracleDriver"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.connection.username" value="############"/>
<property name="hibernate.connection.password" value="############"/>
<property name="hibernate.connection.url" value="jdbc:oracle:thin:@localhost:1521:XE"/>
</properties>
</persistence-unit>
</persistence>
at oracle.jdbc.driver.DatabaseError.throwBatchUpdateException(DatabaseError.java:629)
at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:9467)
at oracle.jdbc.driver.OracleStatementWrapper.executeBatch(OracleStatementWrapper.java:211)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
... 27 more
Exception in thread "main" org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:476)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at $Proxy34.write(Unknown Source)
at it.synclab.fb.jpa.test.ConfigTest.insertEnte(ConfigTest.java:47)
at it.synclab.fb.jpa.test.ConfigTest.main(ConfigTest.java:32)
Caused by: javax.persistence.RollbackException: Transaction marked as rollbackOnly
at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:73)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:467)
... 9 more
为什么一定要复杂?我只是不明白......我希望你们中的一些人遇到过同样的问题并解决了
Hi friends of StackOverflow,
I do not understand how to roll back I read the documentation of Spring, but I still do not understand. Basically I'm going to persist an object in the db (with primary key manually) all the way here all right, the object is inserted into the db. But when you persist the object again with the same primary key I have caused an exception, and rightly so, a violation of restriction of uniqueness. In this case I would get a Transaction rollback and warn you that there was the problem and continue running the program
This is my class:
public class ServiceDaoImpl{
@PersistenceContext (unitName="fb-persistence")
protected EntityManager em;
public void setEntityManager(EntityManager entityManager) {
this.em = entityManager;
}
@Transactional(readOnly=false)
public void write(Service entity){
try {
em.persist(entity);
em.flush();
} catch(Exception ex) {
ex.printStackTrace();
}
}
/*
* .. other method
*/
}
And this is the stack of error:
javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1214)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1147)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1153)
at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:798)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
at $Proxy27.flush(Unknown Source)
at it.synclab.fb.jpa.dao.impl.GenericDaoImpl.write(GenericDaoImpl.java:236)
at it.synclab.fb.jpa.dao.impl.EnteDaoImpl.write(EnteDaoImpl.java:1)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at $Proxy34.write(Unknown Source)
at it.synclab.fb.jpa.test.ConfigTest.insertEnte(ConfigTest.java:47)
at it.synclab.fb.jpa.test.ConfigTest.main(ConfigTest.java:32)
Caused by: org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:268)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:184)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:795)
... 21 more
Caused by: java.sql.BatchUpdateException: ORA-00001: violata restrizione di unicità (FLUSSIBATCH.SYS_C008896)
and my configuration files are (persistence.xml and applicationContext.xml):
This is the applicationContext.xml:
...
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="fb-persistence" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean name="serviceDaoImpl" class="it.synclab.fb.jpa.dao.impl.ServiceDaoImpl" />
...
This is the persistence.xml:
<persistence>
<persistence-unit name="fb-persistence" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<mapping-file>META-INF/orm.xml</mapping-file>
<class>it.entity.Service</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"/>
<property name="hibernate.connection.driver_class" value="oracle.jdbc.driver.OracleDriver"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.connection.username" value="############"/>
<property name="hibernate.connection.password" value="############"/>
<property name="hibernate.connection.url" value="jdbc:oracle:thin:@localhost:1521:XE"/>
</properties>
</persistence-unit>
</persistence>
at oracle.jdbc.driver.DatabaseError.throwBatchUpdateException(DatabaseError.java:629)
at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:9467)
at oracle.jdbc.driver.OracleStatementWrapper.executeBatch(OracleStatementWrapper.java:211)
at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
... 27 more
Exception in thread "main" org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:476)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at $Proxy34.write(Unknown Source)
at it.synclab.fb.jpa.test.ConfigTest.insertEnte(ConfigTest.java:47)
at it.synclab.fb.jpa.test.ConfigTest.main(ConfigTest.java:32)
Caused by: javax.persistence.RollbackException: Transaction marked as rollbackOnly
at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:73)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:467)
... 9 more
Why have to be complicated? I just do not understand ... I hope some of you have had the same problem and solved
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我不知道我是否正确理解您的问题,但您的问题可能与
ServiceDaoImpl
异常处理有关:这是一个非常糟糕的做法 (tm)。不要捕获异常,而是让它从您的方法中弹出。这样:
长话短说:
请注意,您不需要 EntityManager 的 setter,并且该字段可以是私有的。
I don't know if I understand your question correctly, but your problem might be with
ServiceDaoImpl
exception handling:This is a really bad practice (tm). Don't catch the exception but let it pop up from your method. This way:
So to cut long story short:
Note that you don't need setter for
EntityManager
and the field can be private.在 write 方法中添加一个 try catch 块,并在出现错误时抛出异常。
如果您想控制回滚事件,请在您引发的异常的
@Transactional
注释中添加rollbackFor
或rollbackForClassname
属性。Add a try catch block in your write method and throw an exception in case of error.
Put a
rollbackFor
orrollbackForClassname
attribute in your@Transactional
annotation for the exception that you rise, if you want to controll rollback events.