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,应该怎么做?
谢谢~

《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
最佳答案
  1. 我的理解是应该在 Db::commit() 之后,数据才会变。 应该是其他事务在 本事务 commit 之后,才会感知数据的改变,这个是事务隔离性所表述的内容。

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

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

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

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

你理解错了。

学习事务与版本控制

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

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

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

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

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

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

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

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

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

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

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

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

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

4年前 评论

观察这个代码输出结果

    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);
4年前 评论