mysql事务与锁

1 事务针对范围:

(1)mysql的任何一个修改操作sql(insert update delete)事务都是客观伴随的,只不过默认是自动提交,这种情况,一旦执行sql,就自动commit了

(2)sql可以实现手动提交(关闭自动提交):

         (2.1) start  transaction / begin/ set autocimmit = 0

         (2.2)执行update/insert/delete sql 但是没有提交到数据库

         (2.3)commit 提交到数据库

2 事务特性

  (2.1) 原子性:一个事务里有很多条sql(修改操作),这些sql要么全部执行成功,要么全部执行失败,就像原子一样,不能再被分割

  (2.2)一致性:事务执行完成后,数据库状态从一个一致的状态转换到另一个一致的状态,即执行事务之前状态满足约束条件,事务执行完成后状态满足约束条件。

               例子:用户A给用户B转100,A-100,B+100。那是最终的A+B任然保持不变

  (2.3)隔离性:就是每个事务是在不同的session中相互隔离、互不影响。在commit事务之前,修改操作不会提交到数据库。

               session1的select操作不能读取到session2在commit之前修改数据库的结果,session1和session2仿佛隔离状态

               但在session中update、delete会有加: 行锁 ,一定会等到其它session commit该记录的修改操作后才能执行。(select不会加 行锁,故而胀读) 比如:

session1 session2

begin 
update t_charge_record 

set `status` = 3 

where 

id = 'WK-BK-20171211163735578073203' 

and `status`= 1

affect  num : 1

 
 

update t_charge_record

set `status` = 3 

where 

id = 'WK-BK-20171211163735578073203' 

and `status`= 1

  这时,事实上这句update是任然存在事务(自动),由于session1对这行还没有的修改还没commit,所以mysql自身存在一个行锁,必须等session1提交后,才释放行锁

commit

session1释放行锁

 
  affect num : 0 由于session1提交后不满足where条件,返回受影响行数为0

(2.4)持久性

                一旦成功commit后,数据就写到磁盘里面,持久化了,不可改变(妹的。。。把磁盘打碎算不算)

3 事务隔离级别

  胀读 不可重复读 幻读 更新丢失
未提交读
已提交读
可重复度(repeatable read )mysql 默认级别
可序列化

这里讨论的"是、否" 都是同一事务的不同实例(session)。不同事务的不同实例(session)不在讨论范围:

在 repeatable read 隔离级别,多个线程,执行同一个事务,尽管会产生不同session,但不会出现胀读和不可重读情况

4 InnoDB的行锁(针对select)

InnoDB有两种形式select行锁(注意:update/delete本身默认就会加行锁):共享锁、排他锁

(4.1)共享锁:select * from table lock in share mode

只是确保该条记录在整个事务中,不被修改(update delete),包括自己session和其它session。其它session修改会被阻塞,自己session修改会死锁

(4.2)排他锁:select * from table for update

保证在整个事务中,其它session不能修改此记录,且在自己session会修改此记录

5 乐观锁和悲观锁

乐观锁利用update/delete 操作本身行锁性质 + 返回受影响行数 + 版本号 实现

悲观锁利用排他锁实现

6 sql:begin,commit,rollback指令,与spring transaction 提交、回滚效果区别

7 事务中加java锁

8 数据库并发问题

(8.1)更新丢失:只有serializable级别可以完全避免更新丢失。账户余额并发修改:原有1000,扣两100钱,由于并发情况,第一次1000-100=900,第二次1000-100=900。那么第一次的减100的信息就丢失了。更新丢失需要靠应用程序保证。

第二类更新丢失:

在repeatable的级别时,

step1:

session1开启事务 读到账户=100,

step2:

session2开启事务 读到账户=100,

step3:

session2给账户增加100,修改账户=200,并提交。

step4:

可是尽管session2修改已经提交了,session1再次读取账户任然是100,而其他重新开启的事务读账户都是200(session1这时可能错误的认为了账户任然是100状态,满足条件,按原计划执行账户减少100操作:账户=0。也即可重复读级别)。

session1这时修改账户=0,那么覆盖了session2的修改(事实上我们希望账户是session1和session2共同修改的累加结果100)。

(8.2)胀读:session1更新记录1,但未提交。session2 select 记录1, 并根据搜索出来的记录1做后续操作,则造成未提交数据依赖关系问题,故称胀读。

(8.3)不可重复读:session1 读了记录1休息一下 ,session2 delete 记录1 ,这时session1再次读记录1,记录1不存在。

(8.4)幻读:幻读与不可重复读原理恰好相反,session1按照条件A查询,session2新插入数据,并且提交。session1按照条件1搜索出更多的果集

9 事务传播

以service方法为例,f1方法是一个事务,f2方法是一个事务,f1中调用f2时,f2的事务和f1事务的关系?

(9.1)PROPAGATION_REQUIRED:如果f1存在事务,则f2加入f1的事务。

              注意:spring默认事务传播,最常用!

(9.2)PROPAGATION_REQUIRES_NEW:无论f1是否有事务,f2都会新创建一个事务。

             注意:这种级别有死锁情况,f1和f2都更新一个表,会死锁。f1和f2更新不同表不会死锁,且事务独立

猜你喜欢

转载自blog.csdn.net/ShuaiFanPi/article/details/78129168