1. 루프 제출 관련 문제
많은 개발자가 루프에서 트랜잭션을 제출하는 것을 좋아합니다. 다음은 아래와 같이 자주 작성하는 저장 프로시저의 예입니다. 위의 예에서 commit 명령을 추가할지 여부는 중요하지 않습니다. MySQL innodb의 스토리지 엔진은 기본적으로 자동 제출로 설정되어 있으므로 저장 프로시저에서 커밋을 제거한 결과는 동일합니다. 아래와 같이 개발자가 쉽게 간과하는 또 다른 문제는 다음과 같습니다.
DROP PROCEDURE IF EXISTS load1;CREATE PROCEDURE load1(count INT UNSIGNED)BEGIN DECLARE s INT UNSIGNED DEFAULT 1; DECLARE c CHAR(80) DEFAULT REPEAT('a',80); WHILE s <= count DO INSERT INTO t1 select NULL,c; COMMIT; SET s=s+1; END WHILE;END;
위의 어떤 저장 프로시저와 관계없이 오류가 발생하면 데이터베이스는 알 수 없는 위치에 유지됩니다. 예를 들어 10,000개의 데이터를 삽입하려고 하는데 5,000개의 데이터를 삽입하는 중에 오류가 발생했습니다. 그런데 이 5,000개의 데이터가 데이터베이스에 저장되어 있습니다. 어떻게 처리해야 할까요? 다른 하나는 성능 문제입니다. 다음 저장 프로시저는 트랜잭션에 삽입을 넣기 때문에 위의 두 저장 프로시저 중 어느 것도 아래 저장 프로시저보다 빠르지 않습니다.
DROP PROCEDURE IF EXISTS load2; CREATE PROCEDURE load2(count INT UNSIGNED)BEGIN DECLARE s INT UNSIGNED DEFAULT 1; DECLARE c CHAR(80) DEFAULT REPEAT('a',80); WHILE s <= count DO INSERT INTO t1 select NULL,c; SET s=s+1; END WHILE;END;
위의 세 가지 저장 프로시저에 대해 1을 삽입합니다. 실행 시간을 비교해 보면 세 번째 방법이 훨씬 빠르다는 것을 알 수 있는데, 이는 멘션마다 리두 로그를 작성해야 하므로 실제로 load1과 load2는 10만 개의 리두 로그를 작성하기 때문입니다. . 저장 프로시저 load3의 경우 리두 로그를 한 번만 작성했습니다.
먼저 테스트 테이블 준비
DROP PROCEDURE IF EXISTS load3; CREATE PROCEDURE load3(count INT UNSIGNED)BEGIN DECLARE s INT UNSIGNED DEFAULT 1; DECLARE c CHAR(80) DEFAULT REPEAT('a',80); START TRANSACTION; WHILE s <= count DO INSERT INTO t1 select NULL,c; SET s=s+1; END WHILE; COMMIT;END;
테스트 실행
CREATE TABLE `t1` (`id` int NOT NULL AUTO_INCREMENT ,`name` varchar(500) NULL , PRIMARY KEY (`id`) ) ;
두 번째 저장 프로시저 load2의 경우 수동으로 트랜잭션을 열 수도 있고, 저장 프로시저 load3도 수동으로 열 수 있습니다. 달성 효과 및 실행 시간은 다음과 같습니다.
09:50:44 test> call load1(1000000); Query OK, 0 rows affected (1 min 4.90 sec)09:54:23 test> truncate table t1; Query OK, 0 rows affected (0.05 sec)09:54:25 test> call load2(1000000); Query OK, 1 row affected (1 min 3.38 sec)09:55:32 test> truncate table t1; Query OK, 0 rows affected (0.20 sec)09:55:58 test> call load3(1000000); Query OK, 0 rows affected (33.90 sec)
2. 자동 제출 사용에 대해
위에서 언급한 것처럼 일부 특수한 시나리오에서는 자동 제출이 반드시 좋은 것은 아닙니다. 순환 제출 문제로 인해 MySQL 데이터베이스는 기본적으로 자동 제출(자동 커밋)으로 설정됩니다. 다음과 같은 방법으로 MySQL 제출 방법을 변경할 수 있습니다.
09:57:42 test> begin; Query OK, 0 rows affected (0.00 sec)09:57:46 test> call load2(1000000); Query OK, 1 row affected (34.08 sec)09:58:26 test> commit; Query OK, 0 rows affected (0.76 sec)
START TRANSATION 또는 BEGIN을 사용하여 명시적으로 트랜잭션을 시작할 수도 있습니다. MySQL은 자동으로
SET AUTOCOMMIT=0을 실행하고 COMMIT 또는 ROLLBACK이 트랜잭션을 종료한 후에 SET AUTOCOMMIT=1을 실행합니다.
3. 자동 롤백을 사용하여 예외 처리 저장 프로세스에서 예외가 발생하면 어떻게 해야 합니까? Innodb 스토리지 엔진은 HANDLER를 통한 트랜잭션 자동 롤백을 지원합니다. 저장 과정에서 오류가 발생하면 자동으로 롤백 작업이 수행됩니다. 아래 예를 들면 다음과 같습니다.
10:35:34 test> SET AUTOCOMMIT=0; Query OK, 0 rows affected (0.00 sec)
테스트 테이블은 다음과 같습니다
CREATE PROCEDURE sp_auto_rollback_demo()BEGIN DECLARE EXIT HANDLER FOR SQLEXCEPTION ROLLBACK; START TRANSACTION; INSERT INTO b select 1; INSERT INTO b select 2; INSERT INTO b select 1; INSERT INTO b select 3; COMMIT;END;
위의 저장 프로시저를 실행하면 두 번째 레코드 1을 삽입할 때 오류가 발생하지만 자동 롤백 작업이 이루어지기 때문입니다. 활성화, 이 저장 프로시저의 실행 결과는 다음과 같습니다.
CREATE TABLE `b` ( `a` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`a`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
문제도 없고 동작도 비교적 정상적인 것 같은데, sp_auto_rollback_demo 실행 시 실행이 성공한 걸까요, 실패한 걸까요? 이를 다음과 같이 처리할 수 있는데, 예를 들면 다음과 같습니다.
10:09:46 test> call sp_auto_rollback_demo; Query OK, 0 rows affected (0.01 sec)10:10:04 test> select * from b;Empty set (0.00 sec)
오류가 발생하면 먼저 롤백한 후 -1을 반환하여 작업 중 오류가 발생했음을 나타냅니다. 1을 반환하면 정상 작동을 나타냅니다. 실행 결과는 다음과 같습니다.
DROP PROCEDURE IF EXISTS sp_auto_rollback_demo;CREATE PROCEDURE sp_auto_rollback_demo()BEGIN DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN ROLLBACK; SELECT -1; END; START TRANSACTION; INSERT INTO b select 1; INSERT INTO b select 2; INSERT INTO b select 1; INSERT INTO b select 3; COMMIT; SELECT 1;END;
위 내용은 MySQL Innodb 트랜잭션 프로그래밍 문제 및 처리 내용입니다. 더 많은 관련 내용은 PHP 중국어 홈페이지(www.php.cn)를 참고해주세요!