PHP + MySQL işlem örnekleri


294

MySQL işlemlerinin kullanıldığı PHP dosyasının normal örneğini gerçekten bulamadım. Bana bunun basit bir örneğini gösterebilir misin?

Ve bir soru daha. Zaten çok fazla programlama yaptım ve işlemler kullanmadım. Bir PHP işlevi falan koyabilir miyim header.phpbiri mysql_querybaşarısız olursa, o zaman diğerleri de başarısız?


Sanırım çözdüm, doğru mu ?:

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");Sekans yerine kullanabilirsinizmysql_query("SET AUTOCOMMIT=0"); mysql_query("START TRANSACTION");
Kirzilla

75
Lütfen mysql_*yeni kodda işlevleri kullanmayın . Artık bakımları yapılmıyor ve resmi olarak kullanımdan kaldırılıyor . Bkz kırmızı kutuyu ? Bunun yerine hazırlanmış ifadeler hakkında bilgi edininve PDO veya MySQLi kullanın - bu makale hangisine karar vermenize yardımcı olacaktır. PDO'yu seçerseniz, işte size iyi bir öğretici .
Naftali aka Neal

6
"Mysql_query (" SET AUTOCOMMIT = 0 ");" tüm bağlantıları kesinleştirme işlevini bekleyecek şekilde mi ayarlayabilir yoksa sadece ilgili bağlantı için mi?
Hamid

1
@Neal, Aslında mysqlkullanılmamasına rağmen ölür, sonsuza dek PECL'de mevcut olacaktır.
Pacerier

2
@Pacerier Kullanımdan kaldırılan şeyler "ölmez". Eski yazılımlar için resmi olarak tutulurlar, ancak yeni yazılımlar için önerilen uygulamalardan korunmayı ve bunlardan korunmayı durdururlar. Gerçek kalır, kullanmayınmysql
taylorcressy

Yanıtlar:


325

Genellikle işlemlerle çalışırken kullandığım fikir şuna benzer (yarı sözde kod) :

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();
}


Bu fikirle, bir sorgu başarısız olursa bir İstisna atılması gerektiğini unutmayın:

  • PDO bunu nasıl yapılandırdığınıza bağlı olarak yapabilir
  • başka bir API ile, bir sorguyu yürütmek için kullanılan işlevin sonucunu test etmeniz ve kendinize bir istisna atamanız gerekebilir.


Ne yazık ki, hiçbir sihir yoktur. Bir yere bir talimat koyamazsınız ve işlemlerin otomatik olarak yapılmasını sağlayamazsınız: yine de bir işlemde hangi sorgu grubunun yürütülmesi gerektiğini belirtmeniz gerekir.

Örneğin, oldukça sık işlem öncesi sorguları bir çift olacak (daha önce begin) ve işlemden sonra sorguları başka bir çift (ya sonra commitya rollback) bu sorgular olanları olursa olsun idam ve isteyeceksiniz (veya değil) içinde işlem.


35
Eğer db dışında istisnalar atabilecek işlemler yapıyorsanız dikkatli olun. Öyleyse, db olmayan bir ifadeden gelen bir istisna yanlışlıkla (tüm db çağrıları başarılı olsa bile) geri dönmeye neden olabilir. Normalde, hata db tarafında olmasa bile geri almanın iyi bir fikir olduğunu düşünürsünüz, ancak 3. taraf / kritik olmayan kodun çok önemli olmayan istisnalara neden olabileceği zamanlar vardır ve yine de devam etmek istersiniz. işlem.
Halil Özgür

6
$dbBuradaki tip nedir ? mysqli?
Jake

3
@Jake mysqli kullanan bir örnek için cevabımı görün (Pascal'ın yaklaşımına benzer şekilde).
EleventyOne

2
PDOExceptiongerektiğinde istisna değerlerini yakalamak ve hatta kontrol etmek için kolayca değiştirilebilir . us2.php.net/PDOException
Yamiko

1
$ db PDO nesnesidir (bağlantı). Ref: php.net/manual/tr/pdo.connections.php
Fil

110

Sanırım çözdüm, doğru mu ?:

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 ayarlamanıza gerek yoktur. işlemler her zaman böyle çalışır.
bgcode

2
@babonk - InnoDB'de durumun bu olduğundan emin değil misiniz?
buggedcom

6
Bir işleme başladığınızda sanırım AUTOCOMMIT = 0
bgcode

4
@babonk haklı. Bir işlem başlatıldıktan sonra AUTOCOMMIT = 0 örtülü olarak ayarlanır ve işlem ya kesinleştirme ya da geri alma ile sona erdikten sonra, MySql işlemi başlatmadan önce kullanılan AUTOCOMMIT değerini geri ayarlar. NOT: AUTOCOMMIT = 0 ayarlamamalısınız, çünkü değişiklikleri yaptıktan sonra başka bir satır eklemeye / güncellemeye karar verirseniz, bunu açıkça gerçekleştirmelisiniz.
eroteev

4
Motor deposu Myisam değil InnoDB olmalıdır!
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";
}

?>

Bunun gibi geniş ve yüksek profilli bir soru için, cevapların da bunu yansıtması harika olurdu. Kod örneğiniz harika, ancak daha fazla ayrıntı verebilir misiniz? İşlemleri açıklayın, neden, ne zaman ve nerede? Son olarak, kodu açıklamanızla ilişkilendirin.
Dennis Haarbrink

