java - Spring事务管理在出现错误时不起作用

标签 java spring transactions spring-transactions

我想测试当其中一个数据库更新失败时,使用 Spring JDBC 的 Spring 事务管理是否正常工作。以下是我更新两个数据库表的代码:person 和 contact_info

public void createWithContactInfo(String username, String name, Date dob,
            String contactName, String contactPhone, String contactEmail) {

        try {
            String sqlStmt = "INSERT INTO person (username, name, dob) VALUES (?, ?, ?)";
            jdbcTemplateObject.update(sqlStmt, "paul", "Paul", dob);

            sqlStmt = "INSERT INTO contact_info(username, customer_name, contact_name, contact_phone, contact_email) VALUES (?, ?, ?, ?, ?)";
            jdbcTemplateObject.update(sqlStmt, username, name, contactName,
                    contactPhone, contactEmail);

        } catch (DataAccessException e) {
            e.printStackTrace();
        }
    }

我使用 Spring 声明式事务管理来配置 bean:

<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="createWithContactInfo"/>
    </tx:attributes>
</tx:advice>

<aop:config>
    <aop:pointcut id="createOperation"
        expression="execution(* com.example.db.CustomerJDBCTemplate.createWithContactInfo(..))" />
    <aop:advisor advice-ref="txAdvice" pointcut-ref="createOperation" />
</aop:config>

<!-- Initialization for data source -->
<bean id="dataSource"
    class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url" value="jdbc:mysql://localhost:3306/Customer" />
    <property name="username" value="myusername"/>
    <property name="password" value="12345"/>
    <property name="initialSize" value="10"/>
</bean>

<!-- Definition for customerJDBCTemplate bean -->
<bean id="customerJDBCTemplate" class="com.example.db.CustomerJDBCTemplate">
    <property name="dataSource" ref="dataSource" />
</bean>

<bean id="transactionManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>

然后在我的测试代码中,我有:

public class JdbcTest {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
        CustomerDAO dao = (CustomerDAO) ctx.getBean("customerJDBCTemplate");
        Date dob = new Date(90, 9, 10);
        dao.createWithContactInfo("m9087", "Sam", dob, "David", "123456", "a123@example.com");
    }
}

运行主程序后,我收到异常,指出键“PRIMARY”的重复条目“m9087”。这是预期的,因为 m9087 已存在于 contact_info 表中。但是由于第二个数据库插入在事务中失败,我认为第一个 jdbcTemplateObject.update(sqlStmt, "paul", "Paul", dob); 将不会在事务中提交。不过,我检查了 person 表,它返回了 username=paul 的有效条目:

SELECT * FROM person WHERE username='paul'; 

这意味着第一次数据库插入成功,尽管第二次数据库插入由于重复键异常而失败。

我的理解是,如果任何数据库操作失败,事务应该回滚并且不会进行提交。但在这种情况下,即使第二次数据库更新由于重复键异常而失败,第一次数据库插入仍然成功。这难道不是事务管理的错误行为吗?我的事务管理设置是否正确?

最佳答案

它不会回滚,因为您捕获了异常。当抛出未经检查的异常时,事务将回滚。然后你用你的捕获 block 吞下它:

catch (DataAccessException e) {
    e.printStackTrace();
}

关于java - Spring事务管理在出现错误时不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20228228/

相关文章:

javascript - Spring MVC中如何实现AJAX?

node.js - Sequelize 事务中使用了多少个连接

Mysql InnoDB - 锁定场景

c# - MVC 5 IdentityDbContext 和 DbContext 事务

java - JiBX 框架 jar 不在类路径中

java - Windows上的声音等级听起来层次分明

java - 如何克服这种 java 语法,使 double 成为字符串?

java - 如何从文件路径中获取文件所在的文件夹路径?

java - 在elasticsearch查询中配置搜索词的标记化

java - DDD、JPA 和多模块 Maven