PDA

View Full Version : کار با تراکنش ها



tefos666
شنبه 19 دی 1388, 16:10 عصر
سلام دوستان این کد بهم خطا میده مشکل کجاست ؟



private void InsertDates()
{

//Transaction
SqlConnection objConn = new SqlConnection(mydb.ConStr);
SqlCommand insertDataCommand = new SqlCommand();
SqlTransaction insertData_tran;
insertData_tran = null;
try
{
if (objConn.State != ConnectionState.Open)
{
objConn.Open();
}

insertData_tran = objConn.BeginTransaction();
string strSQL = string.Format("insert into tbl_dates (id_person,StartDate,EndDate values (" + txtDocumentsID.Text + "," + txtstrdate.Text + "," + txtenddate.Text + " ) where id_person='"+txtDocumentsID.Text+"'");
insertDataCommand = new SqlCommand(strSQL, objConn, insertData_tran);
insertDataCommand.ExecuteNonQuery();
insertData_tran.Commit(); ;

}
catch (Exception ex)
{
insertData_tran.Rollback();
MessageBox.Show(ex.Message, " ");
}
finally
{
objConn.Close();
}
}



میگه incorrevt syntax near keyword values

ضمنا سوال دوم ما برای select هم میتونیم از تراکنش استفاده کنیم ؟
برای رزرو شماره پرونده توسط کاربر لازم دارم کدش رو شبیه بالا نوشتم ولی اونم خطا میده ؟

مجبور شدم اینطوری بنویسم ولی توش تراکنش وجود نداره لطفا جهت تصحیح این 2 تا کد کمکم کنید



private void NewPerson()
{
SqlConnection max_Conn = new SqlConnection(mydb.ConStr);
SqlCommand FileNumCommand = new SqlCommand();
//
txtID.Text = "";
txtDocumentsID.Text = "";
txtName.Text = "";
txtFamily.Text = "";
txtFather.Text = "";
txtTelH.Text = "";
txtAddress.Text = "";
txtbirthday.Text = "";
txtBirthLocation.Text = "";
txtShSH.Text = "";
txtTelForce.Text = "";
cmbRigion.Text = "";
cmbBlood.Text = "";
txtdonedate.Text = "";
txtSodorPos.Text = "";
txtIdentification.Text = "";
txtPostalCodeH.Text = "";
cmbState.Text = "";
txtdonedate.Text = PublicEvents.FarsiDate();
try
{
mydb.Connect("");
FileNumCommand = new SqlCommand("Select ISNULL(max(cast(FileNumber as int)),0)+1 From dbo.tbl_persons", mydb.Connect(""));
string LastFileNum = FileNumCommand.ExecuteScalar().ToString();
txtDocumentsID.Text = LastFileNum;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, " ");
}
finally
{
mydb.Disconnect("");
isnew = true;
}

}

moharrami
شنبه 19 دی 1388, 16:52 عصر
اولا برا دستور insert نمیشه شرط گذاشت
شکل کلی دستور این طوریه:


insert into [table name] (fields name) values(values)

دوما چیزی رو که میخوای بگو تا بتونم کمکت کنم از کد پایینیت چیزی حالیم نشد

tefos666
شنبه 19 دی 1388, 17:27 عصر
راست میگی چه اشتباه بزرگی کرده بودم اصلا بهش دقت نکرده بودم - ممنون

در رابطه با کد دوم من یک شماره پرونده دارم که تو برنامم تو شبکه وقتی اپراتور new میکنه باید آخرین شماره پرونده رو دریافت کنه و به اون یکی اضافه کنه و نشون بده ، مشکلم اینه اگر 2نفر همزمان با هم new رو بزنن خوب سیستم باید با transaction کار کنه و باقی ماجرا .....

کلا میخوام دستور select زیر رو تو transaction انجام بدم.

saied_genius
شنبه 19 دی 1388, 17:29 عصر
پرانتز بعد از فيلد هايت رو نبستي !!

موفق باشيد

saied_genius
شنبه 19 دی 1388, 17:34 عصر
اگر منظورت از تو transaction انجام بدي اينه که يکي صبر کنه تا اون يکي کارش تمام بشه بعداً select کنه ، مي تواني از with (holdlock) استفاده کني.

