事务
什么是数据库事务
数据库事务有严格的定义,它必须满足4个特性:原子性(atomic)、一致性(consistency)、隔离性(isolation)和持久性(durability),简称acid。
1,原子性:表示组成一个事务的多个数据库操作是一个不可分割的原子单元,只有所有的操作执行成功,整个事务才提交。事务中的任何一个数据库操作失败,已经执行的任何操作都必须撤销,让数据库返回初始状态。
2,一致性:事务操作成功后,数据库所处的状态和它的业务规则是一致的,即数据不会被破坏。如从a账户转账100元到b账户,不管操作成功与否,a账号和b账户的存储总额是不变的。
3,隔离性:在并发数据操作时,不同的事务拥有各自的数据空间,它们操作不会对对方产生干扰。准确地说,并非要求做到完成不干扰。数据库规定了多种事务隔离级别,不同的隔离级别对应不同的干扰程度,隔离级别越高,数据一致性越好,但并发性越弱。
4,持久性:一旦事务提交成功后,事务中所有的数据操作都必须被持久化到数据库中。即使在提交事务后,数据库马上崩溃,在数据库重启时,也必须保证能够通过某种机制恢复数据。
数据并发问题
1,脏读(dirty read)
a事务读取b事务尚未提交的更改数据,并在这个数据的基础上进行操作。
2,不可重复读(unrepeatable read)
不可重复读是指a事务读取了b事务已经提交的更改数据。
3,幻读(phantom read)
a事务读取了b事务提交的新增数据,这时a事务将出现幻读的问题。
4,第一类丢失更新
a事务撤销时,把已经提交的b事务的更新数据覆盖了。
5,第二类丢失更新
a事务覆盖了b事务已经提交的数据,造成b事务所做操作丢失。
回滚机制
spring事务管理器回滚一个事务的推荐方法是在当前事务的上下文内抛出异常。spring事务管理器会捕捉任何未处理的异常,然后依据规则决定是否回滚抛出异常的事务。
默认配置下,spring只有在抛出的异常为运行时unchecked异常时才回滚该事务,也就是抛出的异常为RuntimeException的子类(Errors也会导致事务回滚),而抛出checked异常则不会导致事务回滚。
可以明确的配置在抛出那些异常时回滚事务,包括checked异常。也可以明确定义那些异常抛出时不回滚事务。
还可以编程性的通过setRollbackOnly()方法来指示一个事务必须回滚,在调用完setRollbackOnly()后你所能执行的唯一操作就是回滚。
demo
@Service
public class DemoServiceImpl implements DemoService {
@Autowired
PersonRepository personRepository;
/**
* 如果不指定checked异常回滚,抛出checked异常不会导致事务回滚
* @return
* @throws IOException
*/
@Transactional
@Override
public Person savePersonWithoutRoolbackByCheckedEx() throws IOException {
Person person = new Person(null,"a",1,"test");
Person p =personRepository.save(person);
if(person.getName().equals("a")){
throw new IOException("test");
}
return p;
}
/**
* 如果指定checked异常回滚,抛出checked异常s会导致事务回滚
* @return
* @throws IOException
*/
@Transactional(rollbackFor = {IOException.class})
@Override
public Person savePersonWithRoolbackByCheckedEx() throws IOException {
Person person = new Person(null,"b",2,"test");
Person p =personRepository.save(person);
if(person.getName().equals("b")){
throw new IOException("test");
}
return p;
}
/**
* 默认配置下,spring只有在抛出的异常为运行时unchecked异常时才回滚该事务,
* 也就是抛出的异常为RuntimeException的子类(Errors也会导致事务回滚),
* 而抛出checked异常则不会导致事务回滚。
*
* @return
*/
@Transactional
@Override
public Person savePersonWithRollBack() {
Person person = new Person(null,"c",3,"test");
Person p =personRepository.save(person);
if(person.getName().equals("c")){
throw new IllegalArgumentException("test");
}
return p;
}
/**
* 指定的unchecked异常跟抛出的unchecked异常不一致,但还是会回滚事务
* @return
*/
@Transactional(rollbackFor = {NullPointerException.class})
@Override
public Person savePersonWithRollBack2() {
Person person = new Person(null,"d",4,"test");
Person p =personRepository.save(person);
if(person.getName().equals("d")){
throw new IllegalArgumentException("test");
}
return p;
}
/**
* 指定特定异常不回滚事务
* @return
*/
@Override
@Transactional(noRollbackFor={IllegalArgumentException.class})
public Person savePersonWithoutRollBack(){
Person person = new Person(null,"e",5,"test");
Person p =personRepository.save(person);
if(person.getName().equals("e")){
throw new IllegalArgumentException("test");
}
return p;
}
}
注解事务行为
参考:
https://www.cnblogs.com/yepei/p/4716112.html
《JavaEE开发的颠覆者 Spring Boot实战》