一、前言
这篇文章主要介绍Spring中事务相关知识。
二、内容
1.Spring事务简介
事务回顾
事务四大特性:
原子性:事务是一组不可分割的操作,这些操作要么全部执行,要么全部不执行。
一致性:事务执行前后,总数据不会发生改变。
隔离性:事务之间相互独立,互不干扰。
持久性:事务对数据库的改变是永久的,持久化到硬盘。
spring事务作用:
在数据层或业务层保证对数据的操作符合事务四大特性。
经典案例:银行转账操作
步骤
1.准备工作
首先准备好数据库中的Account表、数据层的接口AccountMapper、业务层接口AccountService和实现类AccountServiceImpl。
public interface AccountMapper { /** * 模拟转账中的出账操作 * @param username 用户名 * @param money 钱数量 * @return 方法执行是否成功的结果 */ @Update("UPDATE account SET money = money - #{money} WHERE name = #{username}") int out(@Param("username") String username, @Param("money") Double money); /** * 模拟转账中的入账操作 */ @Update("UPDATE account SET money = money + #{money} WHERE name = #{username}") int in(@Param("username") String username, @Param("money") Double money); }
public interface AccountService { /** * 转账业务实现 * @param nameOut * @param nameIn * @param money * @return */ @Transactional // 开启spring事务 int transfer(String nameOut,String nameIn,Double money); }
@Service public class AccountServiceImpl implements AccountService { @Autowired private AccountMapper mapper; @Override public int transfer(String nameOut, String nameIn, Double money) { int i = mapper.out(nameOut, money); // int k = 1/0; // 模拟异常 int j = mapper.in(nameIn, money); return 0; } }
2.开启spring事务
在业务层接口和SpringConfig配置类开启事务支持。
3.编写JDBC事务管理器bean
@Bean public PlatformTransactionManager transactionManager(DataSource dataSource){ DataSourceTransactionManager manager = new DataSourceTransactionManager(); manager.setDataSource(dataSource); return manager; }
4.测试
先看数据库中account表的原始数据
运行结果:
模拟异常:
运行结果:
2.事务角色
事务管理员:事务发起方,在Spring中通常指业务层中开启事务的方法(如图中的transfer()方法)
事务协调员:事务加入方,通常指数据层方法,也可以指业务层方法(如图中的out()方法和in()方法)
3.spring事务属性
异常回滚
rollbackFor | noRollBackFor |
为除了运行时异常、error错误之外的异常设置事务回滚,默认遇到运行时异常,error之外的错误是不回滚的 | 为一些本该回滚的事务设置不回滚 |
案例:记录转账日志
1.MySQL数据库准备log表和实体类
@Data @AllArgsConstructor @NoArgsConstructor public class Log { private String log; }
2.准备LogMapper接口和业务层接口以及实现类
public interface LogMapper { @Insert("INSERT INTO log(info,createTime) VALUES (#{info},now())") boolean record(@Param("info") String info); }
public interface LogService { boolean record(String nameOunt,String nameIn,Double money); }
@Service public class LogServiceImpl implements LogService { @Autowired private LogMapper mapper; @Override public boolean record(String nameOunt, String nameIn, Double money) { boolean b = mapper.record("从" + nameOunt + "到" + nameIn + "转账:" + money + "元"); return b; } }
3.在转账操作中加入记录日记的操作
@Service public class AccountServiceImpl implements AccountService { @Autowired private AccountMapper mapper; @Autowired private LogService logService; @Override public int transfer(String nameOut, String nameIn, Double money) throws IOException { try { int i = mapper.out(nameOut, money); int j = mapper.in(nameIn, money); } finally { logService.record(nameOut, nameIn, money); // 记录日志操作 } return 0; } }
4.查看运行结果
@Test public void testTransferAttr() throws IOException { service.transfer("tom","carry",100D); }
5.当异常出现时,设置事务传播行为,并将一定要执行的语句放在finally中
事务传播行为原理图:
三、结语
这篇文章主要讲了Spring中事务的控制,开启Spring事务保持事务的原子性,以及事务中的事务管理员,事务协调员,事务的相关属性,其中propagation属性较为重要,通过这篇文章,更加深入了解数据库事务。