PHP + MySQL 트랜잭션 예제


294

MySQL 트랜잭션이 사용되는 PHP 파일의 일반적인 예를 찾지 못했습니다. 간단한 예를 보여 주시겠습니까?

그리고 하나 더 질문. 나는 이미 많은 프로그래밍을 수행했으며 트랜잭션을 사용하지 않았습니다. header.php하나 mysql_query가 실패하면 다른 하나도 실패 하는 PHP 함수 또는 다른 것을 넣을 수 있습니까 ?


나는 그것을 이해했다고 생각한다, 맞습니까? :

mysql_query("SET AUTOCOMMIT=0");
mysql_query("START TRANSACTION");

$a1 = mysql_query("INSERT INTO rarara (l_id) VALUES('1')");
$a2 = mysql_query("INSERT INTO rarara (l_id) VALUES('2')");

if ($a1 and $a2) {
    mysql_query("COMMIT");
} else {        
    mysql_query("ROLLBACK");
}

10
mysql_query("BEGIN");시퀀스 대신 사용할 수 있습니다mysql_query("SET AUTOCOMMIT=0"); mysql_query("START TRANSACTION");
Kirzilla

75
mysql_*새 코드 에서는 함수를 사용하지 마십시오 . 더 이상 유지 관리되지 않으며 공식적으로 더 이상 사용되지 않습니다 . 참고 항목 빨간색 상자 ? 에 대한 학습 준비된 문 대신 사용할 PDO 또는 MySQLi를 - 이 기사는 당신이 어떤을 결정하는 데 도움이됩니다. PDO를 선택하면 다음 은 좋은 튜토리얼 입니다.
Naftali 일명 Neal

6
"mysql_query ("SET AUTOCOMMIT = 0 ");" 커밋 기능을 기다리도록 모든 연결을 설정하거나 관련 연결 만 설정합니까?
Hamid

1
@Neal, 실제로 mysql는 더 이상 사용되지 않지만 죽으면 PECL에서 영원히 사용할 수 있습니다.
Pacerier

2
@Pacerier 더 이상 사용되지 않는 것들은 "사랑"하지 않습니다. 그것들은 레거시 소프트웨어를 위해 공식적으로 유지되지만 새로운 소프트웨어에 대한 권장 관행에서 유지 및 중단되는 것을 중단합니다. 사실은 남아, 사용하지 마십시오mysql
taylorcressy

답변:


325

트랜잭션 작업을 할 때 일반적으로 사용하는 아이디어는 다음과 같습니다 (세미 의사 코드) .

try {
    // First of all, let's begin a transaction
    $db->beginTransaction();

    // A set of queries; if one fails, an exception should be thrown
    $db->query('first query');
    $db->query('second query');
    $db->query('third query');

    // If we arrive here, it means that no exception was thrown
    // i.e. no query has failed, and we can commit the transaction
    $db->commit();
} catch (Exception $e) {
    // An exception has been thrown
    // We must rollback the transaction
    $db->rollback();
}


이 아이디어로 쿼리가 실패하면 예외가 발생해야합니다.

  • 구성 방법에 따라 PDO가이를 수행 할 수 있습니다.
  • 그렇지 않으면 다른 API를 사용하여 쿼리를 실행하는 데 사용 된 함수의 결과를 테스트하고 예외를 직접 throw해야 할 수도 있습니다.


불행히도 관련된 마술은 없습니다. 어딘가에 지시를 내릴 수 없으며 트랜잭션을 자동으로 수행 할 수 있습니다. 트랜잭션에서 실행해야하는 쿼리 그룹을 구체적으로 지정해야합니다.

예를 들어, 매우 자주 거래하기 전에 쿼리의 몇 가지를해야 합니다 (이전 begin) 및 거래 후 쿼리의 또 다른 커플 (중 후 commit또는 rollback) 그 쿼리에 무슨 일이 있었는지에 상관없이 실행하고 당신이 원하는 것 (여부) 에 거래.


