by shihang.mai
1. Mysql事务
简称:ACID
特性 | 解析 |
---|---|
原子性 | 要么全部成功,要么全部失败 |
一致性 | 事务开启前和事务结束后,并不会存在中间状态。其他3个特性保证了这个特性。 |
隔离性 | 各个事务之间不相互影响。默认隔离级别可重复读 |
持久性 | 所以数据的修改都必须持久化到磁盘 |
隔离级别(并发事务会带来脏读、不可重复读、幻读,所以有隔离级别)
隔离级别 | 解析 | 会导致 |
---|---|---|
读未提交 | 会话A->update data,not commit,会话B->select data = 能查到会话A未提交的数据。出现脏读 | 脏读 |
读已提交 | 会话A->update data,not commit,会话B->不能查到会话A未提交的数据,解决了脏读。会话A->commit,会话B->查到了会话A更新的数据,但是会话B还在自己的事务内,前后查到的结果不一致。出现了不可重复读。 | 不可重复读 |
可重复读 | 会话A->update data,not commit,会话B->不能查到会话A未提交的数据,解决了脏读。会话A->commit,会话B->不能查到了会话A更新的数据,会话B还在自己的事务内,前后查到的结果一致,解决了不可重复读。会话A插入一条id=5的数据,commimt,会话B也插入一条id=5的数据,发现会话B主键和重复,这就出现了幻读。 | 幻读 |
序列化执行(串行执行) | 全部做串行化操作 | 没异常 |
隔离级别的实现是用锁实现的
- 读未提交级别,任何操作都不加锁
- 读已提交,基于MVCC,对于快照读不加锁,对于当前读,保证读到的记录加锁
- 可重复读,也基于MVCC,对于快照读不加锁,对于当前读,会使用next-key lock保证读到的记录和间隙加锁
- 序列化执行,直接都是当前读
2. spring事务-事务的传播机制
@Transactional(propagation = Propagation.REQUIRED)
简单的理解就是多个事务方法相互调用时,事务如何在这些方法间传播。
Spring中事务的默认实现使用的是AOP,也就是代理的方式,如果大家在使用代码测试时,同一个Service类中的方法相互调用需要使用注入的对象来调用,不要直接使用this.方法名来调用,this.方法名调用是对象内部方法调用,不会通过Spring代理,也就是事务不会起作用
事务传播类型 | 含义 |
---|---|
REQUIRED(默认) | 如果当前没有事务,则自己新建一个事务,如果当前存在事务,则加入这个事务 |
SUPPORTS | 当前存在事务,则加入当前事务,如果当前没有事务,就以非事务方法执行 |
MANDATORY | 当前存在事务,则加入当前事务,如果当前事务不存在,则抛出异常 |
REQUIRES_NEW | 创建一个新事务,如果存在当前事务,则挂起该事务 |
NOT_SUPPORTED | 始终以非事务方式执行,如果当前存在事务,则挂起当前事务 |
NEVER | 不使用事务,如果当前事务存在,则抛出异常 |
NESTED | 如果当前事务存在,则在嵌套事务中执行,否则REQUIRED的操作一样 |
Spring7个传播事务,最特殊的是NESTED,这里有必要解析一下
- 当外有有事务时
嵌套事务中执行。意思就是,内层报错,不影响外层;外层报错,会影响内层 - 当外层没事务时
自己开一个新事务执行
3. Spring事务-五个隔离级别
@Transactional(isolation = Isolation.DEFAULT)
隔离级别 | 含义 |
---|---|
DEFAULT | 使用数据库自身的隔离级别 |
READ_UNCOMMITTED | 读未提交 |
READ_COMMITTED | 读已提交 |
REPEATABLE_READ | 可重复读 |
SERIALIZABLE | 串行化 |
在开启事务时,用Isolation指定.当设置了spring的事务隔离级别,那么就按spring的事务隔离级别
原因:spring开启事务时,拿到的当前连接,会对当前会话设置事务隔离级别
//测试代码
@Component
public class Test {
@Autowired
JdbcTemplate jdbcTemplate;
@Transactional
public void test() {
jdbcTemplate.execute("insert into sc(id,score) values (13,50),(14,60)");
try {
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
}
@Transactional(isolation=Isolation.READ_UNCOMMITTED)
public void sle(){
List<Map<String, Object>> maps = jdbcTemplate.queryForList("SELECT * FROM sc");
System.out.println(maps);
}
}
网友评论