Spring @transactional不会导致回滚

时间:2013-09-11 20:25:37

标签: spring transactions

在我开始这个看似很长的段落之前,我想对我可能收到的任何建议/意见表示感谢。 - John Zhu

我开发了一个简单的测试来帮助我理解spring的声明式(@Transactional)事务管理框架如何与spring的RESTful Web服务一起工作。

为此,我开发了以下RESTful控制器:

    @RequestMapping(value="register", method=RequestMethod.POST, produces="application/json", consumes="application/json")
public void accountFacade () {
    tester.accountTest();
}

其中“tester”是以下服务类的bean,并自动装入此控制器。该类中唯一的方法是交易性的:

@Transactional
public class TransactionTest extends ActivityStatus {
@Autowired
private ObjectManager objectManager;

@Autowired
private GenericDB gdb;

public static void main(String[] args) {
    ApplicationContext ac = new ClassPathXmlApplicationContext("META-INF/test- context.xml");   
    TransactionTest tester = (TransactionTest) ac.getBean("tester");
    tester.accountTest();
}

@Transactional(readOnly=false, propagation=Propagation.REQUIRED, isolation=Isolation.READ_COMMITTED,
               rollbackFor=RuntimeException.class)
public void accountTest () {
    try {
           String sql = "insert into account set account_id=0, ....";
           gdb.jdbcTemplateInsert(sql);

           sql = "insert into login set account_id=....";
           gdb.jdbcTemplateInsert(sql, values);
    } catch (DataAccessException dae) {
        System.out.println("Catching DataAccessException (dae)");
        throw new RuntimeException (dae);
    }
}

在上面,GenericDB是一个提供自定义jdbcTemplate的类。

测试运行是从浏览器调用accountFacade。我故意设置数据,以便第一个SQL成功,第二个SQL会失败,以便触发回滚。

问题:最终结果是记录被插入到帐户中,并且保留,即使第二个插入按预期失败。

一些注意事项:

  1. 如果我向两个SQL提供正确的数据,测试运行将会成功。
  2. 如果我只是将Eclipse中的TransactionTest作为独立的Java应用程序运行(参见类defn中的main(...)),那么回滚似乎就会发生。
  3. 执行确实捕获了AccessDataException(请参阅“catch”块中的print语句)。因此,我得出结论“抛出了新的RuntimeException()”。
  4. 由于插入失败导致的错误消息(调用堆栈)确实显示了以下内容:

    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)[spring-tx-3.1.1.RELEASE.jar:3.1.1.RELEASE]

  5. 表示Spring的事务拦截器正确“包装”了方法“accountTest”。这似乎意味着我的配置(见下文)是有效的。

    applicationContext.xml中的相关行:

    <tx:annotation-driven transaction-manager="txManager" />
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <bean id="tester" class="org.SandRiver.Controllers.TransactionTest">
    </bean>
    

    关于我的执行环境的几句话:我在OpenShift的环境中运行应用程序,其中包含

    1. jboss 6.1
    2. mysql 5.x(我不知道“x”)。
    3. 我正在使用Maven来保持Spring版本的最新版本。

1 个答案:

答案 0 :(得分:0)

您需要使用InnoDB而不是MyISAM来支持事务。

检查表的存储引擎:

mysql> show create table your_tbl_name;

使用InnoDB创建表:

CREATE TABLE your_tbl_name (
  col1 VARCHAR(10),
  col2 VARCHAR(10)
)
ENGINE = InnoDB;

希望这有帮助。

相关问题