mysql 排他锁在Laravel 中的使用

mysql 排他锁在Laravel 中的使用

需求

当数据库的某条记录被多个 php 或 java 进程同时修改时,希望数据修改正确。

实现,

通过加锁与解锁来实现,也叫 mysql 行锁,排他锁,悲观锁。

表创建

```
这里有用户表

CREATE TABLE users (
  id int(11) NOT NULL AUTO_INCREMENT,
  user_name varchar(255) NOT NULL DEFAULT '' comment '用户名称',
  level tinyint not null default 0 comment '用户类别,1注册用户,2铜牌用户,3高端用户',
  email varchar(255) NOT NULL DEFAULT '' comment 'email',
  created_at timestamp null default current_timestamp,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB ;

insert into users(id,user_name)values (1,'管理员');
insert into users(id,user_name)values (2,'用户2');
insert into users(id,user_name)values (3,'用户3');
```

加锁的实现(必须同时满足)

1、表引擎必须innodb。
2、必须先开启事务。
3、必须使用 select XXX1 from XXX2 where XXX3 for update;
4、其中的XXX3 必须有索引,建议使用主键最方便。尽量不要使用范围条件,可以使用id=1,或者id in (1,3)这样精确的定位记录的语句。
5、经实际测试,有普通索引的字段也可以。例如 select * from users where type=1 for update,给这个type加索引的话也行。

加锁的后果

1、任何会话或连接,当查询到同一行记录时,如果使用 select XXX1 from XXX2 where XXX3 则没有影响,可以正常查询,无论是否在事务中。
2、任何会话或连接,当查询到同一行记录时,如果使用 select XXX1 from XXX2 where XXX3 for update ,则被强行阻塞等待,无论是否在事务中。
3、任何会话或连接,当修改同一行记录时,如果使用 update XXX2 set XXX1 where XXX3 ,则被强行阻塞等待,无论是否在事务中。
4、任何会话或连接,当修改包括那行的更多记录时,如果使用 update XXX2 set XXX1 where XXX4 ,这个XXX4包含了XXX3的记录和其他记录, 则整个 update 依然被强行阻塞等待,无论是否在事务中。

解锁的实现(满足任意一个均可)

1、在刚才加锁的 mysql 会话中,commit 事务
2、在刚才加锁的 mysql 会话中,rollback 事务
3、刚才加锁 的 mysql 连接断开。实际是 mysql 服务会自己 rollback 事务。

laravel 的实现

```
DB::beginTransaction(); // 开启事务
$user = User::lockForUpdate()->find(1);
// 这里对用户做一些读写操作。
DB::commit();
// 或 DB::rollBack();
```

总结

1、如果修改例如用户账户余额之类的敏感数据,应该总是在使用update 这个语句之前,最先开事务,再使用select …. where id = 1 for update,然后再使用update 。。。where id =1 ,再提交事务。
2、这种总是先 select … for update 的方式,实际是让所有sql修改语句串行执行,而不是并发执行,数据修改时当然肯定不会错,可是也阻塞了 php 或 java 语句的执行, 并发访问高速度也慢。当然悲观锁本身就是这样的。
3、如果想保证数据修改正确,除了这种方法,还有一种方法也可以实现,就是不在数据库查询时加锁,而是让所有的修改sql的程序语言本身不能并发执行,也可以达到效果,比如 java 的 synchronized 关键字。
4、如果想保证数据修改正确,还有一种方法,使用乐观锁的实现。
5、如果想保证数据修改正确,还有一种方法,数据放redis,用redis锁。

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!