MySQL事務心得

事務

事務的概念就不介紹了, 它的目的是解決ACID問題.html

  • MySQL中的事務必須是InnoDB、Berkeley DB引擎,myisam不支持, 新出了一個memory, 貌似也是不支持的, 你們能夠查查。
  • MySQL默認是autocommit=1,也就是說默認是當即提交,若是想開啓事務,先設置autocommit=0,而後用START TRANSACTION、 COMMIT、 ROLLBACK來使用具體的事務。

你可能會有一個疑問: 查詢會不會開事務?

根據上面兩點能夠得出, 若是你在INNODB事務引擎下, 而且autocommit=1 (默認值), 答案是會, 不然不會. 其餘引擎不支持事務, 這個問題也不存在.mysql

這時候你可能又有另一個疑問: 我只是執行單個查詢語句, 爲何要開事務?

  • 若是你一次執行單條查詢語句,則沒有必要啓用事務支持,數據庫默認支持SQL執行期間的讀一致性;
  • 若是你一次執行多條查詢語句,例如統計查詢,報表查詢,在這種場景下,多條查詢SQL必須保證總體的讀一致性,不然,在前條SQL查詢以後,後條SQL查詢以前,數據被其餘用戶改變,則該次總體的統計查詢將會出現讀數據不一致的狀態,此時,應該啓用事務支持。

簡而言之, 由於你須要ACID中的CI: consistency && isolatedspring

嵌套事務

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. sql

Mysql是不支持嵌套事務的,開啓了一個事務的狀況下,再開啓一個事務,會隱式的提交上一個事務. 因此咱們就要在系統架構層面來支持事務的嵌套, 常見的作法就是SAVEPOINT.數據庫

THINKPHP

PHP框架THINKPHP5的嵌套事務處理策略: 若是開啓了supportSavepoint, 則利用SAVEPOINT來等價子事務, 不然啥也不幹, MySQL驅動下默認開啓bash

  • 開啓事務
/**
     * 啓動事務
     * @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 若是當前存在事務,則加入該事務,若是當前不存在事務,則建立一個新的事務。ui

  • Propagation.SUPPORTS 若是當前存在事務,則加入該事務;若是當前不存在事務,則以非事務的方式繼續運行。this

  • Propagation.MANDATORY 若是當前存在事務,則加入該事務;若是當前不存在事務,則拋出異常。

  • Propagation.REQUIRES_NEW 從新建立一個新的事務,若是當前存在事務,延緩當前的事務。

  • Propagation.NOT_SUPPORTED 以非事務的方式運行,若是當前存在事務,暫停當前的事務。

  • Propagation.NEVER 以非事務的方式運行,若是當前存在事務,則拋出異常。

  • Propagation.NESTED 若是沒有,就新建一個事務;若是有,就在當前事務中嵌套其餘事務。

相關文章
相關標籤/搜索