PGSQL 的事物描述貌似是这样的:
Balance: 100
并发事物 A : update table set balance = balance -1 where id = 1 (Balance:99)
并发事物 B : select balance from table where id = 1 (Balance: 100)
这是不是不用事物更好…… - -#
1
lsylsy2 2016-01-02 05:04:16 +08:00
没看懂……首先是事务
然后“事务”的意义是 并发事物 A : update table set balance = 101 where id = 1 select balance from table where id = 1 并发事物 B : update table set balance = 99 where id = 1 select balance from table where id = 1 两个 select 的结果都等于自己那个事务 set 的那个值,不会出现“执行了 A 的 update ”-“执行了 B 的 update ”-“执行了 A 的 select ,得出 balance=99 的结果”这样的问题(这个例子好像不太体现事务的特征但是应该没有错误……大半夜的想不起来了) 从这样的角度来讲,你的那个 B 读出 100 并没有问题,因为 A 和 B 是同时执行的,先执行完了 B (读出 100 )后执行 A (减一)没有任何问题。 |
2
gamexg 2016-01-02 08:28:57 +08:00 via Android
手机不方便
pg 文档,有各种事务级别详细的说明。包括优势和缺陷。 |
3
tabris17 2016-01-02 11:17:08 +08:00
这就是事务隔离啊。大大的好处。怎么得出不用事务更好的结论的
|
4
cevincheung OP @tabris17
假设用户同时在进行购物和提现的操作。分别是两个事物,购物的事物帐户余额扣除了 N 元,提现要要提 X 元,结果前面的事物还没提交,后端 select 到的账户余额是购物扣除前的余额? |
5
lsylsy2 2016-01-02 16:45:59 +08:00
@cevincheung 就是这样,然后提现成功,购物扣款失败,很符合逻辑啊
|
6
cevincheung OP @lsylsy2
假设。 事物 A 、 B 一个购买,一个提现。都是减钱的操作。 账户余额剩余 100 元。 A:消耗 1 元 B:消耗 100 元 A/B: BEGIN A:select balance from user where id = 1 B:同 A 此时两个事物获取的 balance 都是 100 。代码逻辑验证通过 A:update user set balance = 99 where id = 1 A:insert into orders 完成支付并订单入库 B:update user set balance = 0 where id = 1 A/B : commit 期间也没有什么异常,是不是? |
7
cevincheung OP @lsylsy2
更关键的是, PGSQL 的事物是这样的: A:begin A:update user set balance = 0 B:begin A:commit B:select balance from user where id = 1 这个时候获取的 balance 不是 0 ? |
8
lsylsy2 2016-01-02 20:22:00 +08:00
@cevincheung 我不太熟 PG ……用其它 SQL 比如 mysql 不会这样么?
首先是你第一个 at 我的内容:事务隔离如果设置成序列化或者可重复读的话,你的这两个 commit 都只会有一个成功,另一个会失败。 第二个的话,会是两种情况: 1 、读 0 , B commit 成功; 2 、读不是 0 ( Acommit 之前的值),然后 Bcommit 失败。 |
9
cevincheung OP @lsylsy2
每次 begin 会分配一个事物 ID ,每个事物中的数据都是隔离的。 从该 SELECT 查询开始执行时,在此查询执行期间,任何其它并发事物针对该查询结果集的数据操作都将不会被本次查询读到,即本次查询获取的数据版本是与查询开始执行时的数据版本相一致。 可串行: 从该 SELECT 查询所在事物开始时,在此查询执行期间,任何其它并发事物针对该查询结果集的数据操作都将不会被本次查询读到,即本次查询获取的数据版本是与查询所在事物开始时的数据版本相一致。 |
10
ch3nz 2016-01-02 22:30:02 +08:00
A,B 如果是两个的事务,那么是不会出问题的,因为锁表了,只有一个事务在跑.
A,B 如果是两个加减钱的操作但是你放在一个事务里面并且不多加验证,跟拿刀捅自己并且问为什么流血了一样. BEGIN update user set balance = balance -1 where id = 1 insert into orders SAVEPOINT save_order update user set balance = balance - 100 where id = 1 //检查发现 balance 负数了 ROLLBACK to save_order COMMIT |
11
cevincheung OP @ch3nz
可是 pgsql 的事物好像是 如果开启了事物 1 , select 一条数据,事物 2 中如果 update ,事物 1 中再 select ,获取到的仍旧是以前(或当前事物的最新版本)的数据。 |
12
gamexg 2016-01-02 23:40:48 +08:00 via Android
这就是正确的行为啊
如果不这样事务 2 回滚了怎么办? 看 pg 文档吧, 4 中事务级别很详细的介绍。 |
13
gamexg 2016-01-02 23:47:23 +08:00 via Android
|
14
tabris17 2016-01-04 09:55:34 +08:00
@cevincheung 当然了,有什么问题,事务没提交就是没操作成功
|