3
StackOverflow'a hoş geldiniz. Lütfen cevabınıza daima açıklayıcı metinler yazın.
Adrian Heine

6
üzgünüm im begginer, ve benim kötü ingilizce, çok kolay kod sınavı - yeni başlayanlar için - commit () rollback () begin () sınıf DB koymak (örneğin), $ sorgu - bir kez değil - belki $ query0 $ query1 - sonra chek onları - ben bu kodu kullanın, bu çok kolay anlaşılır =)
Gedzberg Alex

20
Yorumları, örneği oldukça açık bir şekilde ortaya koyuyor. İyi kodun metni açıklamasına gerek yoktur. Ayrıca soru basit bir örnek ister. Bu cevabı beğendim.
Hiçbiri

@GedzbergAlex tek bir sorgu için işleme gerek yoktur, sadece işlem hakkında karıştırır, Tek bir sorgu için işlemi kullanmak için bir neden var mı?
ɐɯıɥʇɹɐʞ ouɐɯ

35

Bu "php mysql işlem" için google ilk sonuç olduğu gibi, ben açıkça mysqli (orijinal yazar istediği örnekleri gibi) ile bunu nasıl gösteren bir cevap eklemek düşündüm. PHP / mysqli ile işlemlere basitleştirilmiş bir örnek:

// 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   
}

Ayrıca, PHP 5.5 mysqli :: begin_transaction yeni bir yöntem olduğunu unutmayın . Ancak, bu henüz PHP ekibi tarafından belgelenmemiştir ve hala PHP 5.3'te takılı kalıyorum, bu yüzden yorum yapamam.


2
İlgili bir notta, InnoDB tablolarıyla çalışıyorsanız, işlemlere autocomitt () yaklaşımını kullanırken tabloları kilitlemenin / kilidini açmanın mümkün olduğunu keşfettim, ancak begin_transaction () yaklaşımını kullanırken mümkün DEĞİLDİR: MySQL belgeleri
EleventyOne

Gerçek mysqli koduyla ayrıntılı (ve yorumlanmış) örnek için +1. Bunun için teşekkürler. Kilitleme / işlemler konusundaki düşünceniz gerçekten çok ilginç.
a.real.human.being

1
"Autocommit (FALSE)" aynı veritabanı / tablodaki başka bir bağlantıyı etkiler mi? Demek istediğim, birinin "autocommit (FALSE)" olarak bağlantısını ayarladığı ancak diğeri autocommit işlevinden ayrıldığı iki sayfayı açarsak, kesinleştirme işlevini bekler veya beklemez. Otomatik tamamlamanın bağlantılar / veritabanı / tablo için bir öznitelik olup olmadığını bilmek istiyorum. Teşekkürler
Hamid

2
@Hamid $conn->autocommit(FALSE), yukarıdaki örnekte, yalnızca bireysel bağlantıyı etkilemektedir - veritabanına yapılan diğer bağlantılar üzerinde hiçbir etkisi yoktur.
EleventyOne

1
Not: yerine , sorgu yanlış veya sıfıra değerlendirir geçerli bir sonuç döndürme yeteneğine sahip if (!result), yapmalıdır if (result === false).
ToolmakerSteve

10

Lütfen hangi depolama motorunu kullandığınızı kontrol edin. MyISAM ise, MyISAM Transaction('COMMIT','ROLLBACK')değil , yalnızca InnoDB depolama motoru işlemleri desteklediğinden desteklenmez.


7

PDO bağlantısı kullanılırken:

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

İşlem yönetimi için genellikle aşağıdaki kodu kullanıyorum:

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
    }
}

Kullanım örneği:

transaction(function()
{
    global $pdo;

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

Bu şekilde, işlem yönetimi kodu proje genelinde çoğaltılmaz. Bu iyi bir şey, çünkü bu iş parçacığında PDO ile ilgili diğer cevaplardan yola çıkarak, hata yapmak kolaydır. En yaygın olanlar istisnayı yeniden düşünmeyi ve tryblok içinde işleme başlamayı unutuyor .


5

Bir sorgu vektör almak ve bir işlem yapmak için bir işlev yaptım, belki birisi yararlı bulacaktır:

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

Ben vardı, ama bunun doğru olup olmadığından emin değilim. Bunu da deneyebiliriz.

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");
}

Fikir buradan: http://www.phpknowhow.com/mysql/transactions/


Doğru kod değil. trigger_error true değerine dönecektir (çağrınızı bozmadıysanız), bu nedenle $ sonucu her zaman true olur, bu nedenle bu kod başarısız sorguları kaçırır ve her zaman taahhüt etmeye çalışır. Aynı derecede rahatsız edici olan, kullanan bir öğreticiye bağlansanız da mysql_query, kullanmak yerine eski kullanımdan kaldırılmış olanı kullanıyorsunuzdur . IMHO, bu kötü örneği silmeli veya phpknowhow öğreticisinde yazılan kodu kullanmak için değiştirmelisiniz. mysqlimysqli
ToolmakerSteve

2

Bir daha prosedürel tarzı örneği mysqli_multi_query, varsayar $querynoktalı virgülle ayrılmış ifadelerle doludur.

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
Biraz garip bir kod, ama en azından kullanımını önerir mysqli_multi_query. Bununla ilgilenen herkes daha temiz örnek için başka bir yerde google gerekir.
ToolmakerSteve
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.