MySQL事务和锁

什么是事务:

就是把多个要做的操作组合成一个整体,利用事务的特性来保证操作的安全性。如果一个事务做到一半出现任何错误,就会进行回滚操作,来恢复成最初的模样。

特性:

原子性(Atomicity):表示一组语句要么同时成功要么同时失败

一致性(Consistency) :回滚后返回到上一次正确状态

隔离性 (Isolation) :多个线程之间事务互不影响

持久性(Durability):一旦提交,不可撤销

mysql的每一个连接默认都是自动提交事务,每一句语句的执行,就提交一句。所以你如果需要手动提交事务可以进行如下配置(mysql只有innodb引擎才支持事务

(1)set autocommit = false/0; 对于整个连接都起作用,整个连接的sql语句都变成手动提交

(2)start transaction; 仅仅是对于start transaction; 到 rollback; /commit;之间的语句是手动提交,对于该连接的其他语句还是自动提交(开启事务之后,你只要一直运行commit,它就没有提交)

多线程事务中会产生的问题

(1)脏读

例如:T1线程中,访问了一个数据,这个数据是T2线程中修改但还未提交的数据

(2)不可重复读

例如:T1线程未结束之前,访问了一个数据,之后又访问这个数据,两次的访问结果不一致,这个数据在T2线程中被修改,并提交了。

(3)幻读

例如:T1线程对某个表做查询,同样一个查询语句,第一次查询有n行记录,然后又查询一次时,发现有N+M行记录,发现多了或少了M行,因为T2线程增加了M行或删除了M行

解决的方案:设置隔离级别
在这里插入图片描述
如果要避免以上三个问题,事务的隔离级别是 Serializable

如何设置?

set tx_isolation=’read-uncommitted’

如何查看?

select @@tx_isolation;

【注意】

隔离级别从小到大,安全性越来越高,但是效率越来越低。但是一般情况下不会修改数据库默认的隔离级别,只有在极特殊情况下才会做出修改用以解决一些特殊问题。设置数据库的隔离级别一定要是在开启事务之前;隔离级别的设置只对当前连接有效。

解决不可重复读的方法是 锁行,解决幻读的方式是 锁表。

MySQL中有 快照读和当前读之分:

快照读:读取的是记录数据的可见版本(可能是过期的数据)不用加锁。Select为快照读,它是MVCC实现,不需要竞争锁。
当前读:读取的是记录的最新版本,并且返回的记录都会加上锁。保证了其他的事务不会再并发的修改这些记录。Insert, update, delete都是当前读,排他锁。

MVCC是什么?有什么作用?实现原理是什么?

是一个多版本的并发控制机制,在数据库中实现了高并发的数据访问,对数据进行多版本处理,并通过事务的可见性来保证事务能够看到自己应该看到的数据版本。

MVCC的作用:是如果某条记录正在被修改,则可以并发读取该记录的历史版本,而不必阻塞等待读锁的释放。它的实现方式是通过Undo
log和ReadView实现的,可以读取Undo
log里的历史版本,ReadView用于控制哪个历史版本是对当前事务可见。对同一个事务只会生成一个ReadView,所以避免了可重复读的问题。MVCC的优点在于它能够提供更好的并发性能和更高的数据一致性。相比于传统的锁机制,在并发读取操作的情况下,不需要对数据进行加锁,可以提高并发度。

MVCC的原理是:在MySQL中,每个数据行都有一个隐藏的6字节字段,用于保存数据的版本号。这个版本号是一个单调递增的数字,每次进行写操作时会增加。
当一个事务开始时,MySQL会为该事务分配一个唯一的事务ID(Transaction
ID),用于标识该事务。在进行读取操作时,事务会记录它的开始时间戳,这个时间戳用于判断事务是否能够看到某个版本的数据。
当进行写操作时,MySQL会为新版本的数据分配一个新的版本号,并将旧版本的数据标记为删除。这样,读取操作会忽略已经删除的版本,只读取当前有效的版本。

MySql默认的数据库引擎INNODB支持表级锁和行级锁。

锁根据粒度可分为:

表级锁:

表级锁是数据库中一种常见的锁机制,它锁定整个表而不是表中的单个行。当一个事务锁定了某个表时,其他事务就无法同时对该表进行修改操作,只能等待锁被释放。

表级锁可以控制并发访问,保证数据的一致性和完整性。当多个事务需要修改同一张表的不同行时,表级锁可以避免多个事务之间的竞争和冲突。

然而,表级锁也存在一些问题。由于锁定整个表,其他事务可能因等待锁而产生延迟。另外,表级锁的粒度较大,可能导致并发性能不佳。

对于表级锁的具体实现和管理,可以根据具体的数据库管理系统和锁机制来进行配置和调优。一些数据库管理系统也支持更细粒度的锁,如行级锁或页级锁,以提高并发性能和并发访问的效率。
记录锁、

行级锁==>>行级锁分为共享锁(乐观锁)和排他锁(悲观锁)

悲观锁是基于一种悲观的态度类来防止一切数据冲突,它是以一种预防的姿态在修改数据之前把数据锁住,然后再对数据进行读写,在它释放锁之前任何人都不能对其数据进行操作,直到前面一个人把锁释放后下一个人数据加锁才可对数据进行加锁,然后才可以对数据进行操作,一般数据库本身锁的机制都是基于悲观锁的机制实现的;

乐观锁是对于数据冲突保持一种乐观态度,操作数据时不会对操作的数据进行加锁(这使得多个任务可以并行的对数据进行操作),只有到数据提交的时候才通过一种机制来验证数据是否存在冲突(一般实现方式是通过加版本号然后进行版本号的对比方式实现)。也就是说所有事务都可以更改,但最后提交是看谁的版本号更新,就提交谁的数据。

行级锁(Row-level
locking)是一种数据库中的锁机制,它在事务级别上锁定数据库表中的行,而不是锁定整个表。行级锁允许多个事务同时访问同一张表,但只有在执行更新或删除操作时才锁住相关行,以保证数据的一致性和完整性。

与表级锁不同,行级锁的粒度更细,所以在并发访问的情况下,可以提供更高的并发性能。当一个事务需要修改或删除某一行时,它会对该行进行加锁,其他事务就无法对该行进行修改或删除操作,直到锁被释放。

行级锁可以通过锁定行的方式来保证数据的一致性。当多个事务同时访问同一张表的不同行时,行级锁可以避免脏读、幻读和不可重复读等问题的发生。行级锁通常由数据库管理系统自动处理,而不需要用户显式地进行操作。

需要注意的是,行级锁可能导致死锁问题。当多个事务相互等待对方释放锁时,可能会出现死锁情况。为了避免死锁,数据库管理系统通常会使用各种算法来检测和解决死锁问题。

间隙锁

间隙锁是一种数据库锁定机制,用于解决并发事务中的幻读问题,即在一个事务中查询的结果受到其他事务的插入操作影响。

间隙锁是在一个范围之间的索引键上设置的锁,它可以防止其他事务在该范围之内进行插入操作。当事务A在一个范围上设置间隙锁后,其他事务B就无法在该范围内插入新的数据。这样,事务A在读取范围内的数据时,就不会受到其他事务插入数据的干扰,从而避免了幻读问题的发生。

使用间隙锁可以保证数据的一致性和完整性,但同时也可能影响并发性能。当多个事务同时操作相同的范围时,可能会出现锁竞争和阻塞的情况。因此,使用间隙锁需要根据具体的数据库管理系统和应用场景进行合理的配置和调优。

怎么理解间隙锁?(索引之间)

假设你正在一本书中的某一页上写字,而且正准备写在页码为50到60之间的空白区域。为了确保其他人不会在你写字的过程中也在同样的范围内写字,你会选择在这个范围之间的位置放置一个间隙锁。

这个间隙锁就像一个标志,告诉其他人这个范围正在被使用,不能插入新的内容。任何想要在这个范围内插入新的内容的人都必须等待,直到你完成写字并移除间隙锁。这样,你就可以安心地写下你想要的内容,而不用担心其他人干扰你。

间隙锁类似于数据库中的锁定机制。它们用于保护一段范围内的数据,以防止其他事务对该范围内的数据进行插入操作,从而维护数据的一致性和完整性。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值