事务就是逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部失败。
事务具有四大特性(ACID),原子性(Atomomicity),一致性(Consistency),持久性(Isolation),隔离性(Durability)。不同的隔离级别总共可能产生三种问题脏读,不可重复度,幻读。
MySQL事务的隔离级别有四种read uncommited,read commited,repeatable read,serializable,MySQL默认是可重复读。读未提交三种问题都可能产生,读已提交可以解决脏读问题,但是解决不了不可重复读和幻读问题,可重复读可以解决前两种问题,串行化可以解决这三种问题。
以向数据表删除记录为例
@RestController
@RequestMapping("/user0")
public class UserController0 {
@Autowired
private UserService userService;
//1.创建JDBC事务管理器和事务定义对象
@Autowired
private DataSourceTransactionManager transactionManager;
@Autowired
private TransactionDefinition transactionDefinition;
@RequestMapping("/del")
public int del(Integer id) {
if(id != null && id > 0) {
//2.开启事务
TransactionStatus transactionStatus =
transactionManager.getTransaction(transactionDefinition);
//3.删除用户业务操作
int result = userService.del(id);
System.out.println("删除了: " + result);
// 4.提交事务/回滚事务
// transactionManager.commit(transactionStatus); //提交事务
transactionManager.rollback(transactionStatus); //回滚事务
}
return 0;
}
}
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public int del(Integer id){
return userMapper.del(id);
}
}
@Mapper
public interface UserMapper {
int del(@Param("id")Integer id);
}
<delete id="del">
delete from userinfo where id=#{id}
delete>
在方法/类上加@Transactinonal注解。
进入方法自动开启事务,执行完毕自动提交,发生异常自动回滚事务:
成功的情况:
@RestController
@RequestMapping("/user0")
public class UserController0 {
@Autowired
private UserService userService;
@Transactional
@RequestMapping("/del2")
public int del2(Integer id) {
if(id == null || id <= 0) {
return 0;
}
return userService.del(id);
}
}
对应的mapper和xml配置不用变,还是调用对象的service里的方法。
报异常并回滚事务的情况:
这里人为加一个算数异常:
@Transactional
@RequestMapping("/del3")
public int del3(Integer id) {
if(id == null || id <= 0) {
return 0;
}
int result=0;
result=userService.del(id);
int num=10/0;
System.out.println(result);
return result;
}
Spring事务默认级别就是对应连接数据的默认隔离级别
和MySQL的隔离级别含义基本一模一样。
通过Transactional的isolation属性设置:
多个事务进行嵌套调用的时,事务的执行行为叫做事务的传播机制。事务传播机制保证每个事务在多个调用方法间可控。
事务的传播机制一共分为三大类:支持当前事务,不支持当前事务和嵌套事务。
1.异常捕获处理
去掉try catch包裹
在之前的代码上边加try catch处理,再运行可以发现数据库的记录被删除,报错,事务失效
因为事务通知只有自己捕捉到了对应代码抛出的异常,才能进行回滚操作,这里如果自己处理了,事务没办法感知到。
2.非public修饰的方法
将方法设置成Public类型的
3.抛出受查异常
原因:spring默认只能回滚非受查异常。
解决办法:将@Transactional的rollbackFor属性设置为Exception.class
@Transactional使用方法:修饰类对类中所有public方法都生效,修饰方法对public方法生效。
参数 | 作用 |
---|---|
value | 当配置了多个事务管理器时,可使用该属性指定选择哪个事务管理器 |
transactionManager | 当配置多个事务管理器,可使用该使用指定选择哪个事务管理器 |
propagation | 事务的传播机制,默认值为Propagation.REQUIRED |
isolation | 事务的隔离级别,默认值为Isolation.DEFAULT |
timeout | 事务的超时时间,默认值为-1,如果超过该事件限制但事务还没完成,则自动回滚事务 |
readOnly | 指定事务是否为只读事务,默认值为false |
rollbackFor | 用于指定能够触发事务回滚的异常类型,可以指定多个异常类型 |
rollbackForClassName | 用于指定能够触发事务回滚的异常类型,可以指定多个异常类型(字符串类型) |
noRollbackFor | 不回滚抛出异常 |
noRollbackForClassName | 不回滚抛出异常(字符串类型) |
实际开发中,绝大部分时候会使用声明式事务,毕竟只需要加一个注解就可以实现想要的功能。