PDA

View Full Version : جلوگیری از ورود اطلاعات نا معتبر در Database از طریق Sql Transaction (بخش اول)



Sayehzendeh
یک شنبه 10 تیر 1386, 14:41 عصر
جلوگیری از ورود اطلاعات نا معتبر در Database از طریق Sql Transaction (بخش اول)

مقدمه :
با توجه به اینکه امروزه ( به دلیل حجم گسترده ی اطلاعات )، Database یکی از ارکان اصلی هر نرم افزار است، رفته رفته نیاز به مدیریت اطلاعات درون آن، بیشتر از پیش احساس می شود. یکی از جنبه های این مدیریت، جلوگیری از ورود اطلاعات نامعتبر به Database است، که امروزه حتی در نرم افزار های کاربردی و خانگی مورد نیاز است.
فرض کنید در حال تولید نرم افزاری هستید ( Windows Application ، Web Application و یا Network Application ) که در آن هنگام ایجاد Profile برای کاربر جدید، علاوه بر ورود مشخصات او به یک جدول عمومی ( مثل tblUser ) ، یک جدول اطلاعات مجزا برای او تشکیل می دهید. اگر برنامه در هنگام ارتباط با Database دچار مشکل شود، و یا به هر دلیلی ارتباط قطع گردد، این عمل انجام نخواهد شد. با این همه در صورتی که در همان ابتدای امر مشکل ایجاد شود، می توانید با یک پیغام از کاربر بخواهید که دوباره عمل ثبت نام را انجام دهد. ولی مشکل اصلی زمانی است که در میان عمل ثبت نام، برنامه با مشکل روبرو شود، در این صورت مثلا مشخصات کاربر به جدول tblUser وارد می شود، ولی جدول مجزای کاربر ایجاد نمی شود. در این حالت برنامه ی شما (هر چقدر هم که منظم و بدون عیب ایجاد شده باشد ) دچار مشکل خواهد شد. مشکلی که از نظر کاربر از برنامه نویسی شما ناشی می شود. البته تا حدودی هم حق با اوست، چون کاربر نه می تواند دوباره اطلاعاتش را وارد کند، و نه می تواند با Profile که برای او به صورت ناقص ساخته شده است، با نرم افزار کار کند. در این صورت است که نرم افزار تولید شده توسط شما، دارای برچسب عدم اطمینان خواهد شد.
این تنها یک مثال بود، در صورتی که این اتفاق ممکن است برای هر نرم افزاری که با پایگاه داده سرو کار دارد، رخ دهد. برای جلوگیری از بروز این گونه اشکالات، در زبان T-SQL که زبان مورد استفاده در MS SQL هم هست، دستور Transaction گنجانده شده است. این دستور پیچیدگی هایی برای یک برنامه نویس به همراه دارد، و از آنجا که هدف NET Framework. ایجاد پلتفرمی ساده تر از پیش برای برنامه نویسان بود، در NET. سه راه حل کلی برای اینکار ارائه شده است. پیاده سازی هر کدام از این روش ها با ۳ تا ۵ خط کد انجام می شود. به همین خاطر توصیه شده است، برای تمامی دستوراتی که اطلاعات Database را تغییر می دهند ( از جمله Insert ، Update ، Delete و حتی Create Table و Drop Table )، از Sql Transaction استفاده شود، اعم از اینکه احتمال بروز خطا بالا است یا کمتر از % 0.1 است. فراموش نکنید که یکی از دلایل موفقیت یک نرم افزار، بدون عیب بودن ( در دنیای واقعیت: داشتن حداقل تعداد عیب ) آن است.

