在学习Spring事务管理的过程中遇到了一个很是头疼的问题,不管是声明式事务还是注解式事务遇到异常都无法回滚。起初我以为是代码或者软件的问题,但是找了很久都没解决,最后终于发现是MySQL数据表引擎的问题,所以记录下来以防将来再次遇到。
首先简单的项目搭建,这里使用的是注解式事务管理。
(1)创建数据表并插入两条数据
CREATE TABLE t_account(
id INT PRIMARY KEY auto_increment,
username VARCHAR(50),
balance DOUBLE
);
INSERT INTO t_account(username,balance) VALUES('jack',1000);
INSERT INTO t_account(username,balance) VALUES('rose',1000);
(2)创建Spring的配置文件applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/spring"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="accountDao" class="com.itheima.jdbc.AccountDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
(3)创建AccountDao接口并创建一个转账方法transfer(),然后创建实现类AccountDaoImpl,并添加事务注解
public class AccountDaoImpl implements AccountDao {
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.DEFAULT,readOnly=false)
public void transfer(String outUser, String inUser, Double money) {
this.jdbcTemplate.update("update t_account set balance = balance +? "
+ "where username = ?",money,inUser);
//模拟出现异常
//int i = 1/0;
this.jdbcTemplate.update("update t_account set balance = balance -? "
+ "where username = ?",money,outUser);
}
}
(4)创建测试类TransactionTest,测试jack给rose转100块钱
public class TransactionTest {
@Test
public void Test() {
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("applicationContext.xml");
AccountDao accountDao = (AccountDao) applicationContext.getBean("accountDao");
accountDao.transfer("jack", "rose", 100.0);
System.out.println("转账成功");
}
}
首先把int i=1/0注释掉运行看t_account表的数据
把注释去掉重新运行
rose多了100块钱而jack的金额却没有少,说明事务并没有回滚,原因如下:
这是因为Mysql中的默认引擎是MyISAM,而MyISAM并不支持事务管理,所以将数据表的引擎更改为InnoDB就行了。
MyISAM和InnoDB的基本差别为:MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持。MyISAM类型的表强调的是性能,其执行速度比InnoDB类型更快,但是不提供事务支持,而InnoDB提供事务支持以及外部键等高级数据库功能
更改Mysql数据表的引擎方法:执行sql语句
ALTER TABLE t_account ENGINE=InnoDB;
重新运行测试类,结果没有发生改变说明事务回滚了,至此问题解决。