PDA

View Full Version : تغییرات در چند جدول با اطمینان از اجرا شدن تغییر روی همه جداول



sara_aryanfar
یک شنبه 30 فروردین 1394, 12:17 عصر
با سلام فرض کنید ما می خواهیم روی 3 جدول تغییری رو انجام بدیم روی رکورد هاشون حالا می خواهیم اگر یکی از این تغییرات موفق نبود بقیه هم انجام نشه چطور می تونیم انجام بدیم

محمد رضا فاتحی
یک شنبه 30 فروردین 1394, 12:38 عصر
به نظرم اگه در مورد trigger سرچ بکنید بتونه کمکتون بکنه

alireza_s_84
یک شنبه 30 فروردین 1394, 13:00 عصر
با سلام فرض کنید ما می خواهیم روی 3 جدول تغییری رو انجام بدیم روی رکورد هاشون حالا می خواهیم اگر یکی از این تغییرات موفق نبود بقیه هم انجام نشه چطور می تونیم انجام بدیم

باید از Transaction ها استفاده کنید. نحوه ی استفاده هم بستگی به این داره که از Stored Producer ها استفاده میکنید یا اینکه کدهای T-SQL رو مستقیما اجرا میکنید. اگر در محیط برنامه نویسی مستقیما کدها رو اجرا میکنید میتونید از متد زیر استفاده کنید:

public static bool ExecuteBatch(List<SqlCommand> commands)
{
bool result = false;
SqlTransaction Trans = null;


using (SqlConnection Cnn = InitConnection())
{
try
{
Cnn.Open();
Trans = Cnn.BeginTransaction();


foreach (var command in commands)
{
command.Connection = Cnn;
command.Transaction = Trans;
command.ExecuteNonQuery();
}
Trans.Commit();
result = true;
}
catch (Exception ex)
{
if (Trans != null)
{
Trans.Rollback();
}
//Log.WriteError(MethodInfo.GetCurrentMethod(), ex);
}
finally
{
if (Cnn != null && Cnn.State == ConnectionState.Open)
{
Cnn.Close();
Cnn.Dispose();
commands.Clear();
}
}
}


return result;
}

نحوه استفاده هم بسیار ساده ست ، یک لیست از Command هایی که باید اجرا بشن رو بهش پاس میدین و اون به ترتیب اونها رو اجرا میکنه ، اگر در حین اجرا هرکدوم از اونها خطایی رخ بده تمامی عملیات Rollback میشه در غیر اینصورت همه تغییرات ثبت میشه.
برای استفاده در SPها کمی روش کار متفاوت هست و باید با دستورات T-SQL کار کنید ولی روند عملیات دقیقا مثل همین کد میمونه.

alireza_s_84
یک شنبه 30 فروردین 1394, 13:01 عصر
به نظرم اگه در مورد trigger سرچ بکنید بتونه کمکتون بکنه

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

sara_aryanfar
یک شنبه 30 فروردین 1394, 13:22 عصر
باید از Transaction ها استفاده کنید. نحوه ی استفاده هم بستگی به این داره که از Stored Producer ها استفاده میکنید یا اینکه کدهای T-SQL رو مستقیما اجرا میکنید. اگر در محیط برنامه نویسی مستقیما کدها رو اجرا میکنید میتونید از متد زیر استفاده کنید:

public static bool ExecuteBatch(List<SqlCommand> commands)
{
bool result = false;
SqlTransaction Trans = null;


using (SqlConnection Cnn = InitConnection())
{
try
{
Cnn.Open();
Trans = Cnn.BeginTransaction();


foreach (var command in commands)
{
command.Connection = Cnn;
command.Transaction = Trans;
command.ExecuteNonQuery();
}
Trans.Commit();
result = true;
}
catch (Exception ex)
{
if (Trans != null)
{
Trans.Rollback();
}
//Log.WriteError(MethodInfo.GetCurrentMethod(), ex);
}
finally
{
if (Cnn != null && Cnn.State == ConnectionState.Open)
{
Cnn.Close();
Cnn.Dispose();
commands.Clear();
}
}
}


return result;
}

نحوه استفاده هم بسیار ساده ست ، یک لیست از Command هایی که باید اجرا بشن رو بهش پاس میدین و اون به ترتیب اونها رو اجرا میکنه ، اگر در حین اجرا هرکدوم از اونها خطایی رخ بده تمامی عملیات Rollback میشه در غیر اینصورت همه تغییرات ثبت میشه.
برای استفاده در SPها کمی روش کار متفاوت هست و باید با دستورات T-SQL کار کنید ولی روند عملیات دقیقا مثل همین کد میمونه.

ممنون دوست من دقیقا دنبال همین مبحث بودم اگر در مورد استفاده در SPها هم نمونه ای در دسترس داشته باشید ممنون میشم

ali_md110
یک شنبه 30 فروردین 1394, 13:50 عصر
سایت Code Project مثال خوبی داره


CREATE PROCEDURE addTitle(@title_id VARCHAR(6), @au_id VARCHAR(11),
@title VARCHAR(20), @title_type CHAR(12))
AS

