博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
事务与分布式事务
阅读量:4910 次
发布时间:2019-06-11

本文共 5951 字,大约阅读时间需要 19 分钟。

事务是一种将活动涉及的所有操作作为一个不可分割的执行单元,所有操作只有在正常执行的情况下方能提交,不然集体回滚。(All or Nothing)

事务具有ACID四种属性:原子性、一致性、隔离性、持久性。

事务的处理方式存在很多种处理方式:

可以居于数据库的存储过程编写SQL事务,或通过ADO.NET、企业库均提供事务。

1、数据库存储过程事务:

 数据库结构:

ExpandedBlockStart.gif
View Code
CREATE 
TABLE 
[
dbo
].
[
Player_Account
](
    
[
AccountIPlayer_Account_ID
] 
[
int
] 
IDENTITY(
1,
1
NOT 
NULL,
    
[
PlayerID
] 
[
int
] 
NOT 
NULL,
    
[
AccountName
] 
[
varchar
](
30
NOT 
NULL,
    
[
Password
] 
[
varchar
](
30
NOT 
NULL,
    
[
Balance
] 
[
decimal
](
18
0
NOT 
NULL,
    
[
Status
] 
[
int
] 
NOT 
NULL,
    
[
ActiveTime
] 
[
datetime
] 
NOT 
NULL,
    
[
CreateTime
] 
[
datetime
] 
NOT 
NULL,
    
[
Remark
] 
[
varchar
](
100
NULL,
    
[
ModifyTime
] 
[
datetime
] 
NULL,
    
[
ModifyBy
] 
[
varchar
](
30
NULL,
 
CONSTRAINT 
[
PK_PLAYER_ACCOUNT
] 
PRIMARY 
KEY 
CLUSTERED 
(
    
[
AccountIPlayer_Account_ID
] 
ASC
)
WITH (PAD_INDEX  
= 
OFF, STATISTICS_NORECOMPUTE  
= 
OFF, IGNORE_DUP_KEY 
= 
OFF, ALLOW_ROW_LOCKS  
= 
ON, ALLOW_PAGE_LOCKS  
= 
ON
ON 
[
PRIMARY
]
ON 
[
PRIMARY
]
CREATE 
TABLE 
[
dbo
].
[
Member_Account
](
    
[
Member_Account_ID
] 
[
int
] 
IDENTITY(
1,
1
NOT 
NULL,
    
[
MemberID
] 
[
int
] 
NOT 
NULL,
    
[
AccountName
] 
[
varchar
](
30
NOT 
NULL,
    
[
Password
] 
[
varchar
](
30
NOT 
NULL,
    
[
Balance
] 
[
decimal
](
18
0
NOT 
NULL,
    
[
Status
] 
[
int
] 
NOT 
NULL,
    
[
ActiveTime
] 
[
datetime
] 
NOT 
NULL,
    
[
CreateTime
] 
[
datetime
] 
NOT 
NULL,
    
[
Remark
] 
[
varchar
](
100
NULL,
    
[
ModifyTime
] 
[
datetime
] 
NULL,
    
[
ModifyBy
] 
[
varchar
](
30
NULL
ON 
[
PRIMARY
]

两个账户的转账是一种复合操作,同时也涉及到事务操作。(当然如果涉及到信用额度、可用额度、状态将更加复杂)

 存储过程:

ExpandedBlockStart.gif
View Code
SET ANSI_NULLS 
ON
GO
SET QUOTED_IDENTIFIER 
ON
GO
--
账号转账
CREATE 
PROCEDURE 
[
dbo
].
[
Transfer2Player
]  
    
@AccountIPlayer_Account_ID 
INT 
=
NULL,
    
@Member_Account_ID 
INT 
=
NULL,
    
@Amount 
DECIMAL
=
0
AS
BEGIN
    
IF 
NOT 
EXISTS(
SELECT 
* 
FROM Player_Account pa 
WHERE pa.AccountIPlayer_Account_ID
=
@AccountIPlayer_Account_ID)
      
BEGIN
          
RAISERROR(
'
AccountNotExists
',
16,
1)
          
RETURN 
      
END
    
IF 
NOT 
EXISTS(
SELECT 
* 
FROM Member_Account ma 
WHERE ma.Member_Account_ID
=
@Member_Account_ID)
      
BEGIN
          
RAISERROR(
'
AccountNotExists
',
16,
1)
          
RETURN 
      
END
   
IF 
NOT 
EXISTS(
SELECT 
* 
FROM Member_Account ma 
WHERE ma.Member_Account_ID
=
@Member_Account_ID  
AND ma.Balance
<
@Amount)
     
BEGIN
         
RAISERROR(
'
NoEnoughAmount
',
16,
1)
        
RETURN
     
END
   
--
开始事务
   
BEGIN 
TRANSACTION
     
UPDATE Member_Account
     
SET Balance 
= 
@Amount 
WHERE Member_Account_ID 
=
@Member_Account_ID 
     
IF 
@@ERROR
<>
0
      
BEGIN
          
--
出错回滚
          
ROLLBACK 
TRANSACTION
      
END
     
UPDATE Player_Account
     
SET Balance 
= 
@Amount 
WHERE AccountIPlayer_Account_ID 
=
@AccountIPlayer_Account_ID
     
IF 
@@ERROR
<>
0
      
BEGIN
          
ROLLBACK 
TRANSACTION
      
END
    
--
提交事务
    
COMMIT 
TRANSACTION
END
GO

 

2、ADO.Net 事务

在System.Data.SqlClient也提供了事务功能

 

ExpandedBlockStart.gif
View Code
 private const string connectionString 
= "server
=.;
database
=Game
-Pay2012;sa
=sa;pwd
=
123456;";
        
public void Tranfer2Player(
int Player_Account_ID,
int Member_Account_ID,
decimal Amount)
        {
            SqlConnection conn 
= new SqlConnection(ConfigurationManager.ConnectionStrings
[
connectionString
].ConnectionString);
            SqlCommand cmd 
= new SqlCommand();
            try
            {
                conn.
Open();
                cmd.
Transaction 
= conn.BeginTransaction(IsolationLevel.RepeatableRead, "Tranfer2PlayerTransaction");
                
//充值到玩家
                cmd.CommandText 
= " 
UPDATE Player_Account 
SET Balance 
= 
@Amount 
WHERE AccountIPlayer_Account_ID 
=
@AccountIPlayer_Account_ID";
                cmd.CommandType 
= CommandType.
Text;
                cmd.Connection 
= conn;
                SqlParameter
[] paras 
= new SqlParameter
[]{
                    new SqlParameter("
@AccountIPlayer_Account_ID",SqlDbType.
Int,
32),
                    new SqlParameter("
@Amount",SqlDbType.
Decimal,
18)
                };
                paras
[
0
].Value 
= Player_Account_ID;
                paras
[
1
].Value 
= Amount;
                foreach (SqlParameter para 
in paras)
                {
                    cmd.Parameters.
Add(para);
                }
                cmd.ExecuteNonQuery();
                
//扣除账号金额
                cmd.CommandText 
= "
UPDATE Member_Account 
SET Balance 
= 
@Amount 
WHERE Member_Account_ID 
=
@Member_Account_ID ";
                cmd.CommandType 
= CommandType.
Text;
                cmd.Connection 
= conn;
                SqlParameter
[] paras2 
= new SqlParameter
[]{
                    new SqlParameter("
@Member_Account_ID",SqlDbType.
Int,
32),
                    new SqlParameter("
@Amount",SqlDbType.
Decimal,
18)
                };
                paras
[
0
].Value 
= Member_Account_ID;
                paras
[
1
].Value 
= Amount;
                foreach (SqlParameter para 
in paras)
                {
                    cmd.Parameters.
Add(para);
                }
                cmd.ExecuteNonQuery();
                
//提交事务
                cmd.
Transaction.
Commit();
            }
            catch (Exception)
            {
                
//回滚事务
                cmd.
Transaction.
Rollback();
                throw;
            }
            finally
            {
                conn.
Close();
            }
        }

 

出来ADO.Net 像企业库、Linq to Sql也提供了相关的事务。

3、分布式事务

 

TransactionScope 此类在.Net Framework 2.0 版新增的。它为数据库提供了一个“轻量级”(区别于SqlTransaction)的事务。

 在通过 new 语句实例化 TransactionScope 时,事务管理器将确定要参与哪个事务。一经确定,此范围将始终参与该事务。此决策基于两个因素:是否存在环境事务以及构造函数中TransactionScopeOption 参数的值。环境事务是在其中执行您的代码的事务。通过调用 Transaction 类的 Current 静态属性可获取对环境事务的引用。
详细请看MSDN:

 

 

ExpandedBlockStart.gif
View Code
    
public 
class TransactionClass
    {
        
private 
const 
string strcon1 = 
"
Data Source=192.168.1.36;Initial Catalog=TransactionDB;user id=sa;Password=XhTeam;
";
  
        
private 
const 
string strcon2 = 
"
Data Source=192.168.1.36;Initial Catalog=Transaction2DB;user id=sa;Password=XhTeam;
";
      
        
private 
const 
string strcom1 = 
"
INSERT INTO Account(name,password)VALUES('test222','testone')
";
        
private 
const 
string strcom2 = 
"
INSERT INTO Logger(title,test)VALUES('testlog222','testonecontent')
";
        
public 
void CreateTransactionScope()
        {
            TransactionOptions tOps = 
new TransactionOptions();
            tOps.IsolationLevel = IsolationLevel.RepeatableRead;
            tOps.Timeout = 
new TimeSpan(
0
3
0);
            
try
            {
                
using (TransactionScope scope = 
new TransactionScope(TransactionScopeOption.RequiresNew,tOps))
                {
                    
using (SqlConnection con1 = 
new SqlConnection(strcon1))
                    {
                        con1.Open();
                        SqlCommand com1 = 
new SqlCommand(strcom1, con1);
                        com1.ExecuteNonQuery();
                    }
                    
using (SqlConnection con2 = 
new SqlConnection(strcon2))
                    {
                        con2.Open();
                        SqlCommand com2 = 
new SqlCommand(strcom2, con2);
                        com2.ExecuteNonQuery();
                    }
                    scope.Complete();
                }
            }
            
catch (Exception ex)
            {
                Console.WriteLine(
"
异常信息: 
" + ex.Message);
            }
        }
    }
}

TransactionScope 有三种模式:

TransactionScopeOptions:Required、RequiresNew、Suppress

Required 如果已经存在一个事务,那么这个事务范围将加入已有事务,否则创建自己的事务。

RequiresNew 事务范围将创建自己的事务

Suppress 如果处于当前事务范围,那么事务范围既不会加入范围事务,也不会创建自己的事务。当部分代码留在事务外部时,可以使用该项。

 

 

 

 

 

转载于:https://www.cnblogs.com/xoray007/archive/2012/05/06/2486631.html

你可能感兴趣的文章
车机HMI开发过程中的功能安全方案
查看>>
我要上蓝翔
查看>>
Ping pong(树状数组经典)
查看>>
Mysql 语句优化
查看>>
记一次面试
查看>>
例子:进度条
查看>>
二叉树
查看>>
kubernetes安装记录
查看>>
easyui 回车搜索
查看>>
SAP 使用SQL Trace(ST05)
查看>>
P4777 【模板】扩展中国剩余定理(EXCRT)&& EXCRT
查看>>
[PowerShell]Quote in String
查看>>
Workpress搭建经验 (ubuntu16.04+nginx+mysql+php7)
查看>>
Java List详解
查看>>
选择排序SelectSort
查看>>
一个案例深入Python中的__new__和__init__
查看>>
链接,光标,DHTML,缩放
查看>>
Flask博客类登录注册验证模块代码(十四)
查看>>
LFS、BLFS、ALFS、HLFS的区别
查看>>
Java的MD5加密和解密
查看>>