eloquent的事务

以前没有碰到这种需求,就没在意。在eloquent的事务中,在commit之前,对对象进行save操作,再进行查询,查到的数据已经是更新之后的。代码如下

public function index(){
        DB::beginTransaction();
        $id = 2;
        $user = User::find($id);
        $user->name = 'name_after';
        dump(User::find($id)->name);  //① 此时name是name_before
        $user->save();
        dump(User::find($id)->name);  //② 此时name已经是name_after
        Db::commit();
        dump(User::find($id)->name);  //③ 我的理解是应该此时才会变更
    }

我的理解是应该在Db::commit()之后,数据才会变。
实际上如果去掉commit操作,数据不会写库,但在位置②的时候,查出来的数据也已经是name_after了。
PS:数据库是postgres,隔离等级是read committed,没有问题。
我想要在位置②查出来的数据还是name_before,应该怎么做?
谢谢~

《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
最佳答案
  1. 我的理解是应该在 Db::commit() 之后,数据才会变。 应该是其他事务在 本事务commit 之后,才会感知数据的改变,这个是事务隔离性所表述的内容。

  2. 实际上如果去掉 commit 操作,数据不会写库 框架在处理事务时,如果发现了事务的开始,但没有发现 commit ,会默认执行 rollback

PS: 数据库是 postgres,隔离等级是 read committed,没有问题。隔离级别是隔离的多个事务,不是隔离的同一个事务。。

第二点更正一下,只有通过闭包的方式执行事务,才会自动处理提交与回滚。如果手动开启事务,漏掉了 commit, 回滚动作是 mysql 自己来做的。

3年前 评论
windpuller (楼主) 3年前
arvin-hermit 3年前
讨论数量: 7

你理解错了。

学习事务与版本控制

3年前 评论
windpuller (楼主) 3年前
  1. 我的理解是应该在 Db::commit() 之后,数据才会变。 应该是其他事务在 本事务commit 之后,才会感知数据的改变,这个是事务隔离性所表述的内容。

  2. 实际上如果去掉 commit 操作,数据不会写库 框架在处理事务时,如果发现了事务的开始,但没有发现 commit ,会默认执行 rollback

PS: 数据库是 postgres,隔离等级是 read committed,没有问题。隔离级别是隔离的多个事务,不是隔离的同一个事务。。

第二点更正一下,只有通过闭包的方式执行事务,才会自动处理提交与回滚。如果手动开启事务,漏掉了 commit, 回滚动作是 mysql 自己来做的。

3年前 评论
windpuller (楼主) 3年前
arvin-hermit 3年前

这个和事务没有关系,是你已经对模型属性赋值了,在获取模型的属性 肯定是你赋值后的值,你知道是不是已经写库了 ,在事务在查询一次id=2的记录 对比一下值就知道了!

3年前 评论
windpuller (楼主) 3年前

搜索 mysql mvvc 了解一下多版本并发控制,简单说就是你理解的位置②要取出 name_before 那必须得是在这个事务之外的其他事务(例如另一条连接),才会读到历史版本,在当前事务的视图里,读到的自然是 name_after。

3年前 评论
windpuller (楼主) 3年前

对事务理解错误了。在同一事务中,先 update , 后 select 获取到的是更新后的数据。但如果是不同事务之间,就涉及到数据库 隔离级别 的定义了。

不理解是什么需求一定要求在位置 2 处还希望从数据库取到之前的数据。感觉是可以有其它实现方法的

3年前 评论
windpuller (楼主) 3年前
ruke

同一个事务里边,同一次会话,你先更新再读取,读取到的就是当前会话中的值(包括你事务未提交的更改)

3年前 评论

观察这个代码输出结果

    DB::beginTransaction();
    $id = 1;
    $user = User::find($id);
    $user->name = 'name_after';
    dump(User::find($id)->name);  //① 此时name是name_before

    $user->save();
    dump(User::find($id)->name);  //② 此时name已经是name_after
    sleep(100);
    DB::commit();
    dump(User::find($id)->name);
3年前 评论

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