مدیریت ثبت اطلاعات [C# & SQL Server]

سلام وقت همگی به خیر
دوستان میخواستم بدونم چطور میشه زمانی که به دلیل انجام یک تراکنش نیاز به ثبت و تغییر اطلاعات در چند جدول هست، این کار رو به بهترین روش ممکن انجام داد ؟
روشی که اگر در هنگام ثبت و تغییر اطلاعات برق رفت یا به هر دلیلی ارتباط به صورت ناگهانی با دیتابیس قطع شد تضمین کنه که یا همه ی جدول ها با هم اطلاعاتشون
بروز میشه یا اگر تغییر فقط در چند جدول انجام شده و تعدادی جدول باقی موندن، تغییرات انجام شده تصحیح بشه و به حالت اول برگرده !
دقیقا مثل سیستم بانک که اگه پول از حساب کم بشه ولی خرید انجام نشه، تغییرات انجام شده در حساب تصحیح میشه
فقط ممنون میشم در حد متوسط و قابل فهم توضیح بدین
خیلی ممنون
 

the_king

مدیرکل انجمن
خ

سلام وقت همگی به خیر
دوستان میخواستم بدونم چطور میشه زمانی که به دلیل انجام یک تراکنش نیاز به ثبت و تغییر اطلاعات در چند جدول هست، این کار رو به بهترین روش ممکن انجام داد ؟
روشی که اگر در هنگام ثبت و تغییر اطلاعات برق رفت یا به هر دلیلی ارتباط به صورت ناگهانی با دیتابیس قطع شد تضمین کنه که یا همه ی جدول ها با هم اطلاعاتشون
بروز میشه یا اگر تغییر فقط در چند جدول انجام شده و تعدادی جدول باقی موندن، تغییرات انجام شده تصحیح بشه و به حالت اول برگرده !
دقیقا مثل سیستم بانک که اگه پول از حساب کم بشه ولی خرید انجام نشه، تغییرات انجام شده در حساب تصحیح میشه
فقط ممنون میشم در حد متوسط و قابل فهم توضیح بدین
خیلی ممنون

شخصا متخصص مباحث پایگاه داده ها نیستم، ولی تا اونجایی که اطلاع دارم به این شیوه عمل می کنند :
یک تراکنش بدین صورت مشخص میشه که یک BEGIN TRAN اولش میاد
کد:
BEGIN TRAN
.
.
.
و هر چی که در ادامه بنویسید داخل بدنه تراکنش قرار می گیره و نهایتا با یکی از دو دستور COMMIT TRAN یا ROLLBACK TRAN تصمیم می گیرید که تراکنش مورد قبول و تایید بشه یا برگردونده بشه به حالت قبل از اجرای تراکنش :
کد:
BEGIN TRAN
.
.
.
COMMIT TRAN
کد:
BEGIN TRAN
.
.
.
ROLLBACK TRAN

هر زمانی که دستوری اجرا میشه، ROWCOUNT@@ تغییر می کنه، این متغیر می تونه نشون بده که آخرین دستوری که اجرا شد چند تا رکورد رو تحت پوشش قرار داده. بعضی دستورات که کاری با رکورد ندارند
این مقدار رو 0 می کنند و برخی دیگر عدد 1 رو در ROWCOUNT@@ ثبت می کنند. گاهی اوقات از این متغیر برای بررسی عملکرد دستور قبلی استفاده میشه که مشخص بشه کار درست پیش رفته یا خیر.

مثلا شما می خواهید فردی رو از جدول مشتریان حذف کنید که ممکن است قبلا خرید کرده باشد. جدول مشتریان customers است و جدول ده سفارش های مشتری orders است.
وقتی مشخصات مشتری ای را حذف می کنید اطلاعات فردی مشتری حذف می شود اما خرید ها نباید بخاطر حذف مشتری ناپدید شوند پس باید در جدول خرید ها، سفارش دهنده آن خرید ها به مشتری گمنام (شماره id ئه صفر) تغییر کند.
اگر اینکار انجام نشود و بعد مشتری جدیدی از آن id مشتری قبلی استفاده کند خرید های دو مشتری ادغامی می شوند.

طبیعتا نمی توانید تضمین کنید که این مشتری در جدول سفارش ها فلان تعداد خرید داشته اما اگر تراکنش درست انجام شود باید یک رکورد از جدول مشتریان حذف شود.
اگر چنین شد تراکنش درست و قابل قبول است وگرنه تراکنش باید بصورت کامل لغو شود، چه تغییر مشخصات سفارش ها و چه لیست مشتریان.
به سادگی فرض می کنیم که مشتری با id ئه 123 حذف می شود :
کد:
BEGIN TRAN
UPDATE orders SET customerid = 0 WHERE customerid = 123;
DELETE FROM customers WHERE customerid = 123;
IF @@ROWCOUNT = 1
    COMMIT TRAN
ELSE
    ROLLBACK TRAN

در Net Framework. کلاس SqlTransaction می تواند این کار را به شکل مشخص تری انجام دهد. یک شیء از کلاس SqlTransaction می سازید :
کد:
        SqlTransaction transaction = connection.BeginTransaction("MyTransaction");

و دستورات SQL را در اشیاء SqlCommand می نویسید :
کد:
        SqlCommand command = connection.CreateCommand();
        command.CommandText = "UPDATE orders SET customerid = 0 WHERE customerid = 123;";

و قبل از اجرا به SqlTransaction ای که ساخته اید ربط می دهید :
کد:
        command.Transaction = transaction;
        command.ExecuteNonQuery();

برای اجرا کردن دستورات بعدی نیازی به ساختن command جدید نیست، می توانید CommandText را عوض کنید و موارد جدیدی را اجرا کنید :
کد:
        command.CommandText = "DELETE FROM customers WHERE customerid = 123;";
        command.ExecuteNonQuery();

اگر کد درست اجرا شد تراکنش را تایید کنید، به یاد داشته باشید که ExecuteNonQuery تعداد سطر هایی که کوئری تحت تاثیر قرار داده رو بر می گردونه، مثلا عدد 1 را بر می گرداند :
کد:
        transaction.Commit();

و اگر نتیجه مثبت نبود لغو اش کنید :
کد:
        transaction.Rollback();
 
.
.
.
و اگر نتیجه مثبت نبود لغو اش کنید :
کد:
        transaction.Rollback();

دوست عزیز یه سوال برام پیش اومده...
اگه قطع عملیات ثبت رکوردها در دیتابیس به خاطر قطعی برق باشه، خب مشخصا عمل Rollback هم انجام نمیشه چون سیستم خاموش شده !
خب اینجوری استفاده از این کلاس بی فایده به نظر میرسه که...
 

the_king

مدیرکل انجمن
دوست عزیز یه سوال برام پیش اومده...
اگه قطع عملیات ثبت رکوردها در دیتابیس به خاطر قطعی برق باشه، خب مشخصا عمل Rollback هم انجام نمیشه چون سیستم خاموش شده !
خب اینجوری استفاده از این کلاس بی فایده به نظر میرسه که...
خیر اینطور نیست، فراموش نکنید که شما یک تراکنش تعریف می کنید که هنوز انتهاش مشخص نیست. رفتار SQL Server با اون تراکنش بر اساس همون اصل اتمیک بودن تراکنش ئه.
شما که فرمان Commit رو نداده اید، اون تراکنش مادامی که Commit نداره تاثیری روی پایگاه داده ها نمیذاره. به سادگی می توانید امتحانش کنید.
کدی رو اجرا کنید که ناقصه و به Commit یا Rollback منجر نمیشه و بعد محتویات جدول رو ببینید.
 

جدیدترین ارسال ها

بالا