mysql嵌套事务

操作环境:mysql5.6

CREATE TABLE `ydy_test` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增ID',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

select * from information_schema.innodb_trx\G;

start transaction;
Insert into ydy_test values(1); --另一个会话中没有记录--
start transaction;--另一个会话中记录1--
Insert into ydy_test values(2);--另一个会话中记录1--
Commit;--另一个会话中记录1、2--
Insert into ydy_test values(3);--另一个会话中记录1、2、3--
Rollback;--另一个会话中记录1、2、3--

truncate ydy_test;
start transaction;
Insert into ydy_test values(1); --另一个会话中没有记录--
start transaction;--另一个会话中记录1--
Insert into ydy_test values(2);--另一个会话中记录1--
rollback;--另一个会话中记录1--
Insert into ydy_test values(3);--另一个会话中记录1、3--
commit;--另一个会话中记录1、3--

 

 

truncate ydy_test;

set autocommit = 0;
start transaction;
Insert into ydy_test values(1);--另一个会话中没有记录--
start transaction;--另一个会话中记录1--
Insert into ydy_test values(2);--另一个会话中记录1--
Commit;--另一个会话中记录1、2--
Insert into ydy_test values(3);--另一个会话中记录1、2--
Rollback;--另一个会话中记录1、2--

 

truncate ydy_test;

set autocommit = 0;
start transaction;
Insert into ydy_test values(1); --另一个会话中没有记录--
start transaction;--另一个会话中记录1--
Insert into ydy_test values(2);--另一个会话中记录1--
rollback;--另一个会话中记录1--
Insert into ydy_test values(3);--另一个会话中记录1--
commit;--另一个会话中记录1、3--

 

truncate ydy_test;

set autocommit = 0;
start transaction;
Insert into ydy_test values(1); --另一个会话中没有记录--
start transaction;--另一个会话中记录1--
Insert into ydy_test values(2);--另一个会话中记录1--
rollback;--另一个会话中记录1--
Insert into ydy_test values(3);--另一个会话中记录1--
rollback;--另一个会话中记录1--

 

详解:

1、start transaction;
2、Insert into ydy_test values(1); --另一个会话中没有记录--
3、start transaction;--另一个会话中记录1--
4、Insert into ydy_test values(2);--另一个会话中记录1--
5、Commit;--另一个会话中记录1、2--
6、Insert into ydy_test values(3);--另一个会话中记录1、2、3--
7、Rollback;--另一个会话中记录1、2、3--

在2执行完成后,事务建立;

在3执行后,自动把外层事务提交

在4执行后,重新建立新事务

在5执行后,新事务被提交

6已经执行在没有事务的基础上了。如果会话中@@autocommit=1,那么6就直接提交了,和7rollback没什么关系了。

结论:1、在一个会话中,mysql是无法启动两个事务的,更不会存在父事务和子事务(个人理解,希望大神指正);

2、start transaction并没有真正的开启事务,真正开启事务是在DML语句;

3、DDL语句会隐式提交事务,mysql8已有部分DDL支持原子性。

 

 

可以用savepoint和rollback to来实现[假]嵌套事务

 

 

 

thinkphp中就是采用savepoint和rollback to

/thinkphp/library/think/db/Connection.php

/**

     * 启动事务
     * @access public
     * @return bool|mixed
     * @throws \Exception
     */
    public function startTrans()
    {
        $this->initConnect(true);
        if (!$this->linkID) {
            return false;
        }

        ++$this->transTimes;
        try {
            if (1 == $this->transTimes) {
                $this->linkID->beginTransaction();
            } 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;
        } catch (\Error $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);
    }

 

thinkphp5.0实验

Unit.php

    public function test() {
        // 启动事务
        $this->model->startTrans();
        try{
            $res = $this->model->modifyById(61, ['cn_name'=>'aaa']);
            $trans = $this->model->query("select * from information_schema.innodb_trx");
            write_log(json_encode($trans));
            $res = $this->userModel->test();
            $res = $this->model->modifyById(62, ['cn_name'=>'bbb']);
            $trans = $this->model->query("select * from information_schema.innodb_trx");
            write_log(json_encode($trans));
//            throw new Exception("1");
            
            // 提交事务
            $this->model->commit();    
        } catch (\Exception $e) {
            // 回滚事务
            $this->model->rollback();
        }
            
    }

 

User.php

public function test() {
        // 启动事务
        $this->startTrans();
        try{
            $res = $this->modifyById(362, ['name'=>'ccc']);
            $trans = $this->query("select * from information_schema.innodb_trx");
            write_log(json_encode($trans));
            throw new Exception("ddd");
//            if($res === false) {
//                throw new \Exception("inner");
//            }
            // 提交事务
            $this->commit();    
        } catch (\Exception $e) {
            // 回滚事务
            $this->rollback();
        }
    }

日志结果

2021-04-09 16:33:44[{"trx_id":"21D3DE","trx_state":"RUNNING","trx_started":"2021-04-09 16:33:44","trx_requested_lock_id":null,"trx_wait_started":null,"trx_weight":3,"trx_mysql_thread_id":87304,"trx_query":"select * from information_schema.innodb_trx","trx_operation_state":null,"trx_tables_in_use":0,"trx_tables_locked":0,"trx_lock_structs":2,"trx_lock_memory_bytes":376,"trx_rows_locked":1,"trx_rows_modified":1,"trx_concurrency_tickets":0,"trx_isolation_level":"REPEATABLE READ","trx_unique_checks":1,"trx_foreign_key_checks":1,"trx_last_foreign_key_error":null,"trx_adaptive_hash_latched":0,"trx_adaptive_hash_timeout":10000}]


2021-04-09 16:33:44[{"trx_id":"21D3DE","trx_state":"RUNNING","trx_started":"2021-04-09 16:33:44","trx_requested_lock_id":null,"trx_wait_started":null,"trx_weight":3,"trx_mysql_thread_id":87304,"trx_query":"select * from information_schema.innodb_trx","trx_operation_state":null,"trx_tables_in_use":0,"trx_tables_locked":0,"trx_lock_structs":2,"trx_lock_memory_bytes":376,"trx_rows_locked":1,"trx_rows_modified":1,"trx_concurrency_tickets":0,"trx_isolation_level":"REPEATABLE READ","trx_unique_checks":1,"trx_foreign_key_checks":1,"trx_last_foreign_key_error":null,"trx_adaptive_hash_latched":0,"trx_adaptive_hash_timeout":10000}]


2021-04-09 16:33:44[{"trx_id":"21D3DE","trx_state":"RUNNING","trx_started":"2021-04-09 16:33:44","trx_requested_lock_id":null,"trx_wait_started":null,"trx_weight":3,"trx_mysql_thread_id":87304,"trx_query":"select * from information_schema.innodb_trx","trx_operation_state":null,"trx_tables_in_use":0,"trx_tables_locked":0,"trx_lock_structs":2,"trx_lock_memory_bytes":376,"trx_rows_locked":1,"trx_rows_modified":1,"trx_concurrency_tickets":0,"trx_isolation_level":"REPEATABLE READ","trx_unique_checks":1,"trx_foreign_key_checks":1,"trx_last_foreign_key_error":null,"trx_adaptive_hash_latched":0,"trx_adaptive_hash_timeout":10000}]

结论,代码中嵌套start transaction,但是在一个进程中框架始终只有一个事务。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值