mysql-事务隔离级别以及锁详解

目录

一、事务的隔离级别

1、什么是事务、事务有哪些特性

持久性:事务一旦提交,它对数据库中的数据的改变就是永久性的 事务并发情况下可能会产生的问题有哪些

事务的隔离级别有哪些?默认的隔离级别是什么?

在设置可重复读的情况下,如何保证修改的是最新的数据?

mysql中设置事务隔离级别以及事务的操作

二、锁

说说mysql中有那些锁?

什么是死锁?怎么解决死锁问题?

innodb有哪些行锁算法


一、事务的隔离级别

1、什么是事务、事务有哪些特性

事务:一个或一组sql语句组成的一个执行单元,这个执行单元里面的sql要么都执行,要么都不执行

四大特性:

原子性:

原子性指事务时一个不可分割的工作单位,事务中的操作要么都执行要么都不执行

一致性:
从一个正确的状态,迁移到另一个正确的状态.什么叫正确的状态呢?就是当前的状态满足预定的约束就叫做正确的状态.

隔离性:
事务的隔离性是指一个事务的执行不能被其他事务干,即一个事务内部的操作以及使用的数据对并发的其他事务时隔离的,并发执行的各个事务之前互不干扰

持久性:
事务一旦提交,它对数据库中的数据的改变就是永久性的
 
事务并发情况下可能会产生的问题有哪些

脏读:
对于两个事务T1、T2,T1读取了已经被T2更新但还没提交的字段之后,若T2回滚,T1读取的内容就是临时且无效的

不可重复读:
对于两个事务T1、T2,T1读取了一个字段,然后T2更新了该字段之后,T1再读取一次该字段,值不相同

幻读:
对于两个事务T1、T2,T1从一个表中读取了一个字段,然后T2再在该表中插入一些新数据,之后T1再次读取同一个表,就会多出几行


事务的隔离级别有哪些?默认的隔离级别是什么?

READ UNCOMMITTED  读未提交,该模式下会出现并发事务的所有可能出现的问题
READ COMMITTED  读已提交,能够成功解决脏读现象(不支持间隙锁)
REPEATABLE READ(默认的隔离级别)  可重复读,能够成功解决不可重复读现象,可能会解决幻读现象(通过间隙锁),性能几乎不受影响(select语句通过mvcc维护,不加锁)
SERIALIZABLE 串行化,能够解决并发事务下的所有问题,通过禁止另一个事务增删改的方式,效率非常低下,在分布式事务下使用(对于所有的操作都加锁处理)

  • oracle支持两种隔离级别:READ COMMITED、SERIALIZABLE,默认是 READ  COMMITED
  • mysql支持四种隔离级别:(以上四种),默认是REPEATABLE READ

在设置可重复读的情况下,如何保证修改的是最新的数据?

根据可重复读的特性,在一个事务中通过MVCC机制多次读取到的值一定是相同的,而可能此时真实的数据以及被修改了,那么怎么保证修改的数据是最新的呢?

改变以往通过java代码获取当前值然后作为参数修改数据的形式,将数据的变更和获取融合在一起

update student set score = score+ 5 ;

因为在mysql的mvcc机制的控制下,select读取的实际是历史版本,而增删改会读取当前版本

mysql中设置事务隔离级别以及事务的操作

  • SET autocommit = 0;  关闭自动提交
  • set tx_isolation='read-uncommitted';设置读未提交
  • set tx_isolation='read-committed';设置读已提交隔离级别
  • SET tx_isolation = 'repeatable-read';   设置可重复读隔离级别
  • set tx_isolation='serializable';设置串行化隔离级别
  • start TRANSACTION ;开启事务
  • commit;  提交提交事务
  • rollback ;回滚事务

二、锁

说说mysql中有那些锁?

按操作分类:

共享锁:也叫读锁。针对同一数据,多个事务读取操作可以同时加锁互不影响,但是不能修改数据。

innodb 共享锁:sql+ lock in share mode;例 select * from student lock in share mode;

        当开启共享锁的时候,当前事务可以查询数据、修改数据,并且可以更换锁的类型;其他事务可以对该行进行共享锁查询,但是不能加排他锁查询,也不能修改数据。

myisam 读锁:加锁:lock table 表名  read;解锁:unlock   tables;

        可以多个会话同时对一个表添加读锁,但是不能修改数据以及添加写锁。同一个会话添加读锁后也不能修改当前表的数据,

排他锁:也叫做写锁。当前操作没完成时,会阻断其他操作的加锁读取和修改数据。

innodb 排他锁:sql+for update  例 select * from student for update;

        当开启排他锁时,当前事务可以查找数据和修改数据,也可以修改锁的类型,但是即便从排他锁变成共享锁,其他事务也不能加锁查询,本质上还是排他锁,其他事务只能查询数据,不能加锁也不能修改数据。

myisam 写锁:lock table 表名 write ;解锁:unlock tables; 

        当前会话可以查询和修改数据,其他会话不能查询和修改数据

按粒度分类:

表级锁:锁住整个表,开销小,加锁快,锁粒度大,发生锁冲突概率高,并发力度低,不会出现死锁现象。
          myisam存储引擎支持的就是表锁,innodb存储引擎也支持表锁,但是默认的是行锁

行级锁:锁住当前行,开销大,加锁慢,锁粒度小,发生锁冲突概率低,并发度高,会出现死锁现象。
           innodb存储引擎默认支持行锁,但是需要用索引当作检索条件命中数据才能施加行锁

按照使用方式:

悲观锁:对数据被外界修改保持保守状态,认为数据随时会被修改,整个数据处理过程中需要将数据加锁,悲观锁一般都是依靠关系型数据库提供的锁机制,我们之前学过的锁(共享锁,排他锁,读锁,写锁)都是悲观锁;用于写多读少


乐观锁:每次自己操作数据的时候认为没有人会修改他,所以不去加锁,但是在更新的时候去判断再次期间数据有没有被修改,需要用户自己去实现,不会发生抢占资源,只有在提交操作的时候检查是否违反数据完整性;用于读多写少
方式:给数据表添加一个version列,每次 更新后都将这个列的值加一,读取数据时,将版本号取出来,在执行更新的时候,比较版本号,如果相同则执行,如果不相同说明这条数据已经发生变化了,用户自行根据这个通知来决定怎么处理,比如重新更新一次或者放弃更新。
 

什么是死锁?怎么解决死锁问题?


死锁是指两个或多个事务在同一资源上相互占用,并请求锁定对方的资源,从而导致恶性循环的现象。

常见的解决死锁的方法

  1. 如果不同程序会并发存取多个表,尽量约定以相同的顺序访问表,可以大大降低死锁机会。
  2. 在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁产生概率;
  3. 对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率;
  4. 如果业务处理不好可以用分布式事务锁或者使用乐观锁
     

innodb有哪些行锁算法


Record lock:单个行记录上的锁
当查询的索引含有唯一属性时,将next-key lock降级为record key

Gap lock:间隙锁,锁定一个范围,不包括记录本身
当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁。

关闭间隙锁的方法1、将事务隔离级别设置为read committed; 2、将参数innodb_locks_unsafe_for_binlog设置为1

Next-key lock:record lock+gap lock 锁定一个范围,包含记录本身
innodb对于行的查询使用next-key lock
 

未完待续

猜你喜欢

转载自blog.csdn.net/Promise_J_Z/article/details/121895746