ورود

View Full Version : همزمانی در اجرای دستورات



ali_mnkt
یک شنبه 03 خرداد 1388, 01:30 صبح
با سلام خدمت دوستان عزیز.

من یه برنامه تحت شبکه نوشتم که در جدول فاکتور برای ثبت فاکتور شماره آخرین فاکتور رو

می گیرم و یکی بهش اضافه می کنم و فاکتور جدید رو ثبت می کنم. این روش در زمانی که

client ها در بازه های زمانی مختلف عمل درج رو انجام می دن مشگلی نداره اما وقتی که

مثلا دو client همزمان بخواهند عمل درج را انجام دهند مشگل ایجاد می کنه مشگلشم واضحه

چون در آن واحد آخرین شماره فاکتور رو می گیرن و یکی اضافه می کنن و می خوان بنویسن

مشگل کلید اصلی پیش می یاد . حالا اگه من بخوام ازکنترل همزمانی در sql server 2005

استفاده کنم به صورتی که وقتی یه client روی جدولی مشغول انجام عملیاتی هست

(insert , update,delet) بقیه client های دیگه منتظر اتمام کار شوند و پس از آن کار روی آن

جدول رو انجام بدن چه کاری باید انجام بدم ؟

البته من از transaction هم استفاده کردم و isolation level اون رو هم روی serializeable

قرار دادم اما هنگام اجرا همزمان دستور insert مشگل وجود بن بست رو گرفت.

من کد زیر رو اجرا کردم



set transaction isolation level serializable
begin transation


badaneye transaction


if @@error<>0
rollback transaction
else
commit transaction

amin_alexi
یک شنبه 03 خرداد 1388, 08:44 صبح
من یه برنامه تحت شبکه نوشتم که در جدول فاکتور برای ثبت فاکتور شماره آخرین فاکتور رو

می گیرم و یکی بهش اضافه می کنم و فاکتور جدید رو ثبت می کنم. این روش در زمانی که

client ها در بازه های زمانی مختلف عمل درج رو انجام می دن مشگلی نداره اما وقتی که

مثلا دو client همزمان بخواهند عمل درج را انجام دهند مشگل ایجاد می کنه مشگلشم واضحه

چون در آن واحد آخرین شماره فاکتور رو می گیرن و یکی اضافه می کنن و می خوان بنویسن

مشگل کلید اصلی پیش می یاد .
سلام
شما می تونی از فیلد Identity استفاده کنی و بزاری SQL خودش یکی یکی اضافه کنه !

Hamid.Mayeli
یک شنبه 03 خرداد 1388, 09:12 صبح
سلام
شما می تونی از فیلد Identity استفاده کنی و بزاری SQL خودش یکی یکی اضافه کنه !

Identity کردن فیلد همه جا خوب نیست بیشتر از سر وا کردن، چون تو جدول آیتم فاکتورت باید کلید خارجی هدر رو بزاری که نداریش. بهتر لحظه درج مقدارو بگیری نه وقتی داره کار میکنه یا یه جدول داشته باشی که آخرین ID توش باشه و وقتی فاکتور باز میشه و یک ID اختصاص میشه جدولتو بروز کنی. درضمن همکاران و اقلب شرکت های بزرگ همین کارو میکنن.

linux
یک شنبه 03 خرداد 1388, 09:22 صبح
Identity کردن فیلد همه جا خوب نیست بیشتر از سر وا کردن، چون تو جدول آیتم فاکتورت باید کلید خارجی هدر رو بزاری که نداریش. بهتر لحظه درج مقدارو بگیری نه وقتی داره کار میکنه یا یه جدول داشته باشی که آخرین ID توش باشه و وقتی فاکتور باز میشه و یک ID اختصاص میشه جدولتو بروز کنی. درضمن همکاران و اقلب شرکت های بزرگ همین کارو میکنن.
این که شد همون Identity راستی اغلب درست هست

Hamid.Mayeli
یک شنبه 03 خرداد 1388, 09:25 صبح
این که شد همون Identity راستی اغلب درست هست

نه Identity لحظه درج رخ میده و از قبل به مقداره کلید دسترسی نداریم ولی تو این حالت داریم.


