mysql事务select for update及数据的一致性处理讲解

MySQL中的事务,默认是自动提交的,即autocommit = 1;

但是这样的话,在某些情形中就会出现问题:比如:

如果你想一次性插入了1000条数据,mysql会commit1000次的,

如果我们把autocommit关闭掉[autocommit = 0],通过程序来控制,只要一次commit就可以了,这样也才能更好的体现事务的特点!

对于需要操作数值,比如金额,个数等等!

记住一个原则:一锁二判三更新

在MySQL的InnoDB中,预设的Tansaction isolation level 为REPEATABLE READ(可重读)

在SELECT 的读取锁定主要分为两种方式:

  • SELECT ... LOCK IN SHARE MODE 
  • SELECT ... FOR UPDATE

这两种方式在事务(Transaction) 进行当中SELECT 到同一个数据表时,都必须等待其它事务数据被提交(Commit)后才会执行。

而主要的不同在于LOCK IN SHARE MODE 在有一方事务要Update 同一个表单时很容易造成死锁。

简单的说,如果SELECT 后面若要UPDATE 同一个表单,最好使用SELECT ... UPDATE。

举个例子:

假设商品表单products 内有一个存放商品数量的quantity ,在订单成立之前必须先确定quantity 商品数量是否足够(quantity>0) ,然后才把数量更新为1。代码如下:

SELECT quantity FROM products WHERE id=3; UPDATE products SET quantity = 1 WHERE id=3;

为什么不安全呢?

少量的状况下或许不会有问题,但是大量的数据存取「铁定」会出问题。如果我们需要在quantity>0 的情况下才能扣库存,假设程序在第一行SELECT 读到的quantity 是2 ,看起来数字没有错,但 是当MySQL 正准备要UPDATE 的时候,可能已经有人把库存扣成0 了,但是程序却浑然不知,将错就错的UPDATE 下去了。因此必须透过的事务机制来确保读取及提交的数据都是正确的。

于是我们在MySQL 就可以这样测试,代码如下:

SET AUTOCOMMIT=0; BEGIN WORK; SELECT quantity FROM products WHERE id=3 FOR UPDATE;

