Java 发生错误时Spring事务管理不工作

Java 发生错误时Spring事务管理不工作,java,spring,transactions,spring-transactions,Java,Spring,Transactions,Spring Transactions,我想测试当一个数据库更新失败时,使用SpringJDBC的Spring事务管理是否正常工作。下面是我更新两个DB表的代码:person和contact_info public void createWithContactInfo(String username, String name, Date dob, String contactName, String contactPhone, String contactEmail) { try {

我想测试当一个数据库更新失败时,使用SpringJDBC的Spring事务管理是否正常工作。下面是我更新两个DB表的代码: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>
在运行主程序后,我得到一个异常,即
为键“PRIMARY”复制了条目“m9087”
。这是预期的,因为联系人信息表中已存在
m9087
。但是由于第二个DB插入在事务中失败,我认为第一个
jdbcTemplateObject.update(sqlStmt,“paul”,“paul”,dob)将不会在事务中提交。但是,我检查了
person
表,它返回了
username=paul
的有效条目:

SELECT * FROM person WHERE username='paul'; 
这意味着第一次DB插入成功,即使第二次DB插入由于重复密钥异常而失败


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

JdbcTemplate不会自动创建将两条更新语句封装在一个事务中的事务

@Autowire
PlatformTransactionManager transactionManager;

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

   DefaultTransactionDefinition paramTransactionDefinition =
                                      new DefaultTransactionDefinition();

   TransactionStatus status =
             transactionManager.getTransaction(paramTransactionDefinition);
   try{
       ... your 2 statmenets here ...

       platformTransactionManager.commit(status);
   }catch (Exception e) {
      platformTransactionManager.rollback(status);
   }
}

JdbcTemplate不会自动创建将两个update语句封装在一个事务中的事务

@Autowire
PlatformTransactionManager transactionManager;

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

   DefaultTransactionDefinition paramTransactionDefinition =
                                      new DefaultTransactionDefinition();

   TransactionStatus status =
             transactionManager.getTransaction(paramTransactionDefinition);
   try{
       ... your 2 statmenets here ...

       platformTransactionManager.commit(status);
   }catch (Exception e) {
      platformTransactionManager.rollback(status);
   }
}

它不会因为捕捉到异常而回滚。当引发未检查的异常时,事务将回滚。你用你的抓块吞下它:

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

它不会因为捕捉到异常而回滚。当引发未检查的异常时,事务将回滚。你用你的抓块吞下它:

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

谢谢。这解决了问题,现在我看到当第一个DB插入失败时,第一个DB插入也没有提交。实际上,我遵循了Spring事务示例:在该示例中,它使用
try catch
捕获异常。但是场景是不同的,因为在那个例子中,它还在
try
块中抛出一个异常。非常感谢。这解决了问题,现在我看到当第一个DB插入失败时,第一个DB插入也没有提交。实际上,我遵循了Spring事务示例:在该示例中,它使用
try catch
捕获异常。但是场景是不同的,因为在那个例子中,它还在
try
块中抛出一个异常。谢谢Ralph。我正在使用Spring声明性事务管理。因此,与事务相关的所有内容都由bean配置XML文件中的AOP处理。但是如果我使用程序化事务管理,您的解决方案也可以工作。谢谢Ralph。我正在使用Spring声明性事务管理。因此,与事务相关的所有内容都由bean配置XML文件中的AOP处理。但是,如果我使用编程事务管理,您的解决方案也可以工作。