侧边栏壁纸
博主头像
落叶人生博主等级

走进秋风,寻找秋天的落叶

  • 累计撰写 130562 篇文章
  • 累计创建 28 个标签
  • 累计收到 9 条评论
标签搜索

目 录CONTENT

文章目录

MySQL事务心得

2022-07-10 星期日 / 0 评论 / 0 点赞 / 42 阅读 / 8227 字

事务事务的概念就不介绍了, 它的目的是解决ACID问题.MySQL中的事务必须是InnoDB、Berkeley DB引擎,myisam不支持, 新出了一个memory, 貌似也是不支持的, 大家可以查

事务

事务的概念就不介绍了, 它的目的是解决ACID问题.

  • MySQL中的事务必须是InnoDB、Berkeley DB引擎,myisam不支持, 新出了一个memory, 貌似也是不支持的, 大家可以查查。
  • MySQL默认是autocommit=1,也就是说默认是立即提交,如果想开启事务,先设置autocommit=0,然后用START TRANSACTION、 COMMIT、 ROLLBACK来使用具体的事务。

你可能会有一个疑问: 查询会不会开事务?

根据上面两点可以得出, 如果你在INNODB事务引擎下, 并且autocommit=1 (默认值), 答案是会, 否则不会. 其他引擎不支持事务, 这个问题也不存在.

这时候你可能又有另外一个疑问: 我只是执行单个查询语句, 为什么要开事务?

  • 如果你一次执行单条查询语句,则没有必要启用事务支持,数据库默认支持SQL执行期间的读一致性;
  • 如果你一次执行多条查询语句,例如统计查询,报表查询,在这种场景下,多条查询SQL必须保证整体的读一致性,否则,在前条SQL查询之后,后条SQL查询之前,数据被其他用户改变,则该次整体的统计查询将会出现读数据不一致的状态,此时,应该启用事务支持。
.

简而言之, 因为你需要ACID中的CI: consistency && isolated

.

嵌套事务

Transactions cannot be nested. This is a consequence of the implicit commit performed for any current transaction when you issue a START TRANSACTION statement or one of its synonyms.

Mysql是不支持嵌套事务的,开启了一个事务的情况下,再开启一个事务,会隐式的提交上一个事务. 所以我们就要在系统架构层面来支持事务的嵌套, 常见的做法就是SAVEPOINT.

THINKPHP

PHP框架THINKPHP5的嵌套事务处理策略: 如果开启了supportSavepoint, 则利用SAVEPOINT来等价子事务, 否则啥也不干, MySQL驱动下默认开启

  • 开启事务
    /**     * 启动事务     * @access public     * @return void     * @throws /PDOException     * @throws /Exception     */    public function startTrans()    {        $this->initConnect(true);        if (!$this->linkID) {            return false;        }        ++$this->transTimes;        try {            // 第一个事务, 向mysql发起执行事务 begin            if (1 == $this->transTimes) {                $this->linkID->beginTransaction();            // 非第一个事务, 向mysql添加 SAVEPOINT            } elseif ($this->transTimes > 1 && $this->supportSavepoint()) {                $this->linkID->exec(                    $this->parseSavepoint('trans' . $this->transTimes)                );            }        } catch (/Exception $e) {            if ($this->isBreak($e)) {                --$this->transTimes;                return $this->close()->startTrans();            }            throw $e;        }    }
  • 提交
    /**     * 用于非自动提交状态下面的查询提交     * @access public     * @return void     * @throws PDOException     */    public function commit()    {        $this->initConnect(true);        // 只有第一个事务才真正发起提交        if (1 == $this->transTimes) {            $this->linkID->commit();        }        --$this->transTimes;    }
  • 回滚
/**     * 事务回滚     * @access public     * @return void     * @throws PDOException     */    public function rollback()    {        $this->initConnect(true);        // 只有第一个事务才真正发起回滚        if (1 == $this->transTimes) {            $this->linkID->rollBack();        // 否则回到保存点        } elseif ($this->transTimes > 1 && $this->supportSavepoint()) {            $this->linkID->exec(                $this->parseSavepointRollBack('trans' . $this->transTimes)            );        }        $this->transTimes = max(0, $this->transTimes - 1);    }

这产生了一个很重要的结论: 子事务的回滚不会导致事务回滚, 只有第一个事务的回滚才是真正的ROLLBACK

Spring

Java的spring提供更丰富的嵌套行为, 并且定义为事务传播行为,同时底层也是利用了SAVEPOINT, 默认值为 Propagation.REQUIRED。可以手动指定其他的事务传播行为,总共有七种, 如下:

  • Propagation.REQUIRED如果当前存在事务,则加入该事务,如果当前不存在事务,则创建一个新的事务。

  • Propagation.SUPPORTS如果当前存在事务,则加入该事务;如果当前不存在事务,则以非事务的方式继续运行。

  • Propagation.MANDATORY如果当前存在事务,则加入该事务;如果当前不存在事务,则抛出异常。

  • Propagation.REQUIRES_NEW重新创建一个新的事务,如果当前存在事务,延缓当前的事务。

  • Propagation.NOT_SUPPORTED以非事务的方式运行,如果当前存在事务,暂停当前的事务。

  • Propagation.NEVER以非事务的方式运行,如果当前存在事务,则抛出异常。

  • Propagation.NESTED如果没有,就新建一个事务;如果有,就在当前事务中嵌套其他事务。

.
.

广告 广告

评论区