35
db 이외의 예외가 발생할 수있는 조작을 수행하는 경우주의하십시오. 그렇다면, 모든 db 호출이 성공하더라도 db가 아닌 명령문의 예외로 인해 롤백이 실수로 롤백 될 수 있습니다. 일반적으로 오류가 db 측에 있지 않은 경우에도 롤백이 좋은 생각이라고 생각하지만 타사 / 중요하지 않은 코드로 인해 중요하지 않은 예외가 발생할 수 있으며 여전히 계속하고 싶습니다. 거래.
Halil Özgür

6
$db여기 에 유형 이 무엇입니까 ? MySQL?
Jake

3
@Jake mysqli (파스칼의 접근 방식과 비슷한 스타일)를 사용하는 예제는 내 대답을 참조하십시오.
EleventyOne

2
PDOException필요한 경우 예외 값 을 포착 하고 확인 하기 위해 쉽게 수정할 수 있습니다 . us2.php.net/PDOException
Yamiko

1
$ db 는 PDO 개체 (연결)입니다. 참조 : php.net/manual/en/pdo.connections.php
Fil

110

나는 그것을 이해했다고 생각한다, 맞습니까? :

mysql_query("START TRANSACTION");

$a1 = mysql_query("INSERT INTO rarara (l_id) VALUES('1')");
$a2 = mysql_query("INSERT INTO rarara (l_id) VALUES('2')");

if ($a1 and $a2) {
    mysql_query("COMMIT");
} else {        
    mysql_query("ROLLBACK");
}

26
autocommit = 0을 설정할 필요가 없습니다. 거래는 항상 그런 식으로 작동합니다.
bgcode

2
@babonk-이것이 InnoDB의 경우인지 확실하지 않습니까?
buggedcom

6
거래를 시작하면 마치 AUTOCOMMIT = 0처럼 작동합니다.
bgcode

4
@babonk가 맞습니다. 트랜잭션이 시작되면 AUTOCOMMIT = 0이 암시 적으로 설정되고 트랜잭션이 커밋 또는 롤백으로 종료 된 후 MySql은 트랜잭션을 시작하기 전에 사용 된 AUTOCOMMIT 값을 다시 설정합니다. 참고 : 변경 내용을 커밋 한 후 다른 행을 삽입 / 업데이트하기로 결정한 경우 명시 적으로 커밋해야하므로 AUTOCOMMIT = 0을 설정해서는 안됩니다.
eroteev

4
엔진 스토어는 MyISAM이 아니라 InnoDB 여야합니다!
javad

39
<?php

// trans.php
function begin(){
    mysql_query("BEGIN");
}

function commit(){
    mysql_query("COMMIT");
}

function rollback(){
    mysql_query("ROLLBACK");
}

mysql_connect("localhost","Dude1", "SuperSecret") or die(mysql_error());

mysql_select_db("bedrock") or die(mysql_error());

$query = "INSERT INTO employee (ssn,name,phone) values ('123-45-6789','Matt','1-800-555-1212')";

begin(); // transaction begins

$result = mysql_query($query);

if(!$result){
    rollback(); // transaction rolls back
    echo "transaction rolled back";
    exit;
}else{
    commit(); // transaction is committed
    echo "Database transaction was successful";
}

?>

이와 같이 광범위하고 높은 수준의 질문에 대한 답변도 반영한다면 좋을 것입니다. 코드 샘플은 훌륭하지만 더 자세히 설명 할 수 있습니까? 거래, 왜, 언제, 어디서 거래에 대해 설명 하시겠습니까? 마지막으로 코드를 설명과 연결하십시오.
Dennis Haarbrink

3
StackOverflow에 오신 것을 환영합니다. 항상 답변에 설명 텍스트를 작성하십시오.
Adrian Heine

6
죄송합니다 im begginer, 그리고 내 나쁜 영어, 매우 쉬운 코드 예제-초보자를위한-commit () rollback () begin () 클래스 DB에 넣은 $ query-한 번이 아니라-아마도 $ query0 $ query1-then 그들을
k-

20
그의 의견은 그 예를 아주 분명하게 만듭니다. 좋은 코드는 설명 텍스트가 필요하지 않습니다. 또한 질문은 간단한 예를 요구합니다. 나는이 답변을 좋아한다.
없음

