ورود

View Full Version : ایجاد رکورد توسط 2 کاربر در حالت BeginTrans؟



SYNDROME
شنبه 19 تیر 1389, 21:19 عصر
با سلام
در یک برنامه کاربران متعددی ورود اطلاعات می کنند.
فرض می کنیم Insert کردن هر رکورد با تابعی که بعد از آن اجرا می شود 30 ثانیه طول می کشد
دستور ذخیره هم به شکل زیر است


ADOConnection.BeginTrans;
ADO.Insert;
..
..
ADO.Post;
Call Function
ADOConnection.CommitTrans;

حالا کاربر اول اقدام به ذخیره یک رکورد می کند و کاربر دوم بعد از 1 ثانیه عمل فوق را نجام می دهد.
با Post شدن رکورد کاربر اول ، Post کاربر دوم تا Commit شدن ذخیره کاربر اول طول می کشد.
حالا فکر کنید اگر چند کاربر این عمل را انجام دهند چه فاجعه ای رخ می دهد.
انواع Isolation Level ها را قبل از BeginTransation تست کرده ام ولی باز هم مشکل وجود دارد.
ممنون می شوم بنده را راهنمایی کنید.

حمیدرضاصادقیان
یک شنبه 20 تیر 1389, 12:20 عصر
سلام.من خودم از این روش استفاده کردم و تا الان هم جواب گرفتم.
برای بحث اضافه کردن رکورد.
وقتی کاربر دکمه اضافه رو زد من شماره آخرین کلید فرضا در سند حسابداری شماره آخرین سند رو یکی بهش اضافه میکنم به کاربر نمایش میدم ، کاربر اگر خواست میتونه تغییر بده.وقتی که کاربر دکمه ذخیره رو زد همون موقع شماره رو چک میکنم اگر تکراری نبود اجازه ذخیره میدم اگر تکراری بود در یک تابع مقدار آخرین رکورد رو برمیگردونم و شماره جدید رو در سند قرار میدم.با این روش با 6-7 کاربر همزمان من تست کردم هیچ مشکلی پیش نیومد.در ضمن Table هم قفل نمیشه.
من اطلاعات رو از یک Stringgrid میخونم و ذخیره میکنم.
باز سوالی بود در خدمتم.
موفق باشید.

SYNDROME
یک شنبه 20 تیر 1389, 16:44 عصر
با سلام
آیا شما در هنگام اضافه کردن رکورد به جدول ADOConnection را BeginTransaction می کنید؟؟؟؟؟؟
به چه روشی اطلاعات را داخل بانک اطلاعات ذخیره می کنید؟
من همین که دستور ADO.Post را اجرا می کنم تا زمانی Commit نکنم هیچ کاربری نمی تواند عمل Insert را انجام دهد.
من از محیط Delphi و SQL Server 2005 استفاده می کنم.
البته به این نکته نیم توجه کنید که فاصله زمانی Post تا Commcit مثلاً 30 ثانیه است.
با تشکر

حمیدرضاصادقیان
یک شنبه 20 تیر 1389, 19:19 عصر
سلام.ببینید روشی که من استفاده میکنم هیچ ارتباطی به دیتابیس نداره.
من با استفاده از دستور insert خود sql اینکارو میکنم.یک sp برای اینکار نوشتم.
دیتاروهم با دستور Select خونده و خودم در فرم مقداردهی میکنم.کلا از ابزار data access استفاده نکردم.
وقتی طرف اضافه رو میزنه من یک تابع نوشتم که آخرین شماره رو بهش میده دیگه ارتباط با دیتابیس قطع میشه.
کاربر درون فرم اطلاعاتش رو وارد میکنه.(تا اینجای کار هیچ کاری با جدول و دیتابیس نداریم و کاربرای دیگه خیلی راحت میتونن از همون جدول استفاده کنند یعنی اصلا جدول قفل نیست) بعد وقتی دکمه تائید رو میزنه یک تابع نوشتم که شماره رو چک میکنه که تکراری نباشه بعد با استفاده از یک حلقه و دستور insert مقادیر رو داخل دیتابیس اضافه میکنم.
تاحالا با این روش نه مشکلی برام پیش اومده نه هنگام درج مشکل کندی داشتم نه مشکل همزمانی.

SYNDROME
یک شنبه 20 تیر 1389, 21:58 عصر
با سلام
آیا شما قبل از Insert اطلاعات Transaction ایجاد می کنید یا نه؟
اگر برنامه ای در این زمینه دارید ممنون می شوم برای من قرار دهید.
با تشکر فراوان

