事务传播类型
spring 的7种事务传播类型
PROPAGATION_REQUIRED
: 如果当前没有事务,则创建一个新事务;如果当前存在事务,就加入该事务;该配置是最常用的设置。PROPAGATION_SUPPORTS
: 支持当前事务,如果当前存在事务则加入该事务;如果当前不存在事务,就以非事务执行。PROPAGATION_MANDATORY
: 支持当前事务,如果当前存在事务则就加入该事务;如果不存在事务,则抛出异常。PROPAGATION_REQUIRES_NEW
: 无论当前存在不存在事务,都创建新事务。PROPAGATION_NOT_SUPPORTED
: 以非事务方式执行操作,如果当前存在事务,则把当前事务挂起。PROPAGATION_NEVER
: 以非事务方式执行,如果当前存在事务,则抛出异常。PROPAGATION_NESTED
: 如果当前存在事务,则在嵌套事务内执行,如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
代码语言:javascript复制注意: 内部方法直接调用,传播性失效
@Service("studentImpl")
public class StudentImpl implements Student {
@Autowired
StudentDao studentDao;
@Autowired
UserService userService;
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, rollbackFor = Exception.class)
public String doA() throws Exception {
Student student = new Student();
student.setSex("F");
student.setUsername("唐玄奘");
studentDao.insertStudent(student);
userService.addUser();
int i = 1 / 0; // 模拟异常,事务回滚
return "ok!";
}
}
代码语言:javascript复制@Service("userServiceImpl")
public class UserServiceImpl implements UserService {
@Autowired
UserDao userDao;
@Transactional(propagation = Propagation.REQUIRES_NEW,isolation=Isolation.DEFAULT,rollbackFor=Exception.class)
public String addUser() throws Exception {
User user = new User();
user.setUsername("观世音菩萨");
userDao.insert(user);
return "ok!";
}
}
结果:只会是 user 插入成功, 因为 addUser方法使用了事务传播行为:
Propagation.REQUIRES_NEW
,当前存在事务1,则新建了一个自己的事务,并挂起了事务1. 事务2提交后,事务1由于抛出了异常回滚。
如果以上例子改为在一个方法中调用另一个事务方法,另一个方法的传播行为会失效:
代码语言:javascript复制@Service("studentImpl")
public class StudentImpl implements Student {
@Autowired
StudentDao studentDao;
@Autowired
UserDao userDao;
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, rollbackFor = Exception.class)
public String doA() throws Exception {
Student student = new Student();
student.setSex("F");
student.setUsername("唐玄奘");
studentDao.insertStudent(student);
userService.addUser();
int i = 1 / 0; // 模拟异常,事务回滚
return "ok!";
}
@Transactional(propagation = Propagation.REQUIRES_NEW,isolation=Isolation.DEFAULT,rollbackFor=Exception.class)
public String addUser() throws Exception {
User user = new User();
user.setUsername("观世音菩萨");
userDao.insert(user);
return "ok!";
}
}
结果:addUser 的事务传播性会失效,事务1回滚后,数据库不会插入任何记录。
spring 的5种隔离级别
ISOLATION_DEFAULT
: 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别。ISOLATION_READ_UNCOMMITTED
: 事务最低的隔离级别,它允许其他事务可以看到这个事务未提交的数据;会产生脏读、不可重复读、幻读。ISOLATION_READ_COMMITTED
: 保证一个事务提交后才能被另一个事务读取;另外一个事务不能读取该事务未提交的数据;这种事务隔离级别可以避免脏读出现,但是可能会出现 不可重复读、幻读。ISOLATION_REPEATABLE_READ
: 防止出现脏读、不可重复读,但是可能出现幻读;一个事务不能读取另一个事务未提交的数据,同时避免出现 不可重复读。ISOLATION_SERIALIZABLE
: 防止脏读、不可重复读、幻读;代价最高可靠性最好的事务隔离级别,事务被处理为顺序执行。
关键词:
幻读: 事务1 读取记录时,事务2 增加了记录并提交, 事务1 再次读取时可以看到事务2 新增的记录。 指一个事务读取了一个未提交事务的数据。 不可重复读取: 事务1 读取记录时, 事务2 更新了记录并提交, 事务1 再次读取时可以看到 事务2 修改后的记录。 在一个事务内读取表中的某一行数据,多次读取结果不同,一个事务读取到了另一个事务提交后的数据。 脏读: 事务1 更新了记录, 但是没有提交,事务2 读取了更新后的行, 然后事务1 回滚,现在事务2 读取无效。 在一个事务内读取了别的事务插入的数据,导致前后读取不一致。