spring事务:
什么是事务:就是一个工作的最小单元体,通俗来说就是为了达到某个目的所做的一系列操作,要么一起成功,要么一起失败;
事务的四大特性:
1.原子性:事务中所有的操作是不可再分割的原子单位,事务中所有的操作要么全部执行成功,要么全部执行失败
2.一致性:事务执行后,数据库状态应该与其他业务规则保持一致,如转账业务中,无论事务执行成功与否,参与的两个账号余额之和是不应发生改变的
3.隔离性:隔离是指并发操作中,不同的事务应该隔离开来,事务之间不能存在干扰
4.持久性:一旦事务提交成功,事务中所有的数据操作都必须持久化到数据库中,即使提交事务后,数据库马上崩溃,重启之后也应该保证数据恢复;
事务的隔离级别:由低到高
1.READ UNCOMMITTED (读未提交):就是一个事务可以读取到另外一个事务未提交的数据(会产生脏读)
2.READ COMMITTED (读已提交):就是一个事务要等到另外一个事务已经提交了才会读取到(会产生不可重复读)
3.REPEATABLE READ(可重复读):就是一个事务读取的时候,会将数据锁起来,不允许做修改(会产生幻读)
4.SERIALIZABLE(序列化):最高级别,就是将事务串行化顺序执行,可以避免脏读,不可重复读和幻读,但是这种隔离级别比较消耗性能,一般不使用
一般数据库都是用的Read committed 读已提交,如:sql server,oracle
mysql默认隔离级别是Repeatable read(可重复读) enter)
在事务的并发操作中可能会出现的问题:
1.脏读:事务A读取了事务B尚未提交的事务,如果B事务回滚了,则A读取的就是错误信息
如:线程A读取此数据,线程B去修改了数据还没有提交,但是线程A确读取到线程B修改后的数据,这个时候线程B回滚掉,那么线程A之前读取的数据就是脏数据
2.不可重复读:(特指更新操作)不可重复读指的是对数据库中某个数据,一个事务范围内查询多次,返回了不同的值,这是由于这个数据查询的时候被其他事务给修改并提交了
如:线程A第一次读取数据的时候为100元,线程B在A第二次读取的中途去把100元更改成了50元,线程A读取的数据就不一样了,指的就是在时间范围内读取的数据是不一致的
3.幻读:(特指增加或者删除操作)在事务A多次读取的情况中,事务B对数据进行了新增操作,导致事务A多次读取数据不一致;
4.第一类事务丢失(回滚丢失):
就是A和B两个线程同时操作一个数据,然后B线程事务已经提交,然后A事务回滚了,这样B事务的操作就会因为A事务的回滚而丢失了==如:存钱罐内有100元,A线程拿出来了50,B线程在这个期间放了50进去,存钱罐内还是100元,A线程后来想想还是还回去,保证存钱罐内是100,那么对应代码中就会去判断是否等于100元,这个时候显而易见,所以A事务必然回滚;
5第二类事务丢失(覆盖丢失):
A和B两个线程同时操作一个数据,两个同时取到一个数据,然后B事务首先提交,接着A事务也跟着提交,这样子就覆盖了B事务,导致数据丢失
事务的传播特性:
什么是事务的传播特性:
就是指一个事务方法被另外一个事务方法调用时,这个事务方法应该如何进行;
事务的传播特性类型:
1:PROPAGATION_REQUIRED:默认事务类型,如果没有就新建一个事务;如果有,就加入当前事务,适合大多数情况
2.PROPAGATION_REQUIRES_NEW:如果没有就新建一个事务,如果有,就将当前事务挂起
3.PROPAGATION_NESTED:如果没有,就新建一个事务,如果有就将当前事务嵌套其他事务;
4.PROPAGATION_SUPPORTS:如果没有,就以非事务方式执行,如果有就是用当前事务
5.PROPAGATION_NOT_SUPPRORTED:如果没有,就以非事务方式执行,如果有,就将当前事务挂起,即无论如何不支持事务
6.PROPAGATION_NEVER:如果没有,就以非事务方式执行,如果有就抛出异常;
7.PROPAGATION_MANDATORY:如果没有就抛出异常,如果有就使用当前事务;
将事务传播特性分为三大类:
一.非事务执行
5.PROPAGATION_NOT_SUPPRORTED:如果没有,就以非事务方式执行,如果有,就将当前事务挂起,即无论如何不支持事务
6.PROPAGATION_NEVER:如果没有,就以非事务方式执行,如果有就抛出异常;
二.可有可无
4.PROPAGATION_SUPPORTS:如果没有,就以非事务方式执行,如果有就是用当前事务
三.必须有事务
1:PROPAGATION_REQUIRED:默认事务类型,如果没有就新建一个事务;如果有,就加入当前事务,适合大多数情况
2.PROPAGATION_REQUIRES_NEW:如果没有就新建一个事务,如果有,就将当前事务挂起
3.PROPAGATION_NESTED:如果没有,就新建一个事务,如果有就将当前事务嵌套其他事务;
7.PROPAGATION_MANDATORY:如果没有就抛出异常,如果有就使用当前事务;
事务的传播特性细节:(待更新)
@Service
public class Trancsctional1 {
@Resource
UserMapper userMapper;
/**
* 事务的传播特性:指一个事务方法被另外一个事务方法调用时应该怎么处理
* 如下:
* 1.A方法中调用了B方法,那么A方法再调用完B方法后出现异常,那么B方法如何处理?
* 2.B方法中调用了A方法,那么B方法再调用A方法后,B方法出现异常,那么B方法如何处理?
*/
@Transactional
public String A(){
System.out.println("A方法");
B();
//业务逻辑出现异常
return "";
}
@Transactional
public void B(){
System.out.println("B方法");
A();
//业务逻辑出现异常
}
/**
* 注意点1:
* 这里方法A中去调用方法B,但是这里使用了this.testB()那么这个方法中的事务就会失效,无论你配置什么事务传播特性
* 因为spring事务中使用的是SpringAop中的代理对象去调用的,这里的this不会生成代理对象,
* 所以这里可以将自己注入进来,然后调用生效
* @return
*/
/**
* @Transactional(propagation= Propagation.NEVER)
* 此事务的传播特性说明:绝对不用事务,非事务执行
* @return
*/
//@Transactional(propagation= Propagation.NEVER)
public String testA(){
User user = new User();
user.setId(20L);
user.setName("hhh");
user.setUserName("@222");
user.setPassword("222");
user.setAge(10);
user.setEmail("eeee");
user.setBirthday(new Date());
userMapper.insert(user);
//调用testB方法
this.testB();
int count=10;
if (count==10){
throw new RuntimeException("A方法出现异常");
}
return "做添加操作";
}
@Transactional(propagation= Propagation.NEVER)
public String testB(){
User user = new User();
user.setId(21L);
user.setName("hhh");
user.setUserName("@222");
user.setPassword("222");
user.setAge(10);
user.setEmail("eeee");
user.setBirthday(new Date());
userMapper.insert(user);
int count=10;
if (count==10){
throw new RuntimeException("A方法出现异常");
}
return "做添加操作";
}
}