:بامزه: نمره پاسخ قبلیم شد 19 (اغلب) :اشتباه:

amin_alexi
یک شنبه 03 خرداد 1388, 09:49 صبح
Identity کردن فیلد همه جا خوب نیست بیشتر از سر وا کردن، چون تو جدول آیتم فاکتورت باید کلید خارجی هدر رو بزاری که نداریشحتما شما بلد نیستی استفاده کنی ولی من استفاده می کنم و دارمش !Scope_identity())(


بهتر لحظه درج مقدارو بگیری نه وقتی داره کار میکنه یا یه جدول داشته باشی که آخرین ID توش باشه و وقتی فاکتور باز میشه و یک ID اختصاص میشه جدولتو بروز کنی. درضمن همکاران و اقلب شرکت های بزرگ همین کارو میکنن.شاید حق با شما باشه !
اون هم فقط برای شماره فاکتور وقتی کاربر می خواد Auto ذخیره بشه ! نه برای فیلد کلید اصلی ...
معمولا همه 2 فیلد دارن یکی شماره فاکتور یکی هم فیلد ID یا شماره مبنا ... که شماره فاکتور رو هم کاربر می تونه وارد کنه و هم به صورت Auto باشه ...
این که من گفتم خیلی عمومیت داره هم در داخل و هم در خارج !
اما نباید این طور فکر کنید که چون خیلی از شرکتهای داخلی یک روشی رو استفاده می کنن حتما درسته !
من به علت کاری که دارم با Database خیلی از شرکتها کار کردم ... و خدا می دونه که بعضی از اونها چه فاجعه ای هستند .. البته خیلی ها شون هم دارن ارتقا میدن ... بماند ....
روش کار و طراحی Database و تعریف نوع فیلدها و نحوه ذخیره سازی به ریز سناریوی کار خیلی بستگی داره و اینکه ما چه کاری می خوایم انجام بدیم !
من خودم در بعضی از جاها از روشی که شما گفتید استفاده می کنم ولی فکر می کنم واسه ایشون استفاده از Identity و یک فیلد TimeStamp برای جدول ها شون خیلی مفیده تا بتونن دسترسی همزمان رو کنترل کنند ... و مدیریت اضافه کردن شماره رو به SQL بسپارند.

Hamid.Mayeli
یک شنبه 03 خرداد 1388, 09:59 صبح
اون هم فقط برای شماره فاکتور وقتی کاربر می خواد Auto ذخیره بشه

اگه بخواد سالانه شماره فاکتور از 1 شروع بشه چی؟ پس نمیتونه از Identity استفاده کنه. منم کارم با DataBase و با فاکتور زیاد کار میکنم و میدونم چرا بعضی از شرکتهای به قول شما


و خدا می دونه که بعضی از اونها چه فاجعه ای هستند

چرا این کارو میکنن که جاش تو این تاپیک نیست.

amin_alexi
یک شنبه 03 خرداد 1388, 10:43 صبح
اگه بخواد سالانه شماره فاکتور از 1 شروع بشه چی؟ پس نمیتونه از Identity استفاده کنه
اگه بخواد سالانه از 1 شروع کنه و این فیلد کلید اصلی باشه که نمیشه چند تا یک در یک فیلد کلید اصلی اونجاست که باید یک فیلد مثل ID یا شماره مبنا داشته باشه که اون کلید اصلی باشه ... و با شماره فاکتور هر طور که خواست رفتار کنه !

ali_mnkt
یک شنبه 03 خرداد 1388, 13:48 عصر
دوستان مرسی از توجهتون اما مثال درج یکی از مشگلات بود . مثلا در نظر بگیرید که روی یک

client یه کاربر در حال update کردن یه table باشه و در همون لحظه کاربر دیگه در یه client

دیگه مشغول select روی همون جدول باشه که مسلما با مشگل خواندن داده نادرست مواجه

می شه. من فکر کنم بهترین راه برای مقابله با این چنین مشگلاتی استفاده از سطح های

مختلف ایزوله سازی است که مثلا هر کاربری که روی یک جدول مشغول عملیاتی باشه

(select , update , insert) اون جدول قفل بشه و تا اتمام کار . کاربر دیگه نتونه به اون جدول

دسترسی داشته باشه.

کسی می تونه کمکی در این زمینه کنه ؟

Hamid.Mayeli
یک شنبه 03 خرداد 1388, 14:07 عصر
Amin_alexi غزیز
اینو شما گفتی این طور نیست

شاید حق با شما باشه !
اون هم فقط برای شماره فاکتور وقتی کاربر می خواد Auto ذخیره بشه ! نه برای فیلد کلید اصلی ...
معمولا همه 2 فیلد دارن یکی شماره فاکتور یکی هم فیلد ID یا شماره مبنا ... که شماره فاکتور رو هم کاربر می تونه وارد کنه و هم به صورت Auto باشه ...

پس این چیه


اگه بخواد سالانه از 1 شروع کنه و این فیلد کلید اصلی باشه که نمیشه چند تا یک در یک فیلد کلید اصلی اونجاست که باید یک فیلد مثل ID یا شماره مبنا داشته باشه که اون کلید اصلی باشه ... و با شماره فاکتور هر طور که خواست رفتار کنه !

Hamid.Mayeli
یک شنبه 03 خرداد 1388, 14:11 عصر
دوستان مرسی از توجهتون اما مثال درج یکی از مشگلات بود . مثلا در نظر بگیرید که روی یک

client یه کاربر در حال update کردن یه table باشه و در همون لحظه کاربر دیگه در یه client

دیگه مشغول select روی همون جدول باشه که مسلما با مشگل خواندن داده نادرست مواجه

می شه. من فکر کنم بهترین راه برای مقابله با این چنین مشگلاتی استفاده از سطح های

مختلف ایزوله سازی است که مثلا هر کاربری که روی یک جدول مشغول عملیاتی باشه

(select , update , insert) اون جدول قفل بشه و تا اتمام کار . کاربر دیگه نتونه به اون جدول

دسترسی داشته باشه.

کسی می تونه کمکی در این زمینه کنه ؟


یه TempTable بساز شناسه سند در حال ویرایش رو توش نگه دار به بقیه اجازه نده سند رو ویرایش کنن.

esmaeily-hosein
یک شنبه 03 خرداد 1388, 15:25 عصر
مثلا هر کاربری که روی یک جدول مشغول عملیاتی باشه

(select , update , insert) اون جدول قفل بشه و تا اتمام کار . کاربر دیگه نتونه به اون جدول

دسترسی داشته باشه.

توی این روش دیگه هیشکی نمیتونه کار کنه !
معمولا برای جلوگیری از concurrency خود ماکروسافت از روش Original Record استفاده میکنه یه سری هم time span میزارن و یه چند تا روش دیگه هم هست .
ولی به نظر من original record از همه بهتره .
یعنی قبل از به روز رسانی مقدار original با مقدار فعلی چک میکنند اگر برابر بود که هیچی و اگرنه به کاربر پیغام میدن داده هات قدیمی و برو بروز رسانی کن .

Hamid.Mayeli
یک شنبه 03 خرداد 1388, 16:14 عصر
توی این روش دیگه هیشکی نمیتونه کار کنه !
معمولا برای جلوگیری از concurrency خود ماکروسافت از روش Original Record استفاده میکنه یه سری هم time span میزارن و یه چند تا روش دیگه هم هست .
ولی به نظر من original record از همه بهتره .
یعنی قبل از به روز رسانی مقدار original با مقدار فعلی چک میکنند اگر برابر بود که هیچی و اگرنه به کاربر پیغام میدن داده هات قدیمی و برو بروز رسانی کن .

من گفتم آدی سند رو بگیره و فقط اون سند رو قفل کنه نه کله جدول رو.

و به نظر من بهتر که دونفر رو یه سند کار نکنن چون اطلاعات یکی شون میپره و بین کاربرا حرف پیش میاد و در نهایت به برنامت بد بین میشن. اینو تجربه ثابت کرده.:خجالت::خجالت::خجالت::شی طان::شیطان:

esmaeily-hosein
یک شنبه 03 خرداد 1388, 16:28 عصر
چطور میشه یک رکوردو قفل کنی (در صورت امکان منطقی اصلا هست )!

ali_mnkt
یک شنبه 03 خرداد 1388, 21:07 عصر
توی این روش دیگه هیشکی نمیتونه کار کنه !
معمولا برای جلوگیری از concurrency خود ماکروسافت از روش Original Record استفاده میکنه یه سری هم time span میزارن و یه چند تا روش دیگه هم هست .
ولی به نظر من original record از همه بهتره .
یعنی قبل از به روز رسانی مقدار original با مقدار فعلی چک میکنند اگر برابر بود که هیچی و اگرنه به کاربر پیغام میدن داده هات قدیمی و برو بروز رسانی کن .

دوست عزیز شما با orginal Record کار کردی ونتیجه اش رو دیدی ؟ می شه یکم در موردش

توضیح بدی و یا یه کد نمونه بذاری ؟

ali_mnkt
دوشنبه 04 خرداد 1388, 00:43 صبح
دوستان من در شبیه سازی همزمانی یه مشگل کوچولو دارم:

یه transaction به صورت زیر در managment studio به صورت زیر می نویسم :


set Transaction Isolation Level serializable;
begin tran;
update customer set id=13
where id=12


حلا یکی دیگه هم به صورت زیر اضافه می کنم :



begin tran
insert into customer(id,price) values(12,1000)

حالا کد اول رو اجرا می کنم و بعد کد دوم رو اما می بینم که کد دوم اجرا می شه در صورتی

که چون در کد اول من از isolation level serializable استفاده کردم و هنوز تکلیف commit

یا rollback شدن اون مشخص نشده قاعدتا باید کد دوم به wait برود . اما چرا نمی ره ؟

Hamid.Mayeli
دوشنبه 04 خرداد 1388, 09:13 صبح
چطور میشه یک رکوردو قفل کنی (در صورت امکان منطقی اصلا هست )!


بله منطقی هست، SQL راهی نمیشناسم ولی تو برنامه نمیزاری تغییر بده.

esmaeily-hosein
دوشنبه 04 خرداد 1388, 10:21 صبح
SQL راهی نمیشناسم ولی تو برنامه نمیزاری تغییر بده.
چطور میشه تو یه برنامه تحت Server اینو سمت client کنترل کرد .



دوست عزیز شما با orginal Record کار کردی ونتیجه اش رو دیدی ؟ می شه یکم در موردش

توضیح بدی و یا یه کد نمونه بذاری ؟

نمونه کد تولید شده با استفاده از Type Data Set :


ALTER PROCEDURE [dbo].[sp_Country_Update]
(
@Name nvarchar(50),
@Description nvarchar(200),
@Image image,
@Original_ID int,
@IsNull_Name nvarchar(50),
@Original_Name nvarchar(50),
@IsNull_Description nvarchar(max),
@Original_Description nvarchar(max),
@ID int
)
--WITH ENCRYPTION
AS
SET NOCOUNT OFF;
UPDATE [Country] SET
[Name] = @Name,
[Description] = @Description,
[Image] = @Image
WHERE (([ID] = @Original_ID) AND ((@IsNull_Name = 1 AND [Name] IS NULL) OR ([Name] = @Original_Name)));

SELECT * FROM v_Country WHERE (ID = @ID)

Hamid.Mayeli
دوشنبه 04 خرداد 1388, 10:40 صبح
SELECT * FROM v_Country WHERE (ID = @ID)

به جای این کد بهتره از

Select @@RowCount

استفاده کنید.


چطور میشه تو یه برنامه تحت Server اینو سمت client کنترل کرد .

تو برنامه وقتی میخواد ویرایش کنه یه Select از TempTable میزنید اگه با ID مورد نظر Row وجود داشت میگی سند در حال ویرایش است و امکان تغییر سند و جود ندارد.

majid_afra222
دوشنبه 04 خرداد 1388, 23:55 عصر
سلام
برای رفع اینگونه موارد باید جدول رو برای یک لحظه بسیار کوتاه یعنی زمان پیدا کردن شماره آخرین سند و ثبت شماره سند جدید قفل کنید، در این لجظه یعنی پیدا کردن شماره آخر و درج شماره جدید، تمامی تراکنشها درحالت wait باقی میمونن و بعد از آزاد سازی جدول به کارشون ادامه میدن بدون اینکه توی کارایی سیستم هیچ خللی وارد بشه.
من این روش رو برای سندها و شماره های نامه (صادره، وارده و داخلی و ....) تو چندین سازمان با تعداد بالای همزمانی ورود اطلاعات بکار بردم، 100% هم شماره های بدست آمده unique هستش.
اگه دوستان خواستند میتونم اینکار رو براشون انجام بدم.

Hamid.Mayeli
سه شنبه 05 خرداد 1388, 09:13 صبح
سلام
برای رفع اینگونه موارد باید جدول رو برای یک لحظه بسیار کوتاه یعنی زمان پیدا کردن شماره آخرین سند و ثبت شماره سند جدید قفل کنید، در این لجظه یعنی پیدا کردن شماره آخر و درج شماره جدید، تمامی تراکنشها درحالت wait باقی میمونن و بعد از آزاد سازی جدول به کارشون ادامه میدن بدون اینکه توی کارایی سیستم هیچ خللی وارد بشه.
من این روش رو برای سندها و شماره های نامه (صادره، وارده و داخلی و ....) تو چندین سازمان با تعداد بالای همزمانی ورود اطلاعات بکار بردم، 100% هم شماره های بدست آمده unique هستش.
اگه دوستان خواستند میتونم اینکار رو براشون انجام بدم.


نه اینو همه میدونستیم ولی اگه بخواهی جدول روقفل کنی تا کاربر دیتا وارد کنه ممکن یه روز قفل بمونه پس کارایی نداره.
اگه شماره رو لحظه اخر بخواهیم پر کنیم بله حق با شماست.:چشمک:

mohsen_csharp
سه شنبه 05 خرداد 1388, 11:30 صبح
دوستان نمی شه به جای این همه دردسر از SQL notification استفاده کرد؟
اگر کلاینتی یک جدول را تغییر داد اونوقت بقیه کلاینت ها ازش آگاه بشن و خودشونو به روز کنند.

majid_afra222
سه شنبه 05 خرداد 1388, 21:57 عصر
نه اینو همه میدونستیم ولی اگه بخواهی جدول روقفل کنی تا کاربر دیتا وارد کنه ممکن یه روز قفل بمونه پس کارایی نداره.
اگه شماره رو لحظه اخر بخواهیم پر کنیم بله حق با شماست.:چشمک:

سلام
انگار منظور بنده رو متوجه نشدید.
نحوه کار شما برای قفل کردن جدول چی هستش.

antisocial
سه شنبه 05 خرداد 1388, 22:55 عصر
SQL به طور خودکار از قفل ها استفاده میکنه
برای اطلاعات راجع به قفلها ازین رویه استفاده کنید
exec sp_lock
و یا در MSDN این رو تایپ کنید
SP_LOCK
به طور کلی در تراکنش ها میتونین از 5 نوع قفل استفاده کنین که هرکدوم یک جا کاربرد داره و توضیحاتش خیلی طولانیه
در مورد سوال اول هم سطوح ایزولاسیون هیچ کاربردی تو این مورد نداره چون اونا برای یک لحظه اتفاق می افتن
در ضمن شما اول شماره فاکتور رو میگیرین و اونو به کاربر نشون میدین؟ یا بعد از ثبت، کاربر شماره فاکتور رو میبینه؟

ali_mnkt
چهارشنبه 06 خرداد 1388, 01:09 صبح
SQL به طور خودکار از قفل ها استفاده میکنه
برای اطلاعات راجع به قفلها ازین رویه استفاده کنید
exec sp_lock
و یا در MSDN این رو تایپ کنید
SP_LOCK
به طور کلی در تراکنش ها میتونین از 5 نوع قفل استفاده کنین که هرکدوم یک جا کاربرد داره و توضیحاتش خیلی طولانیه
در مورد سوال اول هم سطوح ایزولاسیون هیچ کاربردی تو این مورد نداره چون اونا برای یک لحظه اتفاق می افتن
در ضمن شما اول شماره فاکتور رو میگیرین و اونو به کاربر نشون میدین؟ یا بعد از ثبت، کاربر شماره فاکتور رو میبینه؟

بعد از ثبت کاربر شماره فاکتور رو می بینه