自己之前一直对这几个概念搞不清楚,这里做一个小的总结,方便以后查看。
1、事务
数据库运行的基本工作单位是事务,事务是用户定义的一组操作序列,这些操作序列要么全做,要么全都不做,是一个不可分割的工作单位。
事务ACID特性:
- 原子性(Atomicity):是一个整体,像原子一样不可分割,要么全部成功,要么全部失败;
- 一致性(Consistency):事务的执行结果必须使数据库从一个一致性状态到另一个一致性状态;
- 隔离性(Isolation): 并发执行的事务不会相互影响,其对数据库的影响和它们串行执行时一样。
- 持久性(Durability):事务一旦提交,其对数据库的更新就是持久的。任何事务或系统故障都不会导致数据丢失。
关于事务的详细介绍和实现原理可以参考:www.cnblogs.com/takumicx/p/…
2、并发控制
2.1 并发操作可能带来的问题
数据库的并发操作带来的主要问题有:丢失更新、不可重复读、脏读、脏写、幻读。
- 丢失更新(W-W):两个事务T1和T2同时对一数据进行修改,T2修改的结果覆盖了T1修改的结果,T1修改丢失
- 不可重复读(R-W):事务T1读取某一个数据后,事务T2执行更新操作,使T1无法再现前一次读取结果
- 脏读: 事务T1修改某一数据,事务T2读取同一数据后,T1由于某种原因被撤销,,T2读到的数据就与数据库中的数据不一致,称为“脏”数据。
- 脏写
- 幻读
2.2 锁
如何处理这些并发操作可能带来的问题?
DBMS必须提供并发控制机制。 并发控制的主要技术有:封锁、时间戳、乐观控制法、多版本并发控制。
封锁是实现并发控制的一种有效手段。
封锁是事务T在对某个数据对象操作时候,要对先其加锁,加锁后事务T就对该数据对象有了一定的控制,在事务T释放它的锁之前,其他事务不能更新此数据对象。
2.2.1 封锁的类型
主要有两种类型的锁,分别是排他锁(X锁)和共享锁(S锁):
- 排他锁(X锁):事务T对数据A加上
X锁后,只有事务T可以读取和修改数据,直到事务T解锁,因此也称独占锁。 - 共享锁(S锁):若事务T对数据对象A加上
S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁为止。
2.2.2 封锁带来的死锁问题
采用封锁方法固然可以有效解决数据的不一致性,但封锁本身也会产生一些问题,主要就是死锁。
如果事务T1封锁了数据R1,T2封锁了数据R2,然后T1又请求封锁R2,因T2封锁了R2,于是T1等待T2释放R2上的锁;接着T2又请求封锁R1,因T1封锁了R1,于是T2等待T1释放R1上的锁。这样就出现了T1在等待T2,而T2又在等待T1的局面,T1、T2两个事务永远不能结束,形成死锁。
2.2.3 事务隔离级别
2.2.4 其他锁的概念
锁的级别、悲观锁乐观锁、
特性:
-
每一数据元素都有唯一的锁;
-
事务在读写数据前,要获得锁;
-
事务被其他事务持有该元素的锁,则要等待;
-
事务处理完成后要释放锁;
数据库管理系统对事务的控制
之前不了解事务、锁这些知识,一直以为事务/锁都是程序员自己通过代码控制的,其实数据库管理系统自身有事务调度器,并综合考虑并发性能和事务隔离,取一个平衡。
Mybatis 乐观锁、悲观锁
个人理解这可以说是程序级别的锁,通过给数据库增加一个字段(比如version),每次更新都给这个version+1,在更新的时候判断此时数据库中这条数据的version值是否与取出时相等,以此解决两个用户操作同一条数据,后边的操作者在不知情的情况下覆盖了前者的操作;
@Transcation注解
spring声明式的事务管理,在具体的方法上添加该注解,如果抛出异常,事务会自动回滚,数据不会插入数据库。
参考
blog.csdn.net/liyunyou/ar… www.cnblogs.com/fjg2572120/… blog.csdn.net/zhouym_/art…