سؤال

أنا باستخدام الخلية AUTO_INCREMENT المجال InnoDB لدعم المعاملات.لقد لاحظت عندما التراجع عن الصفقة ، AUTO_INCREMENT المجال ليست rollbacked?اكتشفت أنه تم تصميم هذا الطريق ولكن هل هناك أي الحلول هذا ؟

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

المحلول

واسمحوا لي أن أشير إلى شيء مهم جدا:

أنت لا ينبغي أبدا أن تعتمد على الميزات رقمية مفاتيح يتم إنشاؤه تلقائيا.

وهذا هو، بخلاف مقارنتها من أجل المساواة (=) أو التساوي (<>)، يجب أن لا تفعل أي شيء آخر. لا العلائقية (<،>)، لا الفرز بواسطة فهارس، وما إذا كنت بحاجة لترتيب النتائج بحسب "وأضاف تاريخ"، لها "وأضاف تاريخ" عمود.

ويعاملهم كما التفاح والبرتقال: هل يعقل أن نسأل إذا كان التفاح هو نفس برتقالة؟ نعم. هل يعقل أن نسأل إذا تفاحة أكبر من برتقالة؟ رقم (في الواقع، فإنه لا، ولكن لك وجهة نظري).

إذا كنت عصا لهذه القاعدة، والثغرات في استمرارية فهارس يتم إنشاؤه تلقائيا لا يسبب مشاكل.

نصائح أخرى

لا يمكن أن تعمل بهذه الطريقة.النظر:

  • برنامج واحد ، يمكنك فتح الصفقة و إدراج في جدول فو الذي autoinc المفتاح الأساسي (بشكل تعسفي ، نقول ذلك يحصل 557 لها قيمة المفتاح).
  • برنامج اثنين يبدأ يفتح صفقة ويدرج في جدول فو الحصول على 558.
  • برنامج اثنين من إدراج في الجدول الذي يحتوي على عمود وهو الأجنبية مفتاح فو.حتى الآن 558 يقع في كل من فو وبار.
  • برنامج اثنين الآن يرتكب.
  • البرنامج ثلاثة يبدأ ويولد تقرير من الجدول فو.فإن 558 سجل المطبوعة.
  • بعد أن برنامج واحد تتحرك مرة أخرى.

كيف قاعدة البيانات استعادة 557 قيمة ؟ أنها لا تذهب إلى فو و إنقاص جميع المفاتيح الأساسية أكبر من 557?كيف إصلاح شريط ؟ كيف محو 558 المطبوعة على تقرير البرنامج ثلاثة الإخراج ؟

أوراكل تسلسل الأرقام هي أيضا مستقلة عن المعاملات لنفس السبب.

إذا كنت يمكن أن تحل هذه المشكلة في وقت ثابت, أنا متأكد من أنك يمكن أن تجعل الكثير من المال في حقل قاعدة البيانات.

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

وكان المريض يحتاج إلى معرف إلى التراجع على جدول الفواتير، حيث يجب أن يكون ترتيب التوالي

وكان لي الحل في الخلية لإزالة AUTO-INCREMENT وسحب آخر رقم من الجدول، إضافة واحد (+1) ثم أدخله يدويا.

إذا تم تسمية الجدول "TableA" وعمود لصناعة السيارات في الزيادة هو "إيد"

INSERT INTO TableA (Id, Col2, Col3, Col4, ...)
VALUES (
(SELECT Id FROM TableA t ORDER BY t.Id DESC LIMIT 1)+1,
Col2_Val, Col3_Val, Col4_Val, ...)

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

إذا كان لديك معلومات كنت تحاول الحفاظ على، وربما هناك حاجة إلى عمود غير رئيسي آخر.

وأنا لا أعرف أي طريقة للقيام بذلك. وفقا ل الخلية الوثائق هذا، ومن المتوقع السلوك وسيحدث مع كل <م> وسائط innodb_autoinc_lock_mode قفل. نص محدد هو:

<اقتباس فقرة>   

في جميع وسائط القفل (0 و 1 و 2)، إذا كان   الصفقة التي ولدت   قيم زيادة تلقائية تتحرك إلى الوراء،   تلك القيم زيادة تلقائية هي   "فقدت". بعد إنشاء قيمة لل   عمود زيادة تلقائية، فإنه لا يمكن أن يكون   التراجع، سواء كان أو لم يكن   اكتمال "مثل INSERT" البيان   وعما إذا كان أو لم يكن يحتوي على   يتم إرجاع المعاملة مرة أخرى. مثل المفقود   لا يتم استخدامها القيم. وهكذا، يمكن هناك   أن الثغرات في القيم المخزنة في   AUTO_INCREMENT عمود من الجدول.

إذا قمت بتعيين auto_increment إلى 1 بعد التراجع أو الحذف، على إدراج المقبل، الخلية سوف نرى بالفعل استخدام هذا 1 وسوف بدلا من ذلك الحصول على قيمة MAX() وإضافة 1 إلى ذلك.

وهذا يضمن أنه إذا تم حذف الصف مع القيمة الأخيرة (أو يتم إرجاع إدراج الظهر)، سيتم إعادة استخدامها.