مثال:

select * from table with (holdlock)

موفق باشيد.

tefos666
شنبه 19 دی 1388, 17:43 عصر
:عصبانی++:
یعنی با همین دستور ساده دیگه نیازی به نوشتن transaction نیست ؟

واقعا کامپیوتر ، مخصوصا برنامه نویسی دنیای عجیبی داره - همین باعث علاقه من به اون شده

برای رسیدن به خدا هزار تا راه وجود داره (مارمولک - پرویز پرستویی):خجالت:

saied_genius
شنبه 19 دی 1388, 17:50 عصر
حقيقتش من منظورتان را از transaction نمي دونم.
گفتم اگر منظورتان چيزي بود که من گفتم ، اين راهش است .

transaction:هرگونه داد و ستد (تراکنش) اطلاعاتي که با ديتابيس صورت مي گيرد را مي گويند transaction.

حالا لطفاً بفرماييد منظورتان از transaction چيه؟؟؟

موفق باشيد.

tefos666
شنبه 19 دی 1388, 17:54 عصر
حقیقتش من منظورتان را از transaction نمی دونم.
گفتم اگر منظورتان چیزی بود که من گفتم ، این راهش است .

transaction:هرگونه داد و ستد (تراکنش) اطلاعاتی که با دیتابیس صورت می گیرد را می گویند transaction.

حالا لطفاً بفرمایید منظورتان از transaction چیه؟؟؟

موفق باشید.

منظور من همون توقف بود - واسه اینکه دونفر همزمان یک درخواست رو به برنامه ندن که مشکل پیش بیاد.

moharrami
شنبه 19 دی 1388, 17:56 عصر
transaction برا اینکه وقتی یه سری کد دارید که باید پشت سر هم اجرا بشن باید تو یه transactionبزاریشون
مثلا تو این کد اگه دستور اول یه کد بگیره ولی بین دستور اول و دستور دوم اگه یکی دیگه یه دستور اول رو دوباره اجرا کنه اون هم همون ای دی رو میگیره در نتیجه یه نفر نمیتونه insert کنه و خطا میگیره

saied_genius
شنبه 19 دی 1388, 18:01 عصر
اگر از کدی که گفتم استفاده کنید ، چنین مشکلی پیش نمی آید. (error نمي دهد)

نفرات بعدی توی نوبت می ایستند تا دیتابیس آزاد بشود و سپس اقدام به insert می کنند.

موفق باشید.

tefos666
شنبه 19 دی 1388, 18:05 عصر
transaction برا اینکه وقتی یه سری کد دارید که باید پشت سر هم اجرا بشن باید تو یه transactionبزاریشون
مثلا تو این کد اگه دستور اول یه کد بگیره ولی بین دستور اول و دستور دوم اگه یکی دیگه یه دستور اول رو دوباره اجرا کنه اون هم همون ای دی رو میگیره در نتیجه یه نفر نمیتونه insert کنه و خطا میگیره

پس با این تفاسیر تو برنامه های بانک اطلاعاتی تحت شبکه بهتره از transaction استفاده کنم ؟ حالا برای چهار حالت باید استفاده کرد select - insert - delete - update یا فقط یکسری خاص ؟ مساله دوم الان راه حلی که دوست عزیزمون گفت مشکل منو حل میکنه ?


Select ISNULL(max(cast(FileNumber as int)),0)+1 From dbo.tbl_persons with (holdlock)

طبق نظر ایشون این دستور هم صبر میکنه و نوبت به نوبت select میکنه

saied_genius
شنبه 19 دی 1388, 18:14 عصر
استفاده از holdlock و يا هر نوع قفل ديگه روي ديتابيس ، فقط مخصوص دستور select است و در حالت هاي ديگر وجود ندارد (اصلاً نياز نمي شود ، اگر درست کد نويسي کنيد.)

با نمونه کدي که نوشتيد ، طرز کار به اين صورت است که:

اگر در زمان select شما کسي در حال وارد کردن اطلاعات (چون خودش table شما را lock مي کند) و يا select کردن اطلاعات از ديتابيس باشد ، user شما منتظر مي ماند تا کار user تمام شود ، تيبل مورد نظر آزاد شود ، سپس اقدام به select مي کند.