نکاتی که قبل از شروع مقاله باید به آنها دقت کنید :
برای بهره برداری کامل از این مقاله، نیاز به مهارت های زیر دارید:
· داشتن علم مقدماتی SQL Server
آشنایی ابتدایی به یکی از زبان های NET. (البته برنامه های این مقاله به زبان VB.NET نوشته شده است، ولی با توجه به اینکه فهم توابع و متدهای به کار برده شده، برای درک کامل کد و ترجمه آن به هر زبان دیگری از جمله #C و J# کافی می باشد، برای درک کامل این مقاله، آشنایی مقدماتی به هرکدام از زبان های NET. برای شما کافی است.)
نکته: هر کدام از روش های ارائه شده، (در بیش از 95% مواقع) به تنهایی جوابگوی این مسئله خواهند بود. با این همه ابتدا هر سه روش را مطالعه کرده، و سپس با توجه به ویژگی های هر کدام، روش مورد استفاده ی خود را انتخاب کنید.


پیاده سازی و استفاده از Sql Transaction :
سه روش معمول برای پیاده سازی Sql Transaction وجود دارد:
۱ - استفاده از کلاس TransactionScope ( ساده ترین روش )
۲- استفاده از کلاس CommittableTransaction ( پر کاربرد ترین روش )
۳ - استفاده از کلاس SqlTransaction ( پر امکانات ترین روش )

روش اول – مدیریت اطلاعات را به NET Framework. واگذار کنید :
کلاس: TransactionScope
مشخصه ی بارز: ساده ترین روش
در این روش همان طور که از نام کلاس آن مشخص است، شما یک محدوده ی Transaction مشخص می کنید و سایر کارها توسط خود NET. انجام می شود.
کلاس TransactionScope در فضای نامی System.Transactions قرار دارد، به طور پیش فرض ارجاعی به فایل system.transactions.dll وجود ندارد، پس شما باید ابتدا یک ارجاع به فایل system.transactions.dll ایجاد کنید، تا بتوانید فضای نامی System.Transactions را به برنامه Imports کنید. (نحوه ی افزودن ارجاع به فایل، در پایان مقاله توضح داده شده است.)


System.Transactions

اکنون باید یک شی از کلاس TransactionScope ایجاد کنید:



sqlTransaction1 As New TransactionScope

از همان لحظه ای که یک شی ( توسط کلمه ی کلیدی New ) از کلاس TransactionScope ایجاد می گردد، محدوده ی Transaction شروع می شود. حال باید اتمام محدوده را هم مشخص کنید، برای اینکار از متد Complete از شی استفاده کنید:



sqlTransaction1.Complete()

اتمام محدوده معمولا به عنوان آخرین دستور ( قبل از آزاد سازی حافظه ) در تابع یا سابروتین نوشته می شود. البته می دانیم که در .NET خود Garbage Collection، آزاد سازی حافظه را انجام می دهد، ولی توصیه می شود، برای نگهداری کد در محدوده ی مهندسی نرم افزار، آزاد سازی های اشیاء ایجاد شده به صورت دستی انجام شود. حتی به غیر از این مسئله، آزادسازی شی TransactionScope در کاربرد های تخصصی تر یک امر الزامی است، وگرنه کار مذکور به صورت ناقص انجام خواهد شد. با این تفاسیر، توصیه می شود همیشه آزاد سازی را به صورت دستی ( با فراخوانی متد Dispose ) انجام دهید.
مثال: کد زیر سابروتینی را نشان می دهد، که یک رکورد به جدول اضافه می کند. در این سابروتین از کلاس TransactionScope برای عمل Transaction استفاده شده است:

http://www.persiadevelopers.com/images/articles/sqlTransaction/New%20Picture.jpg
در این سابروتین، برنامه ابتدا یک شی TransactionScope ایجاد می کند، سپس عملیات درج در جدول را انجام می دهد، و در پایان متد Complete شی را فراخوانی می کند. در صورتی که خطایی رخ ندهد، اجرای سابروتین پس از درج، با موفقیت به پایان می رسد، در غیر این صورت اگر در ساختار Try... Catch... End Try ( تنها جایی که امکان بروز خطا وجود دارد ) خطایی رخ دهد، اجرای برنامه، قبل از فراخوانی متد Complete از شی TransactionScope ، به داخل Catch منتقل می شود و در نتیجه متد Complete فراخوانی نشده و تمامی تغییرات Database ( از آغاز محدوده ی TransactionScope تا اینجا ) ، به صورت خودکار نادیده گرفته می شود و Database به حالتی که قبل از اجرای سابروتین AddToTable داشته، باز می گردد.

روش دوم – بدون پیچیدگی، عمل مدیریت اطلاعات را شخصا" انجام دهید :
کلاس: CommittableTransaction
مشخصه ی بارز: پر کاربرد ترین روش
کلاس CommittableTransaction در فضای نامی System.Transactions قرار دارد، به طور پیش فرض ارجاعی به فایل system.transactions.dll وجود ندارد، پس شما باید ابتدا یک ارجاع به فایل system.transactions.dll ایجاد کنید، تا بتوانید فضای نامی System.Transactions را به برنامه Imports کنید. (نحوه ی افزودن ارجاع به فایل، در پایان مقاله توضح داده شده است.)
نکته: در صورتی که روش قبل را در پروژه ای پیاده سازی کرده اید، نیازی به افزودن دوباره ی ارجاع برای همان پروژه نیست.

System.Transactions


اکنون باید یک شی از کلاس CommittableTransaction ایجاد کنید:



sqlTransaction1 As New CommittableTransaction


همچنین باید بعد از باز کردن مسیر ارتباط با Database ( دستور ()sqlConnection1.Open ) ، شی CommittableTransaction را به عنوان پارامتر به متد EnlistTransaction از شی sqlConnection1 ارسال کنید، تا Transaction بر روی این ارتباط، از همین لحظه آغاز شود.



sqlConnection1.EnlistTransaction(sqlTransaction1)


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



sqlTransaction1.Rollback()


و در صورت اجرای موفقیت آمیز دستورات، لازم است متد Commit از شی را ( برای اعمال تغییرات در Database ) فراخوانی کنید:



sqlTransaction1.Commit()


جایگذاری این دستورات توسط شما و طبق صلاحدید شما انجام می پذیرد، ولی به عنوان یک استاندارد تعریف نشده، فراخوانی متد Commit بلافاصله قبل از بستن ارتباط، و فراخوانی متد Rollback در قسمت Catch شده، قرار می گیرد.
نکته: توجه داشته باشید که نمی توانید قبل از ارسال شی به ارتباط باز شده، عمل Commit و یا Rollback را انجام دهید، ولی قرار دادن آنها پس از بستن ارتباط، مشکلی ایجاد نمی کند.
مثال: کد زیر سابروتینی را نشان می دهد، که یک رکورد به جدول اضافه می کند. در این سابروتین از کلاس CommittableTransaction برای عمل Transaction استفاده شده است:

http://www.persiadevelopers.com/images/articles/sqlTransaction/New%20Picture%20(1).jpg
در این سابروتین، برنامه ابتدا یک شی CommittableTransaction ایجاد می کند، و بعد از باز کردن ارتباط، شی CommittableTransaction را به عنوان Transaction کمکی به شی sqlConnection1 ارسال می کند. سپس عملیات درج در جدول را انجام می دهد. در پایان در صورتی که خطایی رخ ندهد، متد Commit فراخوانی شده و تغییرات در Database ثبت می شوند و اجرای برنامه پس از درج، با موفقیت به پایان می رسد. در غیر این صورت، اگر در ساختار Try... Catch... End Try خطایی رخ دهد، اجرای برنامه، قبل از فراخوانی متد Commit از شی CommittableTransaction ، به داخل Catch منتقل می شود و در نتیجه متد Commit فراخوانی نشده و در عوض متد Rollback فراخوانی می شود. این متد ( برخلاف روش اول )، صراحتا تمامی تغییرات Database ( از ارسال شی CommittableTransaction به ارتباط، تا اینجا ) نادیده گرفته می شود و Database به حالتی که قبل از اجرای سابروتین AddToTable داشته، باز می گردد.

نکته: در صورتی که تنها با Database های کوچک و متوسط سرو کار دارید، و یا تجربه ی زیادی در کار با پایگاه داده ندارید و یا حتی از کد های پیچیده خوشتان نمی آید، روش سوم را فاکتور بگیرید، و از خواندن آن صرف نظر کنید، چون به دلیل پیچیدگی بیشتر نسبت به دو روش قبل، باعث گیج شدن شما خواهد شد. توصیه می کنم در صورتی که این شرایط برای شما صدق می کند، به انتهای مقاله (در بخش دوم ) بروید و با توضیحی که در آنجا آمده است، یکی از دو روش اول را جهت استفاده، انتخاب کنید.

برای افزودن یک ارجاع به فایل system.transactions.dll مراحل زیر را انجام دهید:
از منوی Project آخرین گزینه را انتخاب کنید، تا صفحه ی Project Properties باز شود. در تب References بر روی دکمه ی ...Add کلیک کنید، تا صفحه ی Add References باز شود. در این صفحه در تب اول ( NET. )، به دنبال System.Transactions بگردید، آن را انتخاب کنید و بر روی دکمه ی OK کلیک کنید.
در این لحظه یک ارجاع به فایل system.transactions.dll ایجاد می شود. پروژه را توسط گزینه ی SaveAll از منوی File ذخیره کرده و صفحه ی Project Properties را ببندید.

سخن پایانی :
از اینکه تا اینجا با من همراه بودید، کمال تشکر را دارم.
با توجه به حجم گستره، این مطلب در دو مقاله قرار گرفت که روش های اول و دوم در این بخش ارائه شدند، و روش سوم ( که پیچیده ترین و تخصصی ترین روش است ) در بخش بعدی ارائه می شود. در بخش بعدی همینطور مقایسه بین این سه روش انجام می گیرد و اینکه کدام را به عنوان روش شخصی انتخاب کنیم. البته برای استفاده ، اطلاعاتی که تا این لحظه کسب کرده اید، کافی است و می توانید برنامه تان را با قابلیت Transaction بنویسید، با این همه در مقاله ی بعد، راه دیگری هم توضیح داده می شود.
بحث در مورد Sql Transaction به این سه روش ختم نمی شود، بلکه هم روش های دیگری وجود دارند و هم هر روش جزئیات وسیعی را شامل می شود. با این همه به ارائه ی این سه روش اکتفا می کنم، بقیه ی مطالب را ( در صورتی که به آن احساس علاقه می کنید ) می توانید در MSDN دنبال کنید، هر چند در صورت ایجاد هر گونه ابهام و یا سوالی در مورد سایر روش ها، بنده در حد توان در خدمت دوستان هستم.

M-Gheibi
یک شنبه 10 تیر 1386, 15:32 عصر
ذکر منبع مقالاتی که از محل دیگری برداشت شده الزامیست !
منبع این مطلب : http://www.persiadevelopers.com/articles/sql-transaction.aspx