如何在entitymanager createNativeMethod中回滚

时间:2015-02-23 05:46:30

标签: java spring spring-mvc jpa

我正在使用实体管理器的本机方法,并且我想在发生某些错误时回滚。为此我尝试了@Transactional注释,但这不会回滚。我是示例代码

控制器

@Autowired
ServiceImpl ServiceImpl;

@RequestMapping("/saveinfo")
@ResponseBody
@Transactional
public String saveinfo(Long id)
{
   ServiceImpl.saveInfo(id);
}

服务类

@Autowired
DAOImpl daoImpl;

@Transactional
public String saveinfo(Long id)
{
    daoImpl.saveInfo1(id);
    daoImpl.saveInfo12(id);
    daoImpl.saveInfo12(id);

}

DAO课程

@Override
public BigInteger saveInfo11() {

   Query query =  entityManagerUtil.entityManager().createNativeQuery("insert query");
   return (BigInteger)query.getSingleResult();
}

@Override
public BigInteger saveInfo12() {

   Query query =    entityManagerUtil.entityManager().createNativeQuery("insert query");
   return (BigInteger)query.getSingleResult();
}

@Override
public BigInteger saveInfo13() {

   Query query =    entityManagerUtil.entityManager().createNativeQuery("insert query");
   return (BigInteger)query.getSingleResult();
}

现在在上面的代码中,

如果saveInfo3()中有一些运行时错误,那么我想回滚方法 saveInfo1()saveInfo2()

这是我的方式,但它没有回滚,所以请告诉我该怎么做

修改

我尝试使用

@Transactional(rollbackFor=MyException.class,propagation = Propagation.REQUIRED) and  @Transactional(propagation = Propagation.REQUIRED) and

@Transactional(rollbackFor=MyException.class))

在所有3个案例中,它都没有回滚

更新

applicationcontext.xml



<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"  
       xmlns:aop="http://www.springframework.org/schema/aop" 
       xmlns:context="http://www.springframework.org/schema/context" 
       xmlns:jee="http://www.springframework.org/schema/jee" 
       xmlns:tx="http://www.springframework.org/schema/tx" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:security="http://www.springframework.org/schema/security" 
       xmlns:mongo="http://www.springframework.org/schema/data/mongo"
       xmlns:task="http://www.springframework.org/schema/task"
       xsi:schemaLocation="http://www.springframework.org/schema/aop 
                          http://www.springframework.org/schema/aop/spring-aop-3.0.xsd        
                          http://www.springframework.org/schema/beans 
                          http://www.springframework.org/schema/beans/spring-beans-3.0.xsd         
                          http://www.springframework.org/schema/context 
                          http://www.springframework.org/schema/context/spring-context-3.0.xsd
                           http://www.springframework.org/schema/data/mongo
                          http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd         
                          http://www.springframework.org/schema/jee 
                          http://www.springframework.org/schema/jee/spring-jee-3.0.xsd         
                          http://www.springframework.org/schema/tx  
                          http://www.springframework.org/schema/tx/spring-tx-3.0.xsd 
                          http://www.springframework.org/schema/security 
                          http://www.springframework.org/schema/security/spring-security-3.0.xsd
                          http://www.springframework.org/schema/task  
http://www.springframework.org/schema/task/spring-task-3.0.xsd">



     <!--<context:annotation-config />-->
     <context:spring-configured/>

       <bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
        <property name="dataSource" ref="dataSource"/>
        <property name="persistenceUnitName" value="persistenceUnit"/>
       </bean>
       <bean id="messageDigestPasswordEncoder" class="org.springframework.security.authentication.encoding.MessageDigestPasswordEncoder">
         <constructor-arg value="SHA-256" />
        </bean>

       <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource"  id="dataSource">
         <property name="driverClassName" value="${database.driverClassName}"/>
        <property name="url" value="${database.url}"/>
        <property name="username" value="${database.username}"/>
        <property name="password" value="${database.password}"/>


    </bean>










     <tx:annotation-driven  mode="aspectj" transaction-manager="transactionManager"/>
       <context:property-placeholder location="classpath*:META-INF/database.properties"/>
       <context:property-placeholder location="classpath*:META-INF/project.properties"/>

      <bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
     </bean>

    <bean id="propertiesUtil" class="com.work.project.utils.PropertiesUtil">

    <property name="locations" >
   <list>
                <value>classpath*:META-INF/*.properties</value>

            </list>
    </property>

</bean>

    <context:component-scan base-package="com.work.project">
        <context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
    </context:component-scan>



     <task:executor id="myexecutor" pool-size="5"  />
<task:annotation-driven executor="myexecutor"/>








</beans>

修改后的控制器方法

@Autowired
ServiceImpl ServiceImpl;

@RequestMapping("/saveinfo")
@ResponseBody
//Now I dont use transactional annotation in controller class
public String saveinfo(Long id)
{
   ServiceImpl.saveInfo(id);
}

如果需要更多信息,请询问

5 个答案:

答案 0 :(得分:1)

问题似乎是EntityManager不是由Spring注入的。 EntityManager实例由实用程序类entityManagerUtil.entityManager()创建。这意味着,每次使用新的EntityManager时,它们都不属于您的方法事务。

为了解决这个问题:让Spring正确注入EntityManager(例如,尝试使用@PersistenceContext将其直接注入原始bean中,并在同一个方法中直接执行这三种方法)。


更新: 问题是抛出异常的代码是在try / catch块中,这样,Spring没有回滚事务。仅当事务方法以RuntimeException(默认情况下)退出时,才会回滚事务。

答案 1 :(得分:0)

您需要更改方法,使rollbackFor注释具有@Transactional属性,以便

@Transactional(rollbackFor=MyException.class)
public String saveinfo(Long id)

请记住,MyException应该是未经检查的异常,因为从@Transactional方法抛出的已检查异常不会导致事务被回滚。

<强>更新

确保一切正确

  1. 检查Spring是否确实创建了代理,并且您的方法正在交易中执行(例如使用TransactionSynchronizationManager.isActualTransactionActive()

  2. 检查MyException.class确实是未经检查的例外(java.lang.RuntimeExceptionjava.lang.Error的子类)

  3. 检查您的异常是否确实被抛出(例如没有被捕获)

  4. 为什么你的控制器saveInfo()被标记为交易?不建议这样做,只应将服务层标记为事务性。例如,请参阅this帖子。

答案 2 :(得分:0)

也许entityManagerUtil(您在DAO实现中使用)使用或创建一个未在周围事务上下文中运行的实体管理器。请看下面的tutorial:这里JPA EntityManager注入@PersistenceContext

答案 3 :(得分:0)

您是否可以确保persistenceUnit已配置以下内容,transaction type(可选)和hibernate.connection.autocommitfalse,如果不是,请执行此操作。

<persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
        <properties>
            <property name="hibernate.connection.autocommit" value="false" />
        </properties>
    </persistence-unit>

我为了简洁而排除了其他属性

答案 4 :(得分:0)

@SpringLearner通过注释得到实体管理器持久化上下文层它会照顾回滚@PersistenceContext,用你问题中提到的场景实现样本,测试回滚它工作正常并且我没有使用本机查询,它简单的示例,你可以修改代码和test.it应该工作。

blog with git hub link and full source code