لتعيين AUTO_INCREMENT إلى 1، أن تفعل شيئا من هذا القبيل:

ALTER TABLE tbl auto_increment = 1

وهذه ليست فعالة مثل ببساطة المستمر على مع الرقم التالي لMAX() يمكن أن تكون مكلفة، ولكن إذا قمت بحذف / العودة إلى الحالة السابقة بشكل غير منتظم وهاجس إعادة استخدام أعلى قيمة، ثم وهذا هو نهج واقعي.

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

INSERT INTO prueba(id) 
VALUES (
(SELECT IFNULL( MAX( id ) , 0 )+1 FROM prueba target))

وإذا لم يتضمن جدول قيم أو الصفر صفوف

وإضافة الهدف لتحديث خطأ نوع الخلية من على SELECT

الحل:

دعونا استخدام 'tbl_test' على سبيل المثال الجدول, و لنفترض الميدان 'Id' وقد AUTO_INCREMENT السمة

CREATE TABLE tbl_test (
Id int NOT NULL AUTO_INCREMENT ,
Name varchar(255) NULL ,
PRIMARY KEY (`Id`)
)
;

لنفترض أن الجدول يحتوي houndred أو ألف الصفوف المدرجة بالفعل و كنت لا ترغب في استخدام AUTO_INCREMENT بعد الآن ؛ لأنه عندما يمكنك التراجع عن الصفقة الميدان 'Id' هو دائما إضافة +1 AUTO_INCREMENT القيمة.وذلك لتجنب التي قد تجعل من هذا:

  • دعونا إزالة AUTO_INCREMENT القيمة من العمود 'Id' (هذا لا حذف الصفوف المدرجة):
ALTER TABLE tbl_test MODIFY COLUMN Id  int(11) NOT NULL FIRST;
  • أخيرا, نحن إنشاء قبل إدراج تؤدي إلى توليد 'قيمة' معرف تلقائيا.ولكن باستخدام هذه الطريقة لن تؤثر على قيمة معرف حتى إذا كان يمكنك التراجع عن أي صفقة.
CREATE TRIGGER trg_tbl_test_1
BEFORE INSERT ON tbl_test
FOR EACH ROW
  BEGIN
    SET NEW.Id= COALESCE((SELECT MAX(Id) FROM tbl_test),0) + 1;
  END;

هذا هو!لقد انتهيت!

على الرحب والسعة.

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

وأما وقد قلت ذلك، بل هو فكرة سيئة إلى الاعتماد على هويات يجري في بعض ترتيب معين مع أي ثغرات. إذا كنت بحاجة إلى المحافظة يأمر، ربما يجب عليك طابع زمني على التوالي على إدراج (وربما على التحديث).

والجواب ملموسة لهذه المعضلة محددة (الذي كان أيضا) هو ما يلي:

1) إنشاء جدول الذي يحمل عدادات مختلفة للمستندات مختلفة (الفواتير والإيصالات، وRMA، الخ ..)؛ اضافة الى وجود سجل لكل من المستندات الخاصة بك وإضافة العداد الأولية إلى 0.

2) قبل إنشاء مستند جديد، قم بما يلي (الفواتير، على سبيل المثال):

UPDATE document_counters SET counter = LAST_INSERT_ID(counter + 1) where type = 'invoice'

و3) الحصول على القيمة الأخيرة الذي قمت بتحديثه فقط ل، كما يلي:

SELECT LAST_INSERT_ID()

وأو مجرد استخدام PHP (أو أيا كان) mysql_insert_id () وظيفة للحصول على نفس الشيء

و4) تضاف قياسيا جديدا الخاص جنبا إلى جنب مع ID الأساسي الذي حصل لتوه من DB. وهذا تجاوز مؤشر السيارات زيادة الحالي، وتأكد أن لديك أي ثغرات ID بينك السجلات.

وهذا الشيء كله يحتاج إلى أن تكون ملفوفة داخل معاملة، بطبيعة الحال. جمال هذا الأسلوب هو أنه عند التراجع عن الصفقة، عبارة UPDATE الخاص بك من الخطوة 2 سيتم التراجع، وسوف العداد لن تتغير بعد الآن. والمعاملات الأخرى المتزامنة منع حتى الصفقة الأولى هي إما الالتزام بها أو التراجع حتى لا يحصلون على أي وصفة طبية قديمة أو جديدة، حتى يتم الانتهاء من جميع المعاملات الأخرى أولا.

$masterConn = mysql_connect("localhost", "root", '');
mysql_select_db("sample", $masterConn);

for($i=1; $i<=10; $i++) {
    mysql_query("START TRANSACTION",$masterConn);
    $qry_insert = "INSERT INTO `customer` (id, `a`, `b`) VALUES (NULL, '$i', 'a')";
    mysql_query($qry_insert,$masterConn);
    if($i%2==1) mysql_query("COMMIT",$masterConn);
    else mysql_query("ROLLBACK",$masterConn);

    mysql_query("ALTER TABLE customer auto_increment = 1",$masterConn);

}



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