حمیدرضاصادقیان
یک شنبه 20 تیر 1389, 22:33 عصر
سلام.این یک نمونه تستی هست.که میتونید به حالت جامع تری اینو تعمیم بدید.
در ضمن procedure و توابعی هم که نوشتم میتونید در sql بنویسید که سرعت بالاتر خواهد رفت.

SYNDROME
دوشنبه 21 تیر 1389, 05:57 صبح
سلام.این یک نمونه تستی هست.که میتونید به حالت جامع تری اینو تعمیم بدید.
در ضمن procedure و توابعی هم که نوشتم میتونید در sql بنویسید که سرعت بالاتر خواهد رفت.
با تشکر فراوان از شما دوست گرامی
برنامه را گرفتم
شما فقط یک رکورد را Insert می کنید ولی و نیازی به دستور Begin Trans ندارید.
ولی من در برنامه خودم نیاز دارم بعد از اضافه کردن رکورد عملیات خاصی انجام دهم و اگر آن عملیات انجام نشود باید رکورد اضافه شده هم Rollback شود.
با اجازه شما به قبل از iNSERT یک bEGIN tRANS و بعد از پایان عملیات یک cOMMIT قرا دادم تا دقیقاً شرایط برنامه من ایجاد شود.(اگر امکان دارد شما هم اضافه کنید)
حالا 2 بار دلفی را بز کنید و در برنامه اول در قسمت DataModule2.ADOConnection1.CommitTrans یک Break Point قرار دهید و برنامه را اجرا رده و رکورد را اضافه کنید و بعد از رسید دستورات به Break Point بگذارید همینجوری بماند و برنامه دوم را اجرا کرده و سپس عمل insert را انجام دهید حالا می بنید تا زمانی که برنامه اول Commit را اجرا نکند برنامه دوم قادر به ذخیره اصلاعات نیست.


procedure TForm1.InsertData;
begin
DataModule2.ADOConnection1.BeginTrans;
With DataModule2.ADOQuery1 Do
Begin
sql.clear;
sql.add('insert into tbl_test values(:id,:nam)');
parameters.ParamByName('id').value := Edit1.Text;
Parameters.ParamByName('nam').value := Edit2.Text;
execsql;
End;
DataModule2.ADOConnection1.CommitTrans;
end;


مشکل برنامه من این موضوع است.
ما فرض می کنیم فاصله زمانی Post تا Commit مثلاً 30 ثانیه است.
ممنون می شوم دوستان کمک کنند.

حمیدرضاصادقیان
دوشنبه 21 تیر 1389, 11:21 صبح
سلام.شاید بهتر باشه CommandTimeout رو تنظیم کنید مثلا برای 10 ثانیه که اگر بیش از 10 ثانیه طول کشید rollback کنه.
یا میتونید کارهایی که داخل توابع بعد از insert انجام بدید رو درون یک Sp بنویسید به همراه دستور insert که به محض اینکه کاربر دکمه ذخیره رو زد اون Sp صدا زده میشه و داخل Begin trans,commit tRan هم قرار داره.
یاهمه اون کارها انجام میشه یا هیچکدوم انجام نمیشه اینجوری در دلفی شما فقط اون Sp رو صدا میزنید.
موفق باشید

SYNDROME
دوشنبه 21 تیر 1389, 12:00 عصر
با تشکر از شما
دوست عزیز من داخل چند جدول به صورت پشت سر هم دارم Insert می کنم و اگر از BeginTrans استفاده نکنم اگر در هنگام Insert در جدول دوم خطا پیش بیاید اطلاعات در جدول اول ذخیره شده است.
نمی خواهم در هنگام عمل درج Timeout بدهد چون این زمان (30 ثانیه) باید سپری شود تا Insert در جدول دوم تمام شود و Commi شود.
باز هم منتظر راهنمایی دوستان هستم

AminSobati
دوشنبه 21 تیر 1389, 12:08 عصر
سلام دوست عزیزم،
شما غیر از Insert دقیقا چه عملیات دیگه ای در Transaction دارین؟

حمیدرضاصادقیان
دوشنبه 21 تیر 1389, 12:30 عصر
سلام.به نظر من شما یک Procedure بساز و مقادیر همه جداول رو به اون پاس بده.بعد فرضا شما داری توی 3تاجدول Insert میکنی ، این سه تا insert رو داخل یک Procedure در sql بنویس و بین Begin tran , commit tran قرار بده. در برنامه هم نیازی به Transaction دیگه نداری.فقط کافیه مقدار بهش پاس بدی و اونو صدا بزنی.حالا اگر خطا هم بده میتونی با استفاده از rollback اونو برگردونی.