事务的ACID原则是什么?
- 原子性(atomicity):最小且不可分割的。要么都执行,要么都不执行。
- 一致性(consistency):事务的执行使得数据库从一种正确状态转换成另一种正确状态
- 隔离型(isolation):各事务同步执行时,所获取的数据,不受其他事务的影响。
- 持久性(durability):事务提交之后,结果永远保存在数据库中。
并发下事务会产生什么问题?
- 脏读:事务A读取了事务B未提交的数据。
- 不可重复读:在同一个事务里面读取了两次某个数据,但是读出来的数据不一致。
- 幻读:在同一个事务里面读取了两次某个数据,后一次查询到了前一次没有查到的记录(专指新插入的行)。
- 更新丢失:分成一类更新丢失和二类更新丢失。一类:回滚丢失。二类:覆盖更新丢失。即后修改的记录会覆盖前修改的记录。(加排他锁解决)
mysql事务的隔离级别有几种?
- DEFAULT:默认隔离级别(REPEATABLE-READ)
- READ_UNCOMMITTED:读未提交。能够读取到其他事务未提交的数据(会有并发问题)
- READ_COMMITTED:读已提交。能够读取到其他事务已提交的数据。(简称RC。可以解决脏读,但是会有不可重复读、幻读问题)
- REPEATABLE_READ:重复读。(简称RR。可以解决脏读、不可重复读,但是会有幻读问题)
- SERLALIZABLE:串行化。不管多少事务挨个执行。(能解决所有问题,但是会有性能问题,相当于单线程)
如何解决更新丢失问题:
使用行锁(Record Lock):锁定索引记录,锁住的是key
(1)悲观锁(假设大概率出现更新丢失,一开始就锁住,不过要注意死锁问题)
1、添加共享锁:select …… lock in share model;
共享锁又叫读锁(S锁)。表示本事务可读可写,但其他事务可读不可写。
2、添加排他锁:select …… for update;
排他锁又叫写锁(X锁)。表示本事务可读可写,但其他事务不可读不可写。
(2)乐观锁(假设小概率出现更新丢失,最后一步更新前再锁)
实现方法:在表中增加一列timestamp类型的字段,每次更新或插入都记录最新时间。
当修改数据时查询条件带上timestamp类型的字段。例如:where id=1 and lastUpdateTime='2020-10-12 11:15:03'。当返回影响的行数是0时,说明本次修改失败,提示用户操作过期。
如何解决幻读问题:
也是使用排他锁
mysql查询隔离级别:
1.查看当前会话隔离级别
select @@tx_isolation;(mysql版本 8.0 之前)
select @@transaction_isolation (mysql版本 8.0 以后)
2.查看系统当前隔离级别
select @@global.tx_isolation;
3.设置当前会话隔离级别
set session transaction isolatin level repeatable read;(参数可以为:Read uncommitted|Read committed|Repeatable read|Serializable))
只对当前会话有效
4.设置系统当前隔离级别
set global transaction isolation level repeatable read;
此后所有的会话有效,当前已经存在的会话不受影响
spring Transaction事务传播行为有哪几种?
- PROPAGATION_REQUITRED:如果当前没有事务就创建一个新事务。如果当前存在事务则加入(与父事务相互独立,若父事务回滚不影响子事务)。(常用)
- PROPAGATION_NESTED:如果当前没有事务就创建一个新事务。如果当前存在事务,则在嵌套事务内执行(与父事务相依,若父事务回滚则子事务也回滚)。关键是savepoint
- PROPAGATION_SUPPORTS:如果当前没有事务就已非事务运行。如果当前存在事务则加入。(有父事务就事务运行,没有就非事务运行)
- PROPAGATION_MANDATORY:如果当前没有事务则抛出异常。如果当前存在事务则加入。(他只能被父事务调用。否则,他就要抛出异常)
- PROPAGATION_REQUITRED_NEW:无论当前是否存在事务,都创建新事务。(与PROPAGATION_REQUIRED 的事务区别在于事务的回滚程度,如果子事务异常,父事务捕获后依然会提交)
- PROPAGATION_NOT_SUPPORTED:以非事务运行。如果当前存在事务则把当前事务挂起。(挂起父事务,子事务以非事务执行完毕后,再执行父事务)
- PROPAGATION_NEVER:以非事务运行。如果当前存在事务则抛出异常。(他不能被父事务调用。否则,他就要抛出异常)