4

我正在使用 JPA2.0+hibernate3.2+Spring3.0.5+MySql5.5 来实现 DAO 功能,但是当我尝试将实体持久保存到 DB 时,它不起作用并且只是抛出 javax.persistence.TransactionRequiredException。请参阅我的编码和配置。

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.道

@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文件

    <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>

当运行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);
        }

    }

它会发生 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$$2898182b.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$$58d6a935.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$1.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$3.run(ParentRunner.java:193) [junit-4.7.jar:na]
    at org.junit.runners.ParentRunner$1.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$000(ParentRunner.java:42) [junit-4.7.jar:na]
    at org.junit.runners.ParentRunner$2.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)]
4

3 回答 3

2

在你做 a 之前,通过做em.persist()得到一个EntityTransaction对象(比如et),em.getTransaction()然后做 a et.begin()。完成后em.persist(),执行et.commit().

于 2013-04-24T16:01:05.047 回答
2

如果您使用的是 EntityManagerFactory.createEntityManager() 我认为您还需要手动使用 EntityManager.getTransaction() 。

为什么不注入 Spring 托管的 EntityManager 而不是工厂?

@PersistenceContext(unitName="booking")
EntityManager em;
于 2013-04-26T16:30:41.250 回答
0

Is your DAOFactory a Spring Managed Bean? Is your JUnit running with Spring's Runner or is it aware of the application context?

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.

try using this in your junit (you will need spring-test)

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("spring-cfg.xml")
public class TestClass(){

    @Autowired
    private DAOFactory daoFactory;

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.

于 2013-04-25T19:02:36.163 回答