mysql 悲观锁 机制 请教

2022-11-28 14:55:42 +08:00
 hhhhhh123

问题 1.:悲观锁 运行机制 目前无法理解的是 假设 pk_money= 1 , 我每次运行都会+ 1 但是我没提交啊
不知道为什么他会每次 + 1 ,
不知道是我 sql 语法问题 还是啥 ?
难道每次运行的时候 会把没有提及的 sql 自动提交? 但是我已经关闭了自动提交 。

问题 2: 我想把 set pk_money=pk_money+1 这个 pk_money 等于上面的查询结果 然后在+ 1 这个应该怎么写啊? 同时是悲观锁。 怎么把 下面的 select 和 update 合并。

问题 3: 我不提交的话,我重新开个窗口 单独去运行

update user_basic_info set pk_money=pk_money+1 where uid=123456803;

是会被阻塞到超时。 说明这个悲观锁是起作用了。 但是不知道怎么解释第一个问题

set autocommit=0;
start transaction;
select `pk_money` from user_basic_info where uid=123456803 for update ;
update user_basic_info set pk_money=pk_money+1 where uid=123456803;
--  COMMIT;

不会放图片。。。。

set autocommit=0
> OK
> Time: 0.074s


start transaction
> OK
> Time: 0.077s


select `pk_money` from user_basic_info where uid=123456803 for update
> Affected rows: 0
> Time: 0.071s


update user_basic_info set pk_money=pk_money+1 where uid=123456803
> Affected rows: 1
> Time: 0.074s


--  COMMIT;
> OK
> Time: 0.071s

2178 次点击
所在节点    程序员
44 条回复
rqxiao
2022-11-28 15:02:44 +08:00
mysql update 语句不是自带行锁吗(如果 where 的条件有索引的话)
hhhhhh123
2022-11-28 15:04:08 +08:00
@rqxiao 主键就是 uid
hhhhhh123
2022-11-28 15:05:09 +08:00
@rqxiao 自带这个问题我不是很清楚,sql 目前只会写 curd 。目前在接触更高级的
rqxiao
2022-11-28 15:05:50 +08:00
set autocommit=0;
start transaction;
update user_basic_info set pk_money=pk_money+1 where uid=123456803;
COMMIT;

这样和你加了一句 for update 是一样的把
hhhhhh123
2022-11-28 15:08:20 +08:00
@rqxiao 结果是一样的, 但是把 commit 注释 , 在窗口一直运行重复的代码, 结果会自动+=1 。 这个问题是为什么?
hhhhhh123
2022-11-28 15:10:09 +08:00
@rqxiao 顺便请教一下。 为啥网上几乎所有的教程都是要写一个 select 语法 + for update 。
rqxiao
2022-11-28 15:15:16 +08:00
@hhhhhh123 只是在当前事物看到是加了 1 吧(虽然当前事物还没提交)。新开个会话,查看的话还是原来的值。
hhhhhh123
2022-11-28 15:16:35 +08:00
百度了一下 个人感觉很像是 脏读。
事务并发调度的问题
1. 脏读( dirty read ):A 事务读取 B 事务尚未提交的更改数据,并在这个数据基础上操作。如果 B 事务回滚,那么 A 事务读到的数据根本不是合法的,称为脏读。在 oracle 中,由于有 version 控制,不会出现脏读。
2. 不可重复读( unrepeatable read ):A 事务读取了 B 事务已经提交的更改(或删除)数据。比如 A 事务第一次读取数据,然后 B 事务更改该数据并提交,A 事务再次读取数据,两次读取的数据不一样。
3. 幻读( phantom read ):A 事务读取了 B 事务已经提交的新增数据。注意和不可重复读的区别,这里是新增,不可重复读是更改(或删除)。这两种情况对策是不一样的,对于不可重复读,只需要采取行级锁防止该记录数据被更改或删除,然而对于幻读必须加表级锁,防止在这个表中新增一条数据。
4.第一类丢失更新:A 事务撤销时,把已提交的 B 事务的数据覆盖掉。
5.第二类丢失更新:A 事务提交时,把已提交的 B 事务的数据覆盖掉。
xhinliang
2022-11-28 15:19:39 +08:00
问题 1.:悲观锁 运行机制 目前无法理解的是 假设 pk_money= 1 , 我每次运行都会+ 1 但是我没提交啊
不知道为什么他会每次 + 1 ,
----
你虽然没提交,但是在你的 transaction 内已经可见了,没提交只是别的 transaction 内不可见而已。
不知道这样能理解么?
hhhhhh123
2022-11-28 15:19:56 +08:00
@rqxiao 新会话就是 + 1
hhhhhh123
2022-11-28 15:21:46 +08:00
@xhinliang 数据在数据库中确确实实的变化的 += 1
rqxiao
2022-11-28 15:24:13 +08:00
@hhhhhh123 那应该就是你发的 mysql 隔离级别为 read uncommitted 读未提交 (脏读)
xhinliang
2022-11-28 15:24:44 +08:00
为啥网上几乎所有的教程都是要写一个 select 语法 + for update 。
-----
这个不是必须的。在业务上先「写一个 select 语法 + for update 」一般是先锁定一下这些行的数据,同时可以读到这些数据当前值,你上来就 update 也没问题的。
xhinliang
2022-11-28 15:25:43 +08:00
那你看看当前的隔离级别呢?不会是 read uncommitted 吧?
hhhhhh123
2022-11-28 15:26:41 +08:00
@rqxiao 还有个疑问, 就算是脏读 也不应该更新数据到数据库吧? 更新到数据库那不就持久化了?
xhinliang
2022-11-28 15:28:42 +08:00
还有个疑问, 就算是脏读 也不应该更新数据到数据库吧? 更新到数据库那不就持久化了?
------------
什么叫更新到数据库,所有的写入都是更新到数据库的呀,只是别的 session 能不能看到而已,这不就是隔离级别的基本概念么?
hhhhhh123
2022-11-28 15:29:28 +08:00
@xhinliang ``` show variables like '%tx_isolation%';``` 返回结果是空 啥也没有 ,这种是什么
rqxiao
2022-11-28 15:29:52 +08:00
@hhhhhh123 一般有事物功能的话没提交确实不会更新到数据库。
rqxiao
2022-11-28 15:31:29 +08:00
你是 MyISAM 引擎吗,MyISAM 引擎不支持数事物,不过还没用过 MyISAM
hhhhhh123
2022-11-28 15:32:16 +08:00
@rqxiao
@xhinliang
```
select @@transaction_isolation;
select @@global.transaction_isolation;
```
  结果是 REPEATABLE-READ

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/898510

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX