这时候我们就须要把autocommit关闭掉[autocommit = 0],实在也可以通过程序来掌握,只要一次commit就可以了,这样也才能更好的表示事务的特点!
一锁二判三更新
对付须要操作数值,比如金额,个数等等!
记住一个原则:一锁二判三更新
在MySQL的InnoDB中,预设的Tansaction isolation level 为REPEATABLE READ(可重读)
在SELECT 的读取锁定紧张分为两种办法:
SELECT ... LOCK IN SHARE MODESELECT ... FOR UPDATE这两种办法在事务(Transaction) 进行当中SELECT 到同一个数据表时,都必须等待其它事务数据被提交(Commit)后才会实行。
而紧张的不同在于LOCK IN SHARE MODE 在有一方事务要Update 同一个表单时很随意马虎造成去世锁。
大略的说,如果SELECT 后面若要UPDATE 同一个表单,最好利用SELECT ... UPDATE。
实例假设商品表单products 内有一个存放商品数量的quantity ,在订单成立之前必须先确定quantity 商品数量是否足够(quantity>0) ,然后才把数量更新为1。
sql如下:
SELECT quantity FROM products WHERE id=3; UPDATE products SET quantity = 1 WHERE id=3;
这里实在是不屈安的。
为什么不屈安呢?
少量的状况下或许不会有问题,但是大量的数据存取「铁定」会出问题。如果我们须要在quantity>0 的情形下才能扣库存,假设程序在第一行SELECT 读到的quantity 是2 ,看起来数字没有错,但 是当MySQL 正准备要UPDATE 的时候,可能已经有人把库存扣成0 了,但是程序却浑然不知,将错就错的UPDATE 下去了。因此必须透过的事务机制来确保读取及提交的数据都是精确的。
修正sql如下:
SET AUTOCOMMIT=0; BEGIN WORK; SELECT quantity FROM products WHERE id=3 FOR UPDATE;
此时products 数据中id=3 的数据被锁住,其它事务必须等待这次事务 提交后才能实行SELECT FROM products WHERE id=3 FOR UPDATE
如此可以确保quantity 在别的事务读到的数字是精确的。
UPDATE products SET quantity = '1' WHERE id=3 ; COMMIT WORK;
提交(Commit)写入数据库,products 解锁。
解释:
注1: BEGIN/COMMIT 为事务的起始及结束点,可利用二个以上的MySQL Command 视窗来交互不雅观察锁定的状况。注2: 在事务进行当中,只有SELECT ... FOR UPDATE 或LOCK IN SHARE MODE 同一笔数据时会等待其它事务结束后才实行,一样平常SELECT ... 则不受此影响。注3: 由于InnoDB 预设为Row-level Lock,数据列的锁定可参考这篇。注4: InnoDB 表单只管即便不要利用LOCK TABLES 指令,若情非得已要利用,请先看官方对付InnoDB 利用LOCK TABLES 的解释,以免造成系统常常发生去世锁。MySQL SELECT ... FOR UPDATE 的Row Lock 与Table Lock
前面紧张先容SELECT ... FOR UPDATE 的用法,不过锁定(Lock)的数据是判别就得要把稳一下了。由于InnoDB 预设是Row-Level Lock,以是只有「明确」的指定主键,MySQL 才会实行Row lock (只锁住被选取的数据) ,否则MySQL 将会实行Table Lock (将全体数据表单给锁住)。
MySQL大致可归纳为以下3种锁:
表级锁:开销小,加锁快;不会涌现去世锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。行级锁:开销大,加锁慢;会涌现去世锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。页面锁:开销和加锁韶光界于表锁和行锁之间;会涌现去世锁;锁定粒度界于表锁和行锁之间,并发度一样平常实例:
假设有个表单products ,里面有id 跟name 二个栏位,id 是主键。
例1: (明确指定主键,并且有此数据,row lock)
SELECT FROM products WHERE id='3' FOR UPDATE;
例2: (无主键,table lock)
SELECT FROM products WHERE name='Mouse' FOR UPDATE;
例3: (主键不明确,table lock)
SELECT FROM products WHERE id<>'3' FOR UPDATE;
例4: (主键不明确,table lock)
SELECT FROM products WHERE id LIKE '3' FOR UPDATE;
PS:Myisam 只支持表级锁,InnerDB支持行级锁 添加了(行级锁/表级锁)锁的数据不能被其它事务再锁定,也不被其它事务修正
(修正、删除) 。是表级锁时,不管是否查询到记录,都会锁定表。
乐不雅观所和悲观锁策略悲观锁:在读取数据时锁住那几行,其他对这几行的更新须要等到悲观锁结束时才能连续 。
乐不雅观锁:读取数据时不锁,更新时检讨是否数据已经被更新过,如果是则取消当前更新,一样平常在悲观锁的等待韶光过长而不能接管时我们才会选择乐不雅观锁。
总结今天主要分享mysql事务select for update及数据的同等性处理,然后先容了行锁和表锁及悲观锁、乐不雅观锁,后面再单独整理下mysql锁方面的内容和差异,感兴趣的朋友可以关注下!