سؤال

أنا أعمل على اللاب البيئة (linux apache postgresql php) و أنا فقط triyn لمعرفة كيفية استخدام إعداد البيان ضمن الصفقة (إذا أمكن ذلك).

أتمنى رمز شرح أفضل ثم الكلمات:

مثال 1, بسيطة الصفقة:

BEGIN;
INSERT INTO requests (user_id, description, date) VALUES ('4', 'This dont worth anything', NOW());
UPDATE users SET num_requests = (num_requests + 1) WHERE id = '4';
--something gone wrong, cancel the transaction
ROLLBACK;
UPDATE users SET last_activity = NOW() WHERE id = '4'
COMMIT;

في المثال أعلاه, إذا كنت undestood الحق الصفقة ، تأثير فقط في قاعدة البيانات سوف يكون last_activity التحديث...انتم ؟

إذا حاولت استخدام هذه الصفقة في php (مع كل من شركة تنمية نفط عمان أو pg_ طرق) رمز ينبغي أن تبدو مثل ذلك (مثال 2):

/* skip the connection */
pg_query($pgConnection, "BEGIN");
pg_query($pgConnection, "INSERT INTO requests (user_id, description, date) VALUES ('$id_user', 'This dont worth anything', NOW())");
pg_query($pgConnection, "UPDATE users SET num_requests = (num_requests + 1) WHERE id = '$id_user'");
//something gone wrong, cancel the transaction
pg_query($pgConnection, "ROLLBACK");
pg_query($pgConnection, "UPDATE users SET last_activity = NOW() WHERE id = '$id_user'");
pg_query($pgConnection, "COMMIT");

وأنه يعمل بشكل جيد.ربما القبيح أن نرى, ولكن يبدو العمل (اقتراح هي دائما موضع ترحيب)

على اي حال, المشكلة تأتي عندما أحاول envolve المثال 2 مع إعداد البيانات (وأنا أعلم أن في المثال 2 استخدام البيانات المعدة ليست مفيدة جدا)

مثال 3:

/* skip the connection */
pg_prepare($pgConnection, 'insert_try', "INSERT INTO requests (user_id, description, date) VALUES ('$1', '$2', $3)");
pg_query($pgConnection, "BEGIN");
pg_execute($pgConnection, 'insert_try', array($user_id, 'This dont worth anything', date("Y-m-d")));
/* and so on ...*/

حسنا, على سبيل المثال 3 ببساطة لا تعمل ، إعداد البيان سوف تكون فعالة إذا كانت الصفقة بسبب في التراجع.

لذلك ، فإن البيانات المعدة لا يمكن أن تستخدم في هذه الصفقة ، أو أخذت بطريقة خاطئة ؟

تحرير:

بعد محاولة بعض مع شركة تنمية نفط عمان, أنا وصلت إلى هذه النقطة:

<?php
$dbh = new PDO('pgsql:host=127.0.0.1;dbname=test', 'myuser', 'xxxxxx');

$rollback = false;

$dbh->beginTransaction();

//create the prepared statements
$insert_order = $dbh->prepare('INSERT INTO h_orders (id, id_customer, date, code) VALUES (?, ?, ?, ?)');
$insert_items = $dbh->prepare('INSERT INTO h_items (id, id_order, descr, price) VALUES (?, ?, ?, ?)');
$delete_order = $dbh->prepare('DELETE FROM p_orders WHERE id = ?');

//move the orders from p_orders to h_orders (history)
$qeOrders = $dbh->query("SELECT id, id_customer, date, code FROM p_orders LIMIT 1");
while($rayOrder = $qeOrders->fetch(PDO::FETCH_ASSOC)){
    //h_orders already contain a row with id 293
    //lets make the query fail
    $insert_order->execute(array('293', $rayOrder['id_customer'], $rayOrder['date'], $rayOrder['code'])) OR var_dump($dbh->errorInfo());
    //this is the real execute
    //$insert_order->execute(array($rayOrder['id'], $rayOrder['id_customer'], $rayOrder['date'], $rayOrder['code'])) OR die(damnIt('insert_order'));
    //for each order, i move the items too
    $qeItems = $dbh->query("SELECT id, id_order, descr, price FROM p_items WHERE id_order = '" . $rayOrder['id'] . "'") OR var_dump($dbh->errorInfo());
    while($rayItem = $qeItems->fetch(PDO::FETCH_ASSOC)){
        $insert_items->execute(array($rayItem['id'], $rayItem['id_order'], $rayItem['descr'], $rayItem['price'])) OR var_dump($dbh->errorInfo());
    }
    //if everything is ok, delete the order from p_orders
    $delete_order->execute(array($rayOrder['id'])) OR var_dump($dbh->errorInfo());
}
//in here i'll use a bool var to see if anythings gone wrong and i need to rollback,
//or all good and commit
$dbh->rollBack();
//$dbh->commit();
?>

رمز أعلاه فشل مع هذا الناتج:

مجموعة(3) { [0]=> string(5) "00000" [1]=> int(7) [2]=> string(62) "خطأ:مفتاح مكرر ينتهك قيد فريد "id_h_orders"" }

