PDA

View Full Version : سوال: commit کردن موقت transaction



ozzy_mra
سه شنبه 29 آذر 1390, 11:30 صبح
با سلام
من تو یه حلقه foreach دارم یه دستور اینزرت رو به کمک تراکنش اجرا می کنم ، می خوام اگه عملیات مورد نظرم برای تمام عناصر حلقه انجام بشه تراکنش commit بشه ولی برنامه برای عنصر دوم حلقم هنگ میکنه چون قبلی commit kani
می خواستن بدونم راهی هست که تراکنش رو به صورت موقت commit کنه و در صورتی که تمام عناصر حلقه با موفقیت commit موقت شد کل تراکنش commit بشه؟

ozzy_mra
چهارشنبه 30 آذر 1390, 07:49 صبح
اصلاً برای این کار که میگم چه راهی رو پیشنهاد می کنید؟
من یه دیتا تیبل دارم که با یک سری از اطلاعات کاربر که ورود اطلاعات شده پر شده، قراره این دیتا تیبل با بارسی شرایط خاصی در دیتا بیس ذخیره بشه . برای این کار من اونو به یه حلقه foreach پاس می دم که برای هر سطر یه شرطی رو کنترل کنه و این شرط ایطور چک میشه که یه مقدار خاص از دیتابیس گرفته میشه با مقداری که من دارم کنترل میشه اگه شرایط ok بود در دیتا بیس ذخیره میشه ولی اگر برای یه سطر این شرط برقرار نباشه تمام مقادیری که در دیتابیس نوشته شده باید rollback بشه و شرط commit شدن اینه که تمام سطر ها بدون مشکل و با برقرار بودن شرط کنترل شده تو دیتا بیس ذخیره بشند
من خوده از sqlTransaction استفاده کردم ولی برای سطر دوم به بعد چون وضعیت تراکنش مشخص نیست یعنی نه commit شده و نه rollback شده سیستم هنگ میکنه (که حق داره!)
نمی دونم دیگه چکار کنم خودم یه راه حل به ذهنم رسید که تو یه لیست ID سطر و مقداری که تغییر کرده رو ذخیره کنم و هر وقت شرط برقرار نشد دوباره به مقداری که اضافه کردم همونو کم کنم ولی راه حل خوبی نیست.
لطفاً اگه پیشنهادی دارید راهنماییم کنید

mehdi.mousavi
چهارشنبه 30 آذر 1390, 11:33 صبح
سلام.
کاش کدتون رو میذاشتید تا ببینم چطور کد رو نوشته اید. به کد زیر دقت کنید:


using (SqlConnection connection = new SqlConnection(cnnStr))
{
connection.Open();
using (SqlTransaction trans = connection.BeginTransaction())
{
for (int i = 0; i < 5; i++)
{
string sql = "INSERT INTO myTable(\"Name\") VALUES(@Name)";
using (SqlCommand command = new SqlCommand(sql, connection, trans))
{
command.Parameters.Add("Name", SqlDbType.NVarChar, 20).Value = i == 3 ? (object)DBNull.Value : i.ToString();
command.ExecuteNonQuery();
}
}

trans.Commit();
}
}


اینجا، من در یک حلقه، Insert های مورد نظر رو انجام میدم، و از قصد کاری کرده ام که وقتی i==3 بود، مقدار NULL در فیلد ذخیره بشه. فرض می کنیم فیلد هم Nullable نیست. در نتیجه، اینجا Exception ای Throw میشه و چون Transaction کامیت نشده، کل Insert های انجام شده بطور خودکار Rollback میشه. در نتیجه، هیچ Row ای در بانک ذخیره نمیشه. اگر کد فوق مشکلتون رو حل نکرد، لطفا کدی که نوشته ای رو همینجا ضمیمه کنید تا ببینم مشکل چیه.

موفق باشید.

ozzy_mra
چهارشنبه 30 آذر 1390, 12:24 عصر
اون sp هم که نوشتم اینه
یه نگاهی لطفاً بهش بندازید.
میتونم اینو جایگزین کد های بالا کنم؟