단일 쿼리의 경우 @GedzbergAlex 트랜잭션이 필요 없으며 단순히 트랜잭션에 대해 혼동됩니다. 단일 쿼리에 트랜잭션을 사용해야하는 이유가 있습니까?
ʞɔıɥʇɹɐʞ ouɐɯ

35

이것이 "php mysql transaction"에 대한 Google의 첫 번째 결과이므로, mysqli로이 작업을 수행하는 방법을 명시 적으로 보여주는 답변을 추가 할 것이라고 생각했습니다. 다음은 PHP / mysqli를 사용한 간단한 트랜잭션 예입니다.

// let's pretend that a user wants to create a new "group". we will do so
// while at the same time creating a "membership" for the group which
// consists solely of the user themselves (at first). accordingly, the group
// and membership records should be created together, or not at all.
// this sounds like a job for: TRANSACTIONS! (*cue music*)

$group_name = "The Thursday Thumpers";
$member_name = "EleventyOne";
$conn = new mysqli($db_host,$db_user,$db_passwd,$db_name); // error-check this

// note: this is meant for InnoDB tables. won't work with MyISAM tables.

try {

    $conn->autocommit(FALSE); // i.e., start transaction

    // assume that the TABLE groups has an auto_increment id field
    $query = "INSERT INTO groups (name) ";
    $query .= "VALUES ('$group_name')";
    $result = $conn->query($query);
    if ( !$result ) {
        $result->free();
        throw new Exception($conn->error);
    }

    $group_id = $conn->insert_id; // last auto_inc id from *this* connection

    $query = "INSERT INTO group_membership (group_id,name) ";
    $query .= "VALUES ('$group_id','$member_name')";
    $result = $conn->query($query);
    if ( !$result ) {
        $result->free();
        throw new Exception($conn->error);
    }

    // our SQL queries have been successful. commit them
    // and go back to non-transaction mode.

    $conn->commit();
    $conn->autocommit(TRUE); // i.e., end transaction
}
catch ( Exception $e ) {

    // before rolling back the transaction, you'd want
    // to make sure that the exception was db-related
    $conn->rollback(); 
    $conn->autocommit(TRUE); // i.e., end transaction   
}

또한 PHP 5.5에는 mysqli :: begin_transaction 이라는 새로운 메소드가 있습니다. 그러나 이것은 아직 PHP 팀에 의해 문서화되지 않았으며 여전히 PHP 5.3에 갇혀 있으므로 주석을 달 수 없습니다.


2
관련 메모에, 나는 당신이 InnoDB 테이블로 작업하는 경우 거래에 autocomitt () 방식을 사용하는 경우, 그것은 잠금 / 잠금 해제 테이블에 가능하지만 begin_transaction () 방식을 사용하는 경우가 불가능하다는 것을 발견 : MySQL의 문서
EleventyOne

실제 mysqli 코드를 사용한 자세한 (및 주석이 달린) 예제는 +1입니다. 고마워 그리고 잠금 / 트랜잭션에 대한 당신의 요점은 실제로 매우 흥미 롭습니다.
a.real.human.being

1
"autocommit (FALSE)"는 동일한 데이터베이스 / 테이블의 다른 연결에 영향을 줍니까? 두 페이지를 열면 그 중 하나가 "autocommit (FALSE)"로 연결되어 있지만 다른 페이지는 자동 커밋 기능을 그대로두고 커밋 기능을 기다리거나 기다리지 않습니다. 자동 커밋이 데이터베이스 / 테이블이 아닌 연결의 속성인지 알고 싶습니다. 감사합니다
Hamid

2
$conn->autocommit(FALSE)위의 예에서 @Hamid 는 개별 연결에만 영향을 미치며 데이터베이스에 대한 다른 연결에는 영향을 미치지 않습니다.
EleventyOne

1
참고 : 쿼리에서 false 또는 0으로 평가되는 유효한 결과를 반환 할 수있는 경우 if (!result), 대신을 수행해야 if (result === false)합니다.
ToolmakerSteve

10

사용중인 스토리지 엔진을 확인하십시오. MyISAM 인 경우 MyISAM Transaction('COMMIT','ROLLBACK')이 아닌 InnoDB 스토리지 엔진 만 트랜잭션을 지원하므로 지원되지 않습니다.


