隔离级别
数据库中隔离级别四种
Isolation.DEFAULT 默认,使用数据库默认的隔离级别
隔离级别越往下,安全性越高,数据越安全。
Isolation.READ_UNCOMMITTED 读未提交,即使没有提交,但是做了更改也可以被读到。会产生脏读、幻读,不可重复读。
Isolation.READ_COMMITTED 读已提交,只读取已经提交的事务。会产生幻读,不可重复读。
Isolation.REPEATABLE_READ 可重复读,两个事务之间的读写不冲突。当一个事务进行数据读取,另一个事务进行了修改之后,第一个事务 再次读取,但是数据依旧和第一次读到的一样。可重复读
Isolation.SERIALIZABLE 序列化。效率低。不会脏读、幻读、重复读
System.out.println(" ------------ 事务类型 -----------");
// test.transTestException(3,"zhang"); //执行过程中抛异常了,事务被回滚
// test.transTestExceptionTry(3,"zhang"); //执行过程中异常被try了,事务不会回滚
// test.transTestReadOnly(3,"zhang"); //只读事务,只读过程中不允许修改
// test.transTestNoRoll(3,"zhang");//设置哪些异常不进行回滚,继续提交
// test.transTestRollBack(3,"zhang");//遇到此类异常回滚,不进行提交
System.out.println(" --------- 事务的 ACID 属性-----------");
System.out.println(" A 原子性 要么完整执行,要么不执行");
System.out.println(" B 一致性 一致性代表了底层数据存储的完整性");
System.out.println(" I 隔离性 访问的数据不能受其它部分的影响");
System.out.println(" D 持久性 对数据的修改都必须在事务结束前保存至物理存储中");
System.out.println("------------ 事务隔离级别 从上往下隔离级别越来越高,数据也越安全-------------");
// @Transactional(isolation = Isolation.DEFAULT)
// Isolation.DEFAULT
System.out.println(" 使用数据库默认的隔离级别");
// Isolation.READ_UNCOMMITTED
System.out.println("1. 读未提交 允许读取尚未提交的修改,可能导致脏读、幻读和不可重复");
System.out.println(" 可以读取到已修改但是未提交事务的数据 (产生 : 脏读)");
// Isolation.READ_COMMITTED
System.out.println("2. 读已提交 允许从已经提交的事务读取,可防止脏读、但幻读,不可重复读仍然有可能发生");
System.out.println(" 只能读取到已经提交事务的数据 产生不可重复读。 一个事务正在修改数据,另一个事务读取两次,在两次中间,另一个事务提交了,造成两次数据不一致(不可重复读)");
// Isolation.REPEATABLE_READ
System.out.println("3. 可重复读 对相同字段的多次读取的结果是一致的,除非数据被当前事务自身修改。可防止脏读和不可重复读,但幻读仍有可能发生");
System.out.println(" 两个事务,独立执行。一个事务修改数据,另一个事务进行多次读取,即使第一个事务提交,第二次事务内(未提交前)读取的数据一致 。 会产生幻读");
// Isolation.SERIALIZABLE
System.out.println("4. 序列化 完全服从acid隔离原则,确保不发生脏读、不可重复读、和幻读,但执行效率最低");
System.out.println(" ---数据不一致的问题 ---");
System.out.println(" 脏读");
System.out.println(" 不可重复读");
System.out.println(" 幻读 由于可重复读,两个事务独立。当一个事务添加一条数据时,当前事务读取不到,插入一条相同数据时,但是该数据已经存在了。");
System.out.println(" 锁机制 (粒度) 锁的粒度越小,效率越高。一般是行锁");
System.out.println("1. 数据库级别");
System.out.println("2. 表级别");
System.out.println("3. 行");
System.out.println(" --------- 事务的传播特性 7 ------------");
mysql默认的事务处理级别是'REPEATABLE-READ',也就是可重复读
oracle 默认系统事务隔离级别是READ COMMITTED,也就是读已提交
事务的隔离级别
如图,事务的传播特性有 7 个
Propagation.REQUIRED
如果有事务在运行,当前的这个方法就在事务内运行.否则就开启新的事务,在自己的事务内运行
@Transactional
public void transPropagationTest(){
transProReq(5,"zhangsan");
}
/* 如果有事务在运行,当前的这个方法就在事务内运行
* 否则就开启新的事务,在自己的事务内运行
*/
@Transactional(propagation = Propagation.REQUIRED)
public void transProReq(Integer price,String name){
transTestDao.updateBalance(name,price);
}
Propagation.REQUIRES_NEW
当前的方法必须启动新事务,并在自己的事务内运行。如果有事务在运行,将它挂起
/* 当前的方法必须启动新事务,并在自己的事务内运行。如果有事务在运行,将它挂起
*/
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void transProReqNew(Integer price,String name){
transTestDao.updateBalance(name,price);
}
Propagation.MANDATORY
当前的方法必须运行在事务内部,如果没有正在运行的事务则抛出异常
/*
* 当前的方法必须运行在事务内部,如果没有正在运行的事务则抛出异常
*/
@Transactional(propagation = Propagation.MANDATORY)
public void transProMan(Integer price,String name){
transTestDao.updateBalance(name,price);
}
Propagation.NEVER
当前的方法不应该运行在事务内,如果有运行的事务,就抛出异常
/*
* 当前的方法不应该运行在事务内,如果有运行的事务,就抛出异常
*/
@Transactional(propagation = Propagation.NEVER)
public void transProNever(Integer price,String name){
transTestDao.updateBalance(name,price);
}
Propagation.NESTED
如果有事务在运行,当前的方法就应该在这个事务的嵌套事务内运行。否则就启动一个新的事务,在自己的事务内运行。
如果里面的事务没有异常则不回滚,如果外面的事务有异常没被捕获,里面的事务才会被回滚。
/*
* 如果有事务在运行,当前的方法就应该在这个事务的嵌套事务内运行。
* 否则就启动一个新的事务,在自己的事务内运行。
*/
@Transactional(propagation = Propagation.NESTED)
public void transProNested(Integer price,String name){
transTestDao.updateBalance(name,price);
}
Propagation.SUPPORTS
如果有事务在运行,当前的方法就在这个事务内运行.否则它可以不运行在事务中
/*
* 如果有事务在运行,当前的方法就在这个事务内运行
* 否则它可以不运行在事务中
*/
@Transactional(propagation = Propagation.SUPPORTS)
public void transProSupports(Integer price,String name){
transTestDao.updateBalance(name,price);
}
Propagation.NOT_SUPPORTED
当前的事务不应该运行在事务中,如果有运行的事务,就将它挂起
/*
* 当前的事务不应该运行在事务中,如果有运行的事务,就将它挂起
*/
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void transProNotSupports(Integer price,String name){
transTestDao.updateBalance(name,price);
}