create procedure insertArticle(
@articles dbo.artikleInfo readonly,
@InsertUser decimal(18,3),
@sanadID bigint)
as
declare @kolcode nvarchar(200),@moinCode nvarchar(200),@tafCode nvarchar(200),@jozCode nvarchar(200),@sharh nvarchar(500)
declare @bed bigint,@bes bigint
declare @sarfaslId int,@mahiat int
declare @jambed bigint,@jambes bigint
declare @errorSTR nvarchar(500)
declare @Error int
--------------------------------------------------
begin tran tran1
declare @loopCnt int
select @loopCnt=MAX(id) from @articles
declare @i int
set @i=1
while @i <= @loopCnt
begin
select @kolcode=koleKode,@moinCode=moinKode,@tafCode=tafK ode,@jozCode=jozKode,@sharh=sharhArt,@bed=bedArt,@ bes=BesArt
from @articles
where id=@i

set @Error=@@ERROR
if @Error<>0
begin
goto done
end
/*کنترل سرفصل ابتدا استخراج کلید اصلی سرفصل*/
-----------------------------------------------
if @jozCode=''
begin
SELECT @jambed=utblSarfasl.jamBed,@jambed=utblSarfasl.jam Bes,@mahiat=utblMahiat.MahiatSN,@sarfaslId=utblSar fasl.SarfaslSN FROM utblMahiat INNER JOIN utblKol ON utblMahiat.MahiatSN = utblKol.MahiatID INNER JOIN utblSarfasl ON utblKol.KolSN = utblSarfasl.KolID INNER JOIN utblMoin ON utblSarfasl.MoinID = utblMoin.MoinSN INNER JOIN utblTafzili ON utblSarfasl.tafziliID = utblTafzili.TafziliSN where utblKol.KolCode=@kolcode and utblmoin.MoinCode=@moinCode and utblTafzili.TafziliCode=@tafCode and utblsarfasl.jozid=-1
end
else
begin
SELECT @jambed=utblSarfasl.jamBed,@jambed=utblSarfasl.jam Bes,@mahiat=utblMahiat.MahiatSN,@sarfaslId=utblSar fasl.SarfaslSN FROM utblMahiat INNER JOIN utblKol ON utblMahiat.MahiatSN = utblKol.MahiatID INNER JOIN utblSarfasl ON utblKol.KolSN = utblSarfasl.KolID INNER JOIN utblMoin ON utblSarfasl.MoinID = utblMoin.MoinSN INNER JOIN utblTafzili ON utblSarfasl.tafziliID = utblTafzili.TafziliSN INNER JOIN utblJoz ON utblSarfasl.JozID = utblJoz.JozSN where utblKol.KolCode=@kolcode and utblmoin.MoinCode=@moinCode and utblTafzili.TafziliCode=@tafCode and utblJoz.JozCode=@jozCode
end

set @Error=@@ERROR
if @Error<>0
begin
goto done
end
-----------------------------------------------
/*********************************[کنترل میزان بدهکار و بستانکار با ماهیت سرفصل]**********************/
-----------------------------------------------
set @jambed=0
set @jambes=0
declare @prevbed nvarchar , @prevbes nvarchar
set @prevbed=@jambed
set @prevbes=@jambes
set @jambed=@jambed + @bed
set @jambes=@jambes+@bes
---------کنترل با ماهیت-----------------
if @mahiat=3
begin
if @jambed < @jambes
begin
raiserror('سرفصل بستانکار می شود مشخصات سرفصل کد کل : @a \n و کدمعین : @b \n و کد تفضیلی : @c \n و کد جز : @d \n جمع بدهکار : @e \n و جمع بستانکار : @f',1,1,@kolCode,@moinCode,@tafCode,@jozCode,@prev bed,@prevBes)
goto done
end
end
if @mahiat=4
begin
if @jambed > @jambes
begin
raiserror('سرفصل بدهکار می شود مشخصات سرفصل کد کل : @a \n و کدمعین : @b \n و کد تفضیلی : @c \n و کد جز : @d \n جمع بدهکار : @e \n و جمع بستانکار : @f',1,1,@kolCode,@moinCode,@tafCode,@jozCode,@prev bed,@prevBes)
goto done
end
end
----------------------------------آپدیت جمع بد و بس سرفصل ها-------------------
update utblSarfasl set jamBed=@jambed , jamBes=@jambes where SarfaslSN=@sarfaslId
set @Error=@@ERROR
if @Error<>0
begin
goto done
end