7

PDO 연결을 사용하는 경우 :

$pdo = new PDO('mysql:host=localhost;dbname=mydb;charset=utf8', $user, $pass, [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // this is important
]);

트랜잭션 관리에 종종 다음 코드를 사용합니다.

function transaction(Closure $callback)
{
    global $pdo; // let's assume our PDO connection is in a global var

    // start the transaction outside of the try block, because
    // you don't want to rollback a transaction that failed to start
    $pdo->beginTransaction(); 
    try
    {
        $callback();
        $pdo->commit(); 
    }
    catch (Exception $e) // it's better to replace this with Throwable on PHP 7+
    {
        $pdo->rollBack();
        throw $e; // we still have to complain about the exception
    }
}

사용 예 :

transaction(function()
{
    global $pdo;

    $pdo->query('first query');
    $pdo->query('second query');
    $pdo->query('third query');
});

이런 식으로 트랜잭션 관리 코드가 프로젝트 전체에서 복제되지 않습니다. 이 스레드의 다른 PDO 등급 답변에서 판단하면 실수를하기 쉽습니다. 가장 일반적인 것은 예외를 다시 던지는 것을 잊고 try블록 내에서 트랜잭션을 시작하는 것 입니다.


5

쿼리 벡터를 얻고 트랜잭션을 수행하는 함수를 만들었습니다. 어쩌면 누군가가 유용하다는 것을 알 수 있습니다.

function transaction ($con, $Q){
        mysqli_query($con, "START TRANSACTION");

        for ($i = 0; $i < count ($Q); $i++){
            if (!mysqli_query ($con, $Q[$i])){
                echo 'Error! Info: <' . mysqli_error ($con) . '> Query: <' . $Q[$i] . '>';
                break;
            }   
        }

        if ($i == count ($Q)){
            mysqli_query($con, "COMMIT");
            return 1;
        }
        else {
            mysqli_query($con, "ROLLBACK");
            return 0;
        }
    }

3

나는 이것을 가지고 있었지만 이것이 정확한지 확신하지 못한다. 이것도 시도해 볼 수 있습니다.

mysql_query("START TRANSACTION");
$flag = true;
$query = "INSERT INTO testing (myid) VALUES ('test')";

$query2 = "INSERT INTO testing2 (myid2) VALUES ('test2')";

$result = mysql_query($query) or trigger_error(mysql_error(), E_USER_ERROR);
if (!$result) {
$flag = false;
}

$result = mysql_query($query2) or trigger_error(mysql_error(), E_USER_ERROR);
if (!$result) {
$flag = false;
}

if ($flag) {
mysql_query("COMMIT");
} else {        
mysql_query("ROLLBACK");
}

여기에서 아이디어 : http://www.phpknowhow.com/mysql/transactions/


올바른 코드가 아닙니다. trigger_error는 (전화를 망쳐 놓지 않은 한) true를 반환하므로 $ result는 항상 true이므로이 코드는 실패한 쿼리를 놓치고 항상 커밋을 시도합니다. 마찬가지로 문제는을 사용 하는 자습서에 링크 하더라도을 사용하는 mysql_query대신 사용되지 않는 이전을 사용 mysqli하고 있습니다 mysqli. IMHO,이 나쁜 예제를 삭제하거나 phpknowhow tutorial에서 작성된 코드를 사용하도록 대체해야합니다.
ToolmakerSteve

2

을 사용한 절차 적 스타일 예제 중 하나 는 세미콜론으로 구분 된 명령문으로 채워져 mysqli_multi_query있다고 가정 $query합니다.

mysqli_begin_transaction ($link);

for (mysqli_multi_query ($link, $query);
    mysqli_more_results ($link);
    mysqli_next_result ($link) );

! mysqli_errno ($link) ?
    mysqli_commit ($link) : mysqli_rollback ($link);

1
다소 이상한 코드이지만 적어도 사용을 제안합니다 mysqli_multi_query. 더 관심이있는 사람은 다른 곳에서 구글을 깨끗하게해야합니다.
ToolmakerSteve
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.