此时products 数据中id=3 的数据被锁住(注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 (将整个数据表单给锁住)。

举个例子:

假设有个表单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;

乐观所和悲观锁策略

悲观锁:在读取数据时锁住那几行,其他对这几行的更新需要等到悲观锁结束时才能继续 。

乐观所:读取数据时不锁,更新时检查是否数据已经被更新过,如果是则取消当前更新,一般在悲观锁的等待时间过长而不能接受时我们才会选择乐观锁。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。如果你想了解更多相关内容请查看下面相关链接

(0)

相关推荐

  • PHP后台备份MySQL数据库的源码实例

    PHP 备份 mysql 数据库的源代码,在完善的 PHP+Mysql 项目中,在后台都会有备份 Mysql 数据库的功能,有了这个功能,对于一些不便自己写shell脚本备份的VPS来说,就不用使用 FTP 或者使用 mysql 的管理工具进行 mysql 数据库备份下载,非常方便. 下面是一个php数据库备份的源代码,大家也可以根据自己的需求进行修改. <?php // 备份数据库 $host = "localhost"; $user = "root"; /

  • MySQL Limit性能优化及分页数据性能优化详解

    MySQL Limit可以分段查询数据库数据,主要应用在分页上.虽然现在写的网站数据都是千条级别,一些小的的优化起的作用不大,但是开发就要做到极致,追求完美性能.下面记录一些limit性能优化方法. Limit语法: SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset LIMIT子句可以被用于强制 SELECT 语句返回指定的记录数.LIMIT接受一个或两个数字参数.参数必须是一个整数常量. 如果给定两个参数,第一个参数指定

  • MySQL开启慢查询日志功能的方法

    mysql慢查询日志对于跟踪有问题的查询非常有用,可以分析出当前程序里是否有很耗费资源的sql语句,这是一个有用的日志.它对于性能的影响不大(假设所有查询都很快),并且强调了那些最需要注意的查询(丢失了索引或索引没有得到最佳应用),那如何打开mysql的慢查询日志记录呢? 开启慢查询日志,可以让MySQL记录下查询超过指定时间的语句,通过定位分析性能的瓶颈,才能更好的优化数据库系统的性能. (1)配置开启 Linux: 在mysql配置文件 my.cnf 中增加如下语句: log-slow-qu

  • MySQL索引类型Normal、Unique和Full Text的讲解

    MySQL的索引类型有普通索引(normal),唯一索引(unique)和全文索引(full text),合理使用索引可大大提升数据库的查询效率,下面是三种类型的索引的介绍 normal:这是最基本的索引,它没有任何限制,MyIASM中默认的BTREE类型的索引,是我们大多数情况下用到的索引. unique:表示唯一的,不允许重复的索引,如果该字段信息保证不会重复.例如身份证号用作索引时,可设置为unique. full text : 表示全文搜索的索引,仅可用于 MyISAM 表. FULLT

  • MySQL分库分表总结讲解

    项目开发中,我们的数据库数据越来越大,随之而来的是单个表中数据太多.以至于查询变慢,而且由于表的锁机制导致应用操作也受到严重影响,出现了数据库性能瓶颈. 当出现这种情况时,我们可以考虑分库分表,即将单个数据库或表进行拆分,拆分成多个库和多个数据表,然后用户访问的时候,根据一定的算法与逻辑,让用户访问不同的库.不同的表,这样数据分散到多个数据表中,减少了单个数据表的访问压力.提升了数据库访问性能. 下面是对项目中分库分表的一些总结: 单库单表 单库单表是最常见的数据库设计,例如,有一张用户(use

  • MySQL数据库存储过程和事务的区别讲解

    事务是保证多个SQL语句的原子型的,也就是要么一起完成,要么一起不完成 存储过程是把一批SQL语句预编译后放在服务器上,然后可以远程调用 存储过程: 一组为了完成特定功能的SQL语句集(或者自定义数据库操作命令集), 根据传入的参数(也可以没有), 通过简单的调用, 完成比单个SQL语句更复杂的功能, 存储在数据库服务器端,只需要编译过一次之后再次使用都不需要再进行编译:主要对存储的过程进行控制. 优点: 1.执行速度快.尤其对于较为复杂的逻辑,减少了网络流量之间的消耗,另外比较重要的一点是存储

  • 使用shell脚本每天对MySQL多个数据库自动备份的讲解

    Linux下使用shell脚本,结合crontab,定时备份MySQL下多个数据库,每次备份的数据存放于以日期命名的文件夹中,同时删除超过设定的备份保留时间的数据. 以下例子设定备份保留时间为1个月(-1month),可根据需求修改 #! /bin/bash # MySQL用户 user="root" # MySQL密码 userPWD="123456" # 需要定时备份的数据表列表 dbNames=(db_test1 db_test2 db_test3 db_te

  • PHP5中使用mysqli的prepare操作数据库的介绍

    php5中有了mysqli对prepare的支持,对于大访问量的网站是很有好处的,极大地降低了系统开销,而且保证了创建查询的稳定性和安全性. PHP5.0后我们可以使用mysqli,mysqli对prepare的支持对于大访问量的网站是很有好处的,特别是事务的支持,在大查询量的时候将极大地降低了系统开销,而且保证了创建查询的稳定性和安全性,能有效地防止SQL注入攻击. prepare准备语句分为绑定参数和绑定结果两种.接下来具体介绍. 1.绑定参数 看下面php代码: <?php //创建连接

  • Mysql数据库的QPS和TPS的意义和计算方法

    在做db基准测试的时候,qps,tps 是衡量数据库性能的关键指标.本文比较了网上的两种计算方式.先来了解一下相关概念. 概念介绍: QPS:Queries Per Second         查询量/秒,是一台服务器每秒能够相应的查询次数,是对一个特定的查询服务器在规定时间内所处理查询量多少的衡量标准. TPS :  Transactions Per Second   是事务数/秒,是一台数据库服务器在单位时间内处理的事务的个数. 在对数据库的性能监控上经常会提到QPS和TPS这两个名词,下

  • mysql数据库太大了如何备份与还原

    命令:mysqlhotcopy 这个命令会在拷贝文件之前会把表锁住,并把数据同步到数据文件中,以避免拷贝到不完整的数据文件,是最安全快捷的备份方法. 命令的使用方法是: mysqlhotcopy -u root -p<rootpass> db1 db2 - dbn <output_dir> 如果需要备份全部数据库,可以加上–regexp=".*"参数. Mysqlhotcopy命令可自动完成数据锁定工作,备份时不用关闭服务器. 它还可以刷新日志,使备份文件和日志

随机推荐