مجموعة(3) { [0]=> string(5) "25P02" [1]=> int(7) [2]=> string(87) "خطأ:الصفقة الحالية إحباط الأوامر تجاهلها حتى نهاية الصفقة كتلة" }

خطأ فادح:استدعاء دالة عضو الجلب() على غير كائن في /srv/www/test-db/test-db-pgsql-08.php على خط 23

لذا يبدو عند أول تنفيذ تفشل (واحد مع معرف 293) الصفقة تلقائيا إحباط...هل شركة تنمية نفط عمان لصناعة السيارات في التراجع, أو أي شيء آخر ؟

هدفي هو استكمال الكبيرة الأولى حين حلقة ، في نهاية المطاف ، باستخدام منطقي فار كما علم أن تقرر إذا إلى التراجع أو تنفيذ المعاملة.

هل كانت مفيدة؟

المحلول

مع كيو, إذا كان أي بيان ينتج خطأ في الخادم أثناء المعاملة ، أن الصفقة تتميز بأنها أجهضت.هذا لا يعني انها في الواقع توالت بعد الظهر - فقط بالكاد يمكنك أن تفعل أي شيء إلا لفة مرة أخرى.أفترض شركة تنمية نفط عمان لا تلقائيا مسألة التراجع ، فإنه ينتظر إلى "التراجع" الأسلوب.

لتحقيق ما أعتقد كنت تريد, يمكنك استخدام لنقطة حفظ.بدلا من التراجع عن الصفقة برمتها ، يمكنك العودة إلى لنقطة حفظ و تستمر الصفقة.سأعطيك مثال على استخدام هذا من psql:

srh@srh@[local] =# begin;
BEGIN
srh@srh@[local] *=# insert into t values(9,6,1,true);
INSERT 0 1
srh@srh@[local] *=# savepoint xyzzy;
SAVEPOINT
srh@srh@[local] *=# insert into t values(9,6,2,true);
ERROR:  duplicate key value violates unique constraint "t_pkey"
srh@srh@[local] !=# insert into t values(10,6,2,true);
ERROR:  current transaction is aborted, commands ignored until end of transaction block
srh@srh@[local] !=# rollback to savepoint xyzzy;
ROLLBACK
srh@srh@[local] *=# insert into t values(10,6,2,true);
INSERT 0 1
srh@srh@[local] *=# commit;
COMMIT
srh@srh@[local] =# 

حتى في هذا المثال, العمود الأول من t هو المفتاح الأساسي.حاولت إدراج صفين إلى t مع معرف من 9 ، حصلت تفرد القيد.لا أستطيع إعادة إدراج مع قيم الحق لأنه الآن أي بيان سوف تحصل على "الصفقة الحالية إحباط..." خطأ.ولكن يمكنني أن أفعل "العودة إلى لنقطة حفظ" الذي يعيدني إلى الدولة كنت في عندما فعلت "لنقطة حفظ" ("xyzzy" هو اسم لنقطة حفظ).ثم أنا يمكن أن العدد الصحيح الأمر إدراج وأخيرا تنفيذ المعاملة (الذي يلزم كل من إدراج).

لذا في حالتك أظن ما عليك القيام به هو إنشاء لنقطة حفظ قبل التحديث البيان:إذا كان يعطي خطأ ، القيام ب "العودة إلى لنقطة حفظ" وتعيين العلم الخاص بك.سوف تحتاج إلى توليد فريدة من نوعها أسماء savepoints:باستخدام العداد ، على سبيل المثال.

لست متأكدا من أنني أفهم لماذا تفعل كل هذا.بالتأكيد كنت ترغب في التوقف عن المعالجة في أقرب وقت كما كنت تعرف أنك ذاهب إلى دحر هذه الصفقة ؟ أو هل هناك معالجة أخرى في حلقة يجب أن يحدث ؟

نصائح أخرى

يجب أن تستخدم

pdo_obj->beginTransaction()
pdo_obj->commit()
pdo_obj->prepare()

أيضا لديك عشوائي ترتكب في المثال الأول.

begin
// do all your stuff
// check for errors through interface
commit OR not

pg_query($pgConnection, "ROLLBACK"); // end of tx(1)
// start new transaction after last rollback = tx(2)
pg_query($pgConnection, "UPDATE users SET last_activity = NOW() WHERE id = '$id_user'");
// commit tx(2) or don't here
// this isn't needed pg_query($pgConnection, "COMMIT");

إذا لم ترتكبها, و تحتاج إلى يدويا ضبط الاشياء استخدام معاملة أخرى.إعداد الاستعلام الخاص بك (على ما أذكر) هو جزء من الصفقة ، لأنه يمكن أن تفشل.لا يمكنك حقا فقط يدويا تأخذ عبارة SQL وتحويلها إلى الاستعلامات.PDO واجهة تجريدات لسبب ما.:)

http://uk3.php.net/pdo <-- الصلبة أمثلة PHP/Postgre باستخدام شركة تنمية نفط عمان

حظا سعيدا

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top