>  기사  >  데이터 베이스  >  MySQL 중첩 트랜잭션에서 발생하는 문제에 대한 자세한 코드 예

MySQL 중첩 트랜잭션에서 발생하는 문제에 대한 자세한 코드 예

黄舟
黄舟원래의
2017-03-06 13:26:28976검색

이 글은 주로 MySQL 중첩 트랜잭션에서 발생하는 문제에 대한 관련 정보를 소개합니다. 필요한 친구는 이를 참고할 수 있습니다.

MySQL은 중첩 트랜잭션을 지원하지만 얼마 전까지만 해도 이를 수행하는 사람은 많지 않았습니다. , 해외에서 MySQL 중첩 트랜잭션의 필요성에 대해 논쟁하는 일부 외국인을 보았습니다. 정말 재미있습니다. 이 중첩된 유령 사용법이 장면에 필요한 이유는 무엇입니까? 나는 이전 DBA 동료들과 이야기를 나누고 어떤 시나리오에서도 MySQL 중첩 트랜잭션을 사용해서는 안 된다는 것을 알게 되었습니다.

그럼 MySQL 중첩 트랜잭션을 사용하면 어떤 문제가 발생하나요?

mysql> select * from ceshi; 
+------+ 
| n  | 
+------+ 
|  1 | 
+------+ 
1 row in set (0.00 sec) 
 
mysql> start transaction ; 
Query OK, 0 rows affected (0.00 sec) 
 
mysql> insert into ceshi values(2); 
Query OK, 1 row affected (0.00 sec) 
 
mysql> start transaction ; 
Query OK, 0 rows affected (0.00 sec) 
 
mysql> insert into ceshi values(3); 
Query OK, 1 row affected (0.00 sec) 
 
mysql> commit; 
Query OK, 0 rows affected (0.00 sec) 
 
mysql> rollback; 
Query OK, 0 rows affected (0.00 sec)


마지막에 롤백했지만 데이터가 표시는 1 2 3 입니다. 원래 모든 사람들은 내 트랜잭션이 중첩된 상태였지만 결국에는 롤백된 것처럼 느꼈다고 생각했습니다. 실제로 우리가 보고 싶은 것은 하위 트랜잭션이 성공적으로 실행되었다는 것입니다. 외부 트랜잭션의 실패는 롤백됩니다. 그러나 이는 사실이 아니며 최종 결과는 1 2 3입니다.

+-----+ 
| n   | 
+-----+ 
|  1 | 
|  2 | 
|  3 | 
+-----+

SQL 인터프리터가 시작 트랜잭션을 발견하면 커밋이 트리거됩니다. .. !! 

begin_1  sql_1  begin_2  sql_2  sql_3 commit_1  rollback_1  .

begin_2가 실행되면 이미 sql_1이 제출되어 있고 다시 commit_1을 실행하면 이때 sql_2가 제출됩니다. 다시 롤백하면 당연히 소용없을텐데... 이미 제출한거라서 뭘 롤백할 수 있겠는가...

앞서 말씀드린 것처럼 아키텍처 측면에서는 대체적으로 사람이 거의 없습니다. 중첩된 트랜잭션을 사용하지만 때로는 실수로 중첩된 트랜잭션도 있습니다. Python 프로젝트를 예로 들어 보겠습니다. 먼저 데코레이터를 사용하여 트랜잭션 패키징을 구현한 다음 데이터 처리 def a() 및 def b() 함수를 트랜잭션으로 래핑합니다. . 단일 거래. 로직이 b를 다시 호출하면 어떻게 될까요? 예, 트랜잭션은 중첩되어 있습니다. 이는 대부분의 비즈니스 개발에서 직면하게 될 문제라고 생각합니다.

그러면 이 위험을 방지하는 방법은 무엇일까요? 잠금을 추가하면... 전역 잠금을 설정하면 하위 트랜잭션이 생성되기 전에 잠금 상태가 판단됩니다...

Flask 프레임워크라면 플라스크 g 전역 변수를 사용할 수 있습니다.

Django 프레임워크인 경우 스레드 로컬을 사용하여 전역 변수를 사용할 수 있습니다.

tornado, gevent 등 비동기식 IO 아키텍처인 경우 fd를 사용하여 코루틴 변수를 연결할 수 있습니다.

@decorator
def with_transaction(f, *args, **kwargs):
 
  db = connection.get_db_by_table("*")
  try:
    db.begin()
    ret = f(*args, **kwargs)
    db.commit()
  except:
    db.rollback()
    raise
  return ret
 
 
@with_transaction
def hide(self):
  '''订单不在app端显示'''
  if self.status not in OrderStatus.allow_deletion_statuses():
    raise OrderStatusChangeNotAllowed(self.status, OrderStatus.deleted)
...
 
 
@with_transaction
def change_receipt_info(self, address, name, phone):
  region = Region.get_by_address(address)
  ...

다음 명령문을 실행하면 트랜잭션이 강제로 커밋됩니다. 물론 여기서 전제는 autocommit = True입니다.

ALTER FUNCTION  
ALTER PROCEDURE  
ALTER TABLE  
BEGIN  
CREATE DATABASE  
CREATE FUNCTION  
CREATE INDEX  
CREATE PROCEDURE  
CREATE TABLE  
DROP DATABASE  
DROP FUNCTION  
DROP INDEX  
DROP PROCEDURE  
DROP TABLE  
UNLOCK TABLES  
LOAD MASTER DATA  
LOCK TABLES  
RENAME TABLE  
TRUNCATE TABLE  
SET AUTOCOMMIT=1  
START TRANSACTION

위는 MySQL 중첩 트랜잭션에서 발생하는 문제의 코드 예제에 대한 자세한 설명입니다. 더 많은 관련 내용을 보려면 PHP 중국어 웹사이트를 참고하세요. (www.php.cn)!


성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.