spring javax.persistence.TransactionRequiredException:执行更新/删除查询
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16196142/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
javax.persistence.TransactionRequiredException: Executing an update/delete query
提问by Chailie
I am using JPA2.0+hibernate3.2+Spring3.0.5+MySql5.5 to implement DAO function,but it doesn't work and just throw javax.persistence.TransactionRequiredException when i tried to persist entity to DB. Please see my coding and configuration.
我正在使用 JPA2.0+hibernate3.2+Spring3.0.5+MySql5.5 来实现 DAO 功能,但是当我尝试将实体持久化到 DB 时,它不起作用并且只是抛出 javax.persistence.TransactionRequiredException。请参阅我的编码和配置。
1.Entity
1.实体
@Entity
@Table(name="booking_no")
public class BookingNo {
public BookingNo(){
};
@Id
@GeneratedValue
private Integer id;
@Column(unique=true,length=30)
private String prefix;
2.DAO
2.DAO
@Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.DEFAULT)
public Object generateBookingNo(String customer) throws Exception{
logger.debug("generateBookingNo() start,generate booking no by customer:"+customer);
if(customer == null || customer.trim().length() == 0){
logger.error("generateBookingNo(),customer is empty,return null");
return null;
}
EntityManager em = emf.createEntityManager();
try{
Query query = em.createQuery("select b from BookingNo b where b.prefix='"+customer+"'");
Object object =null;
try{
object = query.getSingleResult();
}catch(NoResultException e){
logger.info("generateBookingNo(),not find id for customer["+customer+"],will save a initial record");
BookingNo bkNo = new BookingNo();
bkNo.setPrefix(customer);
logger.debug("generateBookingNo(),the bookingNo is:"+bkNo);
em.persist(bkNo);
//em.flush();
Object object2 =null;
try{
object2 = em.createQuery("select b.id from BookingNo b where b.prefix='"+customer+"'").getSingleResult();
}catch(Exception e2){
logger.error("get error when query customer ["+customer+"]",e);
return null;
}
return customer+"-"+object2;
}
if(object == null || !(object instanceof BookingNo)){
logger.error("generateBookingNo(),return nothing but not catch NoResultException,return null");
return null;
}
BookingNo bkNo =(BookingNo) object;
Integer newId = bkNo.getId()+1;
//Query query2 = em.createQuery("update BookingNo b set b.id="+newId+" where b.prefix='"+customer+"'");
Query query2 = em.createNativeQuery("update booking_no b set b.id="+newId+" where b.prefix='"+customer+"'");
int res = query2.executeUpdate();
logger.debug("generateBookingNo(),the to be update bookingNo is:"+bkNo+",the update result is:"+res);
//em.flush();
return customer+"-"+newId;
}catch(Exception e){
logger.error("get error in generateBookingNo()",e);
return null;
}finally{
em.close();
emf.close();
}
3.Spring cfg file
3.Spring cfg文件
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="bookingEMF"/>
</bean>
<bean id="dataSource1" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost/booking"></property>
<property name="user" value="root"></property>
<property name="password" value="123456"></property>
<property name="initialPoolSize" value="1"></property>
<property name="minPoolSize" value="1"></property>
<property name="maxPoolSize" value="20"></property>
<property name="maxIdleTime" value="60"></property>
<property name="acquireIncrement" value="5"></property>
<property name="idleConnectionTestPeriod" value="60"></property>
<property name="acquireRetryAttempts" value="20"></property>
<property name="breakAfterAcquireFailure" value="true"></property>
</bean>
<!-- Entity Manager Factory -->
<bean id="bookingEMF" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="booking"/>
<property name="dataSource" ref="dataSource1" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="jpaPropertyMap">
<map>
<entry key="hibernate.transaction.flush_before_completion" value="true"/>
<entry key="hibernate.transaction.auto_close_session" value="true"/>
<entry key="hibernate.connection.release_mode" value="auto"/>
<entry key="hibernate.hbm2ddl.auto" value="update"/>
<entry key="format_sql" value="true"/>
<!-- <entry key="hibernate.transaction.manager_lookup_class" value="com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup"/> -->
</map>
</property>
</bean>
<!-- JPA Vendor,Implementation is hibernate -->
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="MYSQL" />
<property name="showSql" value="true"/>
<property name="generateDdl" value="false"/>
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
</bean>
<!-- DAO -->
<bean id="BookingDAO" class="com.chailie.booking.dao.impl.booking.BookingDAO" >
<property name="emf" ref="bookingEMF"/>
</bean>
when run junit test case as following
当运行 junit 测试用例如下
@Test
public void testGenerateBookingNo(){
try {
BookingDAO dao = (BookingDAO) DAOFactory.getDAO("BookingDAO", DAOFactory.TYPE_APPLICATION);
dao.generateBookingNo("chailie");
//dao.generateBookingNo("chailie2");
} catch (Exception e) {
// TODO Auto-generated catch block
logger.error("get error",e);
}
}
It will occur javax.persistence.TransactionRequiredException and i don't know what happeded,does anybody could help to solve this?i really appreciate it By the way,please see my log
它会发生 javax.persistence.TransactionRequiredException ,我不知道发生了什么,有人可以帮助解决这个问题吗?我真的很感激 顺便说一句,请查看我的日志
23:15:46.817 [main] DEBUG org.hibernate.hql.ast.ErrorCounter - throwQueryException() : no errors
23:15:46.837 [main] DEBUG o.h.hql.ast.QueryTranslatorImpl - HQL: select b from com.chailie.booking.model.booking.BookingNo b where b.prefix='chailie'
23:15:46.837 [main] DEBUG o.h.hql.ast.QueryTranslatorImpl - SQL: select bookingno0_.id as id0_, bookingno0_.prefix as prefix0_ from booking_no bookingno0_ where bookingno0_.prefix='chailie'
23:15:46.837 [main] DEBUG org.hibernate.hql.ast.ErrorCounter - throwQueryException() : no errors
23:15:46.856 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
23:15:46.856 [main] DEBUG org.hibernate.jdbc.ConnectionManager - opening JDBC connection
23:15:46.891 [main] DEBUG org.hibernate.SQL - select bookingno0_.id as id0_, bookingno0_.prefix as prefix0_ from booking_no bookingno0_ where bookingno0_.prefix='chailie' limit ?
Hibernate: select bookingno0_.id as id0_, bookingno0_.prefix as prefix0_ from booking_no bookingno0_ where bookingno0_.prefix='chailie' limit ?
23:15:46.922 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to open ResultSet (open ResultSets: 0, globally: 0)
23:15:46.926 [main] DEBUG org.hibernate.loader.Loader - result row: EntityKey[com.chailie.booking.model.booking.BookingNo#8]
23:15:46.935 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to close ResultSet (open ResultSets: 1, globally: 1)
23:15:46.936 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
23:15:46.936 [main] DEBUG org.hibernate.jdbc.ConnectionManager - aggressively releasing JDBC connection
23:15:46.936 [main] DEBUG org.hibernate.jdbc.ConnectionManager - releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
23:15:46.939 [main] DEBUG org.hibernate.engine.TwoPhaseLoad - resolving associations for [com.chailie.booking.model.booking.BookingNo#8]
23:15:46.941 [main] DEBUG org.hibernate.engine.TwoPhaseLoad - done materializing entity [com.chailie.booking.model.booking.BookingNo#8]
23:15:46.942 [main] DEBUG o.h.e.StatefulPersistenceContext - initializing non-lazy collections
23:15:46.942 [main] DEBUG org.hibernate.jdbc.ConnectionManager - aggressively releasing JDBC connection
23:15:46.944 [main] DEBUG o.h.ejb.AbstractEntityManagerImpl - mark transaction for rollback
23:15:46.954 [main] ERROR c.c.b.d.booking.impl.BookingDAOTest - get error in generateBookingNo()
javax.persistence.TransactionRequiredException: Executing an update/delete query
at org.hibernate.ejb.QueryImpl.executeUpdate(QueryImpl.java:48) [hibernate-entitymanager-3.4.0.GA.jar:3.4.0.GA]
at com.chailie.booking.dao.impl.booking.BookingDAO.generateBookingNo(BookingDAO.java:104) [classes/:na]
at com.chailie.booking.dao.impl.booking.BookingDAO$$FastClassByCGLIB$98182b.invoke(<generated>) [cglib-2.2.jar:na]
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191) [cglib-2.2.jar:na]
at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:688) [spring-aop-3.0.5.RELEASE.jar:3.0.5.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) [spring-aop-3.0.5.RELEASE.jar:3.0.5.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110) [spring-tx-3.0.5.RELEASE.jar:3.0.5.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) [spring-aop-3.0.5.RELEASE.jar:3.0.5.RELEASE]
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:621) [spring-aop-3.0.5.RELEASE.jar:3.0.5.RELEASE]
at com.chailie.booking.dao.impl.booking.BookingDAO$$EnhancerByCGLIB$d6a935.generateBookingNo(<generated>) [cglib-2.2.jar:na]
at com.chailie.booking.dao.booking.impl.BookingDAOTest.testGenerateBookingNo(BookingDAOTest.java:42) [test-classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [na:1.7.0_15]
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) [na:1.7.0_15]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) [na:1.7.0_15]
at java.lang.reflect.Method.invoke(Unknown Source) [na:1.7.0_15]
at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:44) [junit-4.7.jar:na]
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) [junit-4.7.jar:na]
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41) [junit-4.7.jar:na]
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) [junit-4.7.jar:na]
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76) [junit-4.7.jar:na]
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) [junit-4.7.jar:na]
at org.junit.runners.ParentRunner.run(ParentRunner.java:193) [junit-4.7.jar:na]
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:52) [junit-4.7.jar:na]
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) [junit-4.7.jar:na]
at org.junit.runners.ParentRunner.access@PersistenceContext(unitName="booking")
EntityManager em;
0(ParentRunner.java:42) [junit-4.7.jar:na]
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:184) [junit-4.7.jar:na]
at org.junit.runners.ParentRunner.run(ParentRunner.java:236) [junit-4.7.jar:na]
at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:53) [surefire-junit4-2.10.jar:2.10]
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:123) [surefire-junit4-2.10.jar:2.10]
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:104) [surefire-junit4-2.10.jar:2.10]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [na:1.7.0_15]
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) [na:1.7.0_15]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) [na:1.7.0_15]
at java.lang.reflect.Method.invoke(Unknown Source) [na:1.7.0_15]
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:164) [surefire-api-2.10.jar:2.10]
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:110) [surefire-booter-2.10.jar:2.10]
at org.apache.maven.surefire.booter.SurefireStarter.invokeProvider(SurefireStarter.java:175) [surefire-booter-2.10.jar:2.10]
at org.apache.maven.surefire.booter.SurefireStarter.runSuitesInProcessWhenForked(SurefireStarter.java:107) [surefire-booter-2.10.jar:2.10]
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:68) [surefire-booter-2.10.jar:2.10]
23:15:46.958 [main] INFO o.hibernate.impl.SessionFactoryImpl - closing
23:15:46.960 [main] DEBUG o.h.transaction.JDBCTransaction - commit
23:15:46.962 [main] DEBUG o.h.transaction.JDBCTransaction - re-enabling autocommit
23:15:46.962 [main] DEBUG o.h.transaction.JDBCTransaction - committed JDBC Connection
23:15:46.962 [main] DEBUG org.hibernate.jdbc.ConnectionManager - aggressively releasing JDBC connection
23:15:46.963 [main] DEBUG org.hibernate.jdbc.ConnectionManager - releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
回答by Pradeep Pati
Before you do a em.persist(), get a EntityTransactionobject (say et), by doing em.getTransaction(), and then do a et.begin(). After you are done with the em.persist(), do a et.commit().
你做之前em.persist(),获得一个EntityTransaction对象(比如et),这样做em.getTransaction(),然后做一个et.begin()。完成后em.persist(),执行et.commit().
回答by German
If you are using EntityManagerFactory.createEntityManager() I think you need to use EntityManager.getTransaction() manually as well.
如果您使用 EntityManagerFactory.createEntityManager() 我认为您也需要手动使用 EntityManager.getTransaction() 。
Why not inject a Spring managed EntityManager instead of the factory?
为什么不注入 Spring 管理的 EntityManager 而不是工厂?
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("spring-cfg.xml")
public class TestClass(){
@Autowired
private DAOFactory daoFactory;
回答by fpmoles
Is your DAOFactory a Spring Managed Bean? Is your JUnit running with Spring's Runner or is it aware of the application context?
你的 DAOFactory 是 Spring Managed Bean 吗?您的 JUnit 是与 Spring 的 Runner 一起运行还是知道应用程序上下文?
What it looks like to me is that the code is actually running outside of Spring from the data provided, indicating that there is no support for the Transaction Proxy you are trying to create, ie it is being ignored.
在我看来,根据提供的数据,代码实际上是在 Spring 之外运行的,这表明不支持您尝试创建的事务代理,即它被忽略了。
try using this in your junit (you will need spring-test)
尝试在您的 junit 中使用它(您将需要 spring-test)
##代码##Now you will need to configure your DAOFactory to be a Spring Bean and it shouldn't use new to create your BookingDAO, instead that should be injected via Spring into the DAOFactory for it to serve, granted with Spring you really shouldn't need this type of logic.
现在你需要将你的 DAOFactory 配置为一个 Spring Bean,它不应该使用 new 来创建你的 BookingDAO,而是应该通过 Spring 注入到 DAOFactory 中以供它使用,Spring 授予你真的不需要这个逻辑类型。