BEGIN TRAN
INSERT titles(title_id, title, type)
VALUES (@title_id, @title, @title_type)

IF (@@ERROR <> 0) GOTO ERR_HANDLER

INSERT titleauthor(au_id, title_id)
VALUES (@au_id, @title_id)

IF (@@ERROR <> 0) GOTO ERR_HANDLER

COMMIT TRAN

RETURN 0

ERR_HANDLER:
PRINT 'Unexpected error occurred!'
ROLLBACK TRAN
RETURN 1


http://www.codeproject.com/Articles/4451/SQL-Server-Transactions-and-Error-Handling

alireza_s_84
یک شنبه 30 فروردین 1394, 13:55 عصر
ممنون دوست من دقیقا دنبال همین مبحث بودم اگر در مورد استفاده در SPها هم نمونه ای در دسترس داشته باشید ممنون میشم
توی SPها شما ابتدا یک transaction رو شروع میکنید
بعد تک تک دستورات رو اجرا میکنید.
بعد از اجرای هر دستور چک میکنید خطایی رخ داده یا خیر
اگر خطایی رخ داده باشه به یک برچسب کنترل خطا پرش می کنید
در نهایت آخر همه دستورات Transaction رو Commit میکنید
برای نمونه:

ALTER PROCEDURE [dbo].[sp_InsertUser]
@Username varchar(20),
@Email varchar(100),
@Password varchar(12),
@FirstName nvarchar(30),
@LastName nvarchar(50),
@Birthday varchar(10),
@CityId int,
@Address nvarchar(300),
@ZipCode varchar(10),
@Mobile varchar(11),
@MobileActiveCode char(4),
@GenderId tinyint,
@MaritalStatusId tinyint,
@DegreeId tinyint,
@Courses nvarchar(50),
@ExpireDate datetime,
@Description nvarchar(500),
@PicturePath nvarchar(300),
@YahooID varchar(30),
@WebSite nvarchar(80),
@MemberTypeId tinyint,
@UserRoles AS UserRolesId READONLY
AS
BEGIN
SET NOCOUNT ON;
DECLARE @TranStarted bit;
SET @TranStarted = 0;


IF( @@TRANCOUNT = 0 )
BEGIN
BEGIN TRANSACTION
SET @TranStarted = 1
END
ELSE
SET @TranStarted = 0




DECLARE @HashedPassword char(32);
SET @HashedPassword = CONVERT(CHAR(32),HashBytes('MD5', @Password),2)


INSERT INTO [dbo].[tbl_Users]
([Username]
,[Email]
,[Password]
,[FirstName]
,[LastName]
,[Birthday]
,[CityId]
,[Address]
,[ZipCode]
,[Mobile]
,[MobileActiveCode]
,[GenderId]
,[MaritalStatusId]
,[DegreeId]
,[Courses]
,[ExpireDate]
,[Description]
,[PicturePath]
,[YahooID]
,[WebSite]
,[MemberTypeId])
VALUES
(
LOWER(@Username),
LOWER(@Email),
@HashedPassword,
@FirstName,
@LastName,
@Birthday,
@CityId,
@Address,
@ZipCode,
@Mobile,
@MobileActiveCode,
@GenderId,
@MaritalStatusId,
@DegreeId,
@Courses,
@ExpireDate,
@Description,
@PicturePath,
@YahooID,
@WebSite,
@MemberTypeId
)


DECLARE @UserId int;
SELECT @UserId = SCOPE_IDENTITY();


IF ( @@ERROR <> 0)
GOTO Cleanup


--************************************************** ***************************************

INSERT INTO [dbo].[tbl_Scores]
(
[UserId]
,[ScoreModeId]
,[Value]
)
VALUES
(
@UserId
,1
,100
)


IF ( @@ERROR <> 0)
GOTO Cleanup


--************************************************** ***************************************

INSERT INTO [dbo].[tbl_ChatSetting]
(
[UserId]
)
VALUES
(
@UserId
)


IF ( @@ERROR <> 0)
GOTO Cleanup


--************************************************** ***************************************

DECLARE @TotalRoles int;
DECLARE @CurrentRow int;
DECLARE @RoleId tinyint;


SELECT @TotalRoles = COUNT(*) FROM @UserRoles;
SET @CurrentRow = 1;


WHILE @CurrentRow <= @TotalRoles
BEGIN
SELECT TOP 1 @RoleId = [RoleId] FROM @UserRoles WHERE ( [No] = @CurrentRow );
INSERT INTO tbl_UsersInRoles (UserId, RoleId) VALUES (@UserId, @RoleId)
SET @CurrentRow = @CurrentRow + 1;


IF ( @@ERROR <> 0)
BEGIN
GOTO Cleanup
BREAK
END
END


--************************************************** ***************************************


IF( @TranStarted = 1 )
BEGIN
SET @TranStarted = 0
COMMIT TRANSACTION


SELECT @UserId AS 'NewRecordId'
RETURN

END




Cleanup:
IF( @TranStarted = 1 )
BEGIN
SET @TranStarted = 0
ROLLBACK TRANSACTION
END


SELECT 0 AS 'NewRecordId'


END


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