با اين روش ، شما ديگر دچار DeadLock معروف sql server (معمولاً در تبادلات خيلي زياد با database اتفاق مي افتد.) نمي شويد.

براي اطلاعات بيشتر :
http://www.mssqlcity.com/Articles/Adm/SQL70Locks.htm

موفق باشيد.

AliRezaPro
شنبه 19 دی 1388, 18:40 عصر
Trans[Action] مگه برای این نبود که
"وقتی می خواهیم عملیت حساسی رو بر رو ی دیتابیس انجام دهیم استفاده از Trans باعث میشود تا حاشیه اطمینان 100% شود"
؟

tefos666
شنبه 19 دی 1388, 21:25 عصر
Trans[Action] مگه برای این نبود که
"وقتی می خواهیم عملیت حساسی رو بر رو ی دیتابیس انجام دهیم استفاده از Trans باعث میشود تا حاشیه اطمینان 100% شود"
؟


دوستان من واقعا گیج شدم !!! :گریه:

یکی کمک کنه ، اصلا مفاهیم رو همه رو به کل قاطی کردم ؟ الان حرف کی رو گوش کنم ، بلاخره لطفا یکی یه مقدار فنی تر توضیح بده ، اصلا چرا از transaction استفاده میکینم ؟ استفاده اون برای چیه ؟ این چیزی که من تو سوالم مطرح کردم transaction هستش ؟ یا چیز دیگه ای.:گیج:


ضمنا نهایتا من کدم رو به این شکل تغییر دادم - ظاهرا مشکلی نداره البته هنوز نتونستم تستش کنم ، کسی میدونه چجوری میتونم همزمانی رو روش تست کنم ، یعنی تو یک زمان دونفر دکمه new رو بزنند ؟ و کد زیر اجرا بشه ببسنم خروجی صحیح کار میکنه یا نه



private void InsertDates()
{

//Transaction
SqlConnection objConn = new SqlConnection(mydb.ConStr);
SqlCommand insertDataCommand = new SqlCommand();
SqlTransaction insertData_tran;
insertData_tran = null;
try
{
if (objConn.State != ConnectionState.Open)
{
objConn.Open();
}

insertData_tran = objConn.BeginTransaction();
string strSQL = string.Format("insert into tbl_dates (id_person,StartDate,EndDate) values (" + txtDocumentsID.Text + "," + txtstrdate.Text + "," + txtenddate.Text + ")");
insertDataCommand = new SqlCommand(strSQL, objConn, insertData_tran);
insertDataCommand.ExecuteNonQuery();
insertData_tran.Commit(); ;

}
catch (Exception ex)
{
insertData_tran.Rollback();
MessageBox.Show(ex.Message, " ");
}
finally
{
objConn.Close();
}
}



اینم اون یکی کدم که با lock درست شد



private void NewPerson()
{
SqlConnection max_Conn = new SqlConnection(mydb.ConStr);
SqlCommand FileNumCommand = new SqlCommand();
//
txtID.Text = "";
txtDocumentsID.Text = "";
txtName.Text = "";
txtFamily.Text = "";
txtFather.Text = "";
txtTelH.Text = "";
txtAddress.Text = "";
txtbirthday.Text = "";
txtBirthLocation.Text = "";
txtShSH.Text = "";
txtTelForce.Text = "";
cmbRigion.Text = "";
cmbBlood.Text = "";
txtdonedate.Text = "";
txtSodorPos.Text = "";
txtIdentification.Text = "";
txtPostalCodeH.Text = "";
cmbState.Text = "";
txtdonedate.Text = PublicEvents.FarsiDate();
try
{
mydb.Connect("");
FileNumCommand = new SqlCommand("Select ISNULL(max(cast(FileNumber as int)),0)+1 From dbo.tbl_persons with (holdlock)", mydb.Connect(""));
string LastFileNum = FileNumCommand.ExecuteScalar().ToString();
txtDocumentsID.Text = LastFileNum;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, " ");
}
finally
{
mydb.Disconnect("");
isnew = true;
}

}

