【问题标题】:Spring @transactional does not cause rollbacksSpring @transactional 不会导致回滚
【发布时间】:2013-09-16 00:45:15
【问题描述】:

在开始这个看似很长的段落之前,我想对我可能收到的任何建议/建议表示感谢。 ——朱约翰

我开发了一个简单的测试来帮助我了解 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 成功,第二个失败的数据。

问题:最终结果是一条记录被插入到帐户中,并且仍然存在,即使第二次插入也按预期失败。

几点说明:

  1. 如果我向两个 SQL 提供正确的数据,测试运行就会成功。

  2. 如果我只是将 TransactionTest 作为 Eclipse 中的独立 java 应用程序(参见类 defn 中的 main(...))针对本地数据库运行,似乎会发生回滚。

  3. 执行确实捕获了一个 AccessDataException(请参阅我在“catch”块中的打印语句)。因此,我得出结论,抛出了“new RuntimeException()”。

  4. 由于插入失败而导致的错误消息(调用堆栈)确实显示了以下内容:

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

这表明方法“accountTest”已被 Spring 的事务拦截器正确“包装”。这似乎暗示我的配置(见下文)是有效的。

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 版本保持同步。

【问题讨论】:

  • 您在数据库中使用 InnoDB 吗?
  • 我不熟悉“InnoDB”这个词。我正在使用 MySQL 的基本功能。
  • InnoDB 是 MySQL 的存储引擎。详情请参阅herehere。如果您使用 MyISAM,它是 MySQL 5.5.4 及之前的默认存储引擎,请使用 InnoDB。 MyISAM 不支持事务。
  • 凯三,感谢您的跟进。你可以进一步解释一下。得知 MySQL 5.5.4 或更早版本的默认存储引擎不支持事务,令我感到惊讶。然而,我一直被告知事务管理是 DBMS 的关键和基本特性之一。我一定错过了什么。朱约翰
  • 您可以基于表(或数据库)配置存储引擎。我已经发布了如何做到这一点作为答案。

标签: spring transactions


【解决方案1】:

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

检查表的存储引擎:

mysql> show create table your_tbl_name;

使用 InnoDB 创建表:

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

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 2013-01-13
    • 2017-04-14
    • 1970-01-01
    • 2018-11-08
    • 2019-06-30
    • 2016-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多