/*------------------------------------ذخیره آرتیکل ها----------------------------*/
insert into utblGardeshSanad (SanadID,SarfaslID,GardeshSharh,GardeshBed,Gardesh Bes,InsertDate,InsertUser,TarikheBarge,ShomareBarg e)
values
(@sanadID,@SarfaslID,@sharh,@bed,@bes,GETDATE(),@I nsertUser,null,null)

set @Error=@@ERROR
if @Error<>0
begin
goto done
end

set @i=@i+1
end
------------end of loop1
commit tran tran1


done:
rollback tran tran1

ozzy_mra
چهارشنبه 30 آذر 1390, 13:38 عصر
برای استفاده از sp بالا من تو sql یه type تعریف کردم به شکل زیر

CREATE TYPE [dbo].[artikleInfo] AS TABLE(
[id] [int] NOT NULL,
[koleKode] [nvarchar](200) NULL,
[moinKode] [nvarchar](200) NULL,
[tafKode] [nvarchar](200) NULL,
[jozKode] [nvarchar](200) NULL,
[sharhArt] [nvarchar](1000) NULL,
[bedArt] [bigint] NULL,
[BesArt] [bigint] NULL,
PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (IGNORE_DUP_KEY = OFF)
)
GO
و دیتا تیبلم رو به این sp پاس میدم با این کد :


using (SqlCommand command = newSqlCommand())
{
command.Connection = _conhelp;
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "insertArticle";
SqlParameter param = command.Parameters.AddWithValue("@articles", dtTemp);
param.SqlDbType = SqlDbType.Structured;
param.TypeName = "dbo.artikleInfo";
command.Parameters.AddWithValue("@articles", dtTemp);
command.Parameters.AddWithValue("@InsertUser", Convert.ToDouble(user) + ostan * .001);
command.Parameters.AddWithValue("@sanadID", sanadid);
command.ExecuteNonQuery();
}

ولی نسبت به اطلاعاتی که به پروسیجرم پاس دادم کاری انجام نمی ده

ozzy_mra
شنبه 03 دی 1390, 07:45 صبح
مشکلم با تعریف یک isolationLevel برای Transaction حل شد چون تو یکی از تابع ها از جدولی می خوند که تراکنش کامیت نشده ای روی اون در حال اجرا بود که برای تابع با تعریف ReadUncommited به عنوان IsolationLevel مشکل حل شد

Arash_janusV3
شنبه 03 دی 1390, 09:18 صبح
چرا commit رو بعد از اتمام حلقه انجام نمی دید؟

ozzy_mra
شنبه 03 دی 1390, 10:24 صبح
چرا commit رو بعد از اتمام حلقه انجام نمی دید؟
ساختار این برنامه اینجوری بود (که الان کمی ساختارشو تغییر دادم) که ابتدا یه سری فیلد باید تو حلقه ثبت بشه اگه ارور داد کل باید رکبک بشه اگر از جدول دیگه ای استفاده می کردم کد درست مار می کرد اما مشکل اینجا بود که از همون جدولی که در حلقه for و برای اولین بار آپدیت انجام میشه (که تراکنش چون حلقه به پایان نرسیده commit نشده) یه دیتایی خونده بشه و همین باعث می شد که برنامه هنگ کنه که با اضافه کردت کد پایین به اونجایی که می خواستم دیتا رو بخونم مشکلم حل شد :

using (SqlTransaction tr = con.BeginTransaction(IsolationLevel.ReadUncommitte d)