1. 문제의 근원
MySQL 공식 문서에는 중첩 트랜잭션이 지원되지 않는다는 명확한 설명이 있습니다.
1. 트랜잭션은 중첩될 수 없습니다. 이는 START TRANSACTION 문이나 동의어 중 하나를 실행할 때 현재 트랜잭션에 대해 수행된 암시적 커밋의 결과입니다.
그러나 복잡한 시스템을 개발할 때 의도치 않게 트랜잭션을 트랜잭션에 포함시키는 것은 불가피합니다. 예를 들어 함수 A가 함수 B를 호출하고, 함수 A가 트랜잭션을 사용하고, 함수 B가 함수 B에서 호출됩니다. 역시 트랜잭션이므로 트랜잭션 중첩이 발생합니다. 현재로서는 A씨의 일은 사실 별 의미가 없다. 위 문서에 언급되어 있으며, 간단히 번역하면 다음과 같습니다.
1. START TRANSACTION 명령을 실행하면 커밋 작업이 암시적으로 수행됩니다. 따라서 시스템 아키텍처 수준에서 트랜잭션 중첩을 지원해야 합니다.
다행히도 일부 성숙한 ORM 프레임워크에서는 교리나 라라벨과 같은 중첩을 지원합니다. 다음으로, 이 두 프레임워크가 어떻게 구현되는지 살펴보겠습니다. 참고로, 이 두 프레임워크의 함수 및 변수 이름 지정은 비교적 직관적입니다. 비록 매우 길어 보이지만 이름 지정을 통해 함수나 변수의 의미를 직접적으로 알 수 있으므로 첫눈에 그렇게 큰 혼란을 겪지는 마세요. 너무 무서웠어요 :)
2. 교리의 해결책
먼저 교리에 따라 거래를 생성하는 코드를 살펴보겠습니다(관련 없는 코드 제거).
[php] 일반 사본 보기
-
/**
-
* 저자 http://www.lai18.com
-
* 날짜 2015-04-19
-
* 버전 1
-
**/
-
공개 함수 startTransaction()
-
- {
-
- ++$this->_transactionNestingLevel
-
- if ($this->_transactionNestingLevel == 1) {
-
- $this->_conn->beginTransaction()
-
- } else if ($this->_nestTransactionsWithSavepoints) {
-
- $this->createSavepoint($this->_getNestedTransactionSavePointName())
-
- }
-
- }
이 함수의 첫 번째 줄은 _transactionNestingLevel을 사용하여 현재 중첩 수준을 식별합니다. 1인 경우, 즉 아직 중첩이 없는 경우 기본 방법을 사용하여 START TRANSACTION을 실행하면 괜찮습니다. 즉, 중첩이 있을 때 저장점을 생성하는 데 도움이 됩니다. 이 저장점은 트랜잭션 기록 지점으로 이해될 수 있습니다. 롤백이 필요한 경우 이 지점으로만 롤백할 수 있습니다. 그런 다음 롤백 기능을 살펴보세요.
[php] 일반 사본 보기
- 1. /**
- * 저자 http://www.lai18.com
- * 날짜 2015-04-19
- * 버전 1
- **/
- 공개 함수 rollBack()
-
- {
-
- if ($this->_transactionNestingLevel == 0) {
-
- throw ConnectionException::noActiveTransaction();
-
- }
- if ($this->_transactionNestingLevel == 1) {
-
- $this->_transactionNestingLevel = 0;
-
- $this->_conn->rollback();
-
- $this->_isRollbackOnly = false;
-
- } else if ($this->_nestTransactionsWithSavepoints) {
-
- $this->rollbackSavepoint($this->_getNestedTransactionSavePointName());
-
- --$this->_transactionNestingLevel;
-
- } 그밖에 {
-
- $this->_isRollbackOnly = true;
-
- --$this->_transactionNestingLevel;
-
- }
-
- }
可以看到处理的方式也很简单,如果level是1,直接rollback,否则就回滚到前면의 저장점.然后我们继续看下commit函数:
[php] 일반 사본 보기
- 1. /**
- * 저자 http://www.lai18.com
- * 날짜 2015-04-19
- * 버전 1
- **/
- 공개 함수 commit()
-
- {
-
- if ($this->_transactionNestingLevel == 0) {
-
- throw ConnectionException::noActiveTransaction();
-
- }
-
- if ($this->_isRollbackOnly) {
-
- 던지기 ConnectionException::commitFailedRollbackOnly();
-
- }
- if ($this->_transactionNestingLevel == 1) {
-
- $this->_conn->commit();
-
- } else if ($this->_nestTransactionsWithSavepoints) {
-
- $this->releaseSavepoint($this->_getNestedTransactionSavePointName());
-
- }
- --$this->_transactionNestingLevel;
-
- }
算了,不费口舌解释这段了吧 :)
3, laravel의 解决方案laravel의 处理方式毹简单粗暴一些,我们先来看下创建事务的操작곡:
[php] 일반 사본 보기
- 1.
- /**
- * 저자 http://www.lai18.com
- * 날짜 2015-04-19
- * 버전 1
- **/
- 공개 함수 beginTransaction()
-
- {
-
- ++$this->transactions;
- if ($this->transactions == 1)
-
- {
-
- $this->pdo->beginTransaction();
-
- }
-
- }
感觉如何?너무 쉬워요吧?先判断当前有几个事务,如果是第一个,ok,事务开始,否则就啥都不做,那么为啥是啥啥做呢?继续往下看RollBack의 작업:
[php] 일반 사본 보기
- 1. /**
- * 저자 http://www.lai18.com
- * 날짜 2015-04-19
- * 버전 1
- **/
- 공개 함수 rollBack()
-
- {
-
- if ($this->transactions == 1)
-
- {
-
- $this->거래 = 0;
- $this->pdo->rollBack();
-
- }
-
- 그밖에
-
- {
-
- --$this->거래;
-
- }
-
- }
명백신은?处理比较简单粗暴一些,현재嵌套的内层里是也解决了에서 内层new建一个务时体你成, 虽然简单粗暴, 但是也解决了成커밋합니다.完整起见,把commit的代码也copy过来吧!
[php] 일반 사본 보기
- 공개 함수 commit()
-
- {
-
- if ($this->transactions == 1) $this->pdo->commit();
- --$this->거래;
-
- }
以上就介绍了PHP中实现MySQL嵌套事务的两种解决方案, 包括了方案, 包括了方案, 内容, 希望对PHP教程兴趣的朋友趣的朋友帮助.