AliRezaPro
شنبه 19 دی 1388, 21:31 عصر
والله من اینی که میدونم اینه !:D
دستور begin Trans[Action]
در صورتی که قرار است عملیت حساس روی پایگاه داده به خصوص در زمان ذخیره سازی سازی صورت گیرد استفاده از TransAction باعث میشود حاشیه اطمینان 100% افزایش یابد و عملیاتی نظیر قطع ناگهانی برق و یا سایر موارد باعث تخریب عملیات نگردد(نظیر عملیات حساب بانکی در این حالت با اعلام begin Transaction به server اعلام میگردد که شروع فرایند حساس اغاز گردیده است
از کتاب Kaffasg_Sqlserver_book

tefos666
شنبه 19 دی 1388, 21:37 عصر
والله من اینی که میدونم اینه !:D
دستور begin Trans[Action]
در صورتی که قرار است عملیت حساس روی پایگاه داده به خصوص در زمان ذخیره سازی سازی صورت گیرد استفاده از TransAction باعث میشود حاشیه اطمینان 100% افزایش یابد و عملیاتی نظیر قطع ناگهانی برق و یا سایر موارد باعث تخریب عملیات نگردد(نظیر عملیات حساب بانکی در این حالت با اعلام begin Transaction به server اعلام میگردد که شروع فرایند حساس اغاز گردیده است
از کتاب Kaffasg_Sqlserver_book

مواقعی مثل این که من میخوام مشکل همزمانی رو رفع کنم باید چکار کنم ؟ احیانا در یک زمان 2 یا چند نفر بخواهند مثلا با فشردن یک دکمه سند جدیدی صادر کنند و شماره سند جدید معمولا آخرین شماره موجود +1 میباشد ، خوب حالا همه با هم تو یک زمان دکمه رو زدن سیستم چجوری میتونه تشخیص بده ؟ یا صبر کنه یکی 1 سند بگیره بعد نفر بعد و همینطور الی آخر وگرنه به طور یقین باید خطا بده ؟ من شنیده بودم transaction این مشکل رو حل میکنه رفتم دنبالش کدهاشم پیدا کردم حالا به نظر شما اگر برای کار دیگری هستش لطفا کمک کنید .

saied_genius
شنبه 19 دی 1388, 22:10 عصر
ببین عزیزم ...

من مشکل شما را داشتم.

در هر ثانیه دیتابیسم قرار بود 250 رکورد را اضافه کند به دیتابیس و در عین حال قبل از اضافه کردن ، چک کند تا تکراری نباشند (select with holdlock) .

راه حلی که دادم را راحت بدست نیاوردم (معما چو حل گشت ، آسان شود!!) ، برای همین مطمئنم که جواب می دهد.

مشکل شما ، در اصل مشکل نیست ، چون در یک لحظه وقتی دو نفر کلید ثبت رو فشار می دهند ، شما با یکی از select ها داری دیتابیس رو lock می کنی (حالت پیش فرض sql server) و در کاربر دومی ، منتظر آزاد شدن دیتابیس خود هستی تا select انجام شود.

trans خیلی خوبه (D:) ولی در این مورد به کار شما نمی آید.

trans اگر نتواند عملیات را انجام دهد ، به حالت قبل از trans برمی گرداند و (احتمالاً) error می دهد ، که به کار شما نمی آید ، چون مشکل شما چیز دیگری است.

لینکی هم که در پست های قبلی گذاشتم ، حالت های مختلف lock کردن رو توضیح داده است.

در مورد شبیه سازی کلیک چند کاربر هم به نظر من ، شما می توانید یک برنامه بنویسید با چند thread که به طور همزمان عملیات insert و select مورد نظر را انجام می دهند.

البته گفته باشم که زمان انتظار select برای holdlock یک مقدار معینی است و بعد از آن روال عادی را طی می کند (مثلاً خطا می دهد.) که البته قابل تنظیم است.

ولی به نظر من روش شما برای در آوردن شماره آخرین رکورد + 1 برای دادن شماره سند کار خیلی جالبی نیست.

روش های بهتر برای این کار:
1- استفاده از همان autonumber دیتابیس است
2- استفاده از GUID


سوالی بود در خدمتم.

موفق باشید.