事务:指作为单个逻辑工作单元执行的一系列操作,而这些逻辑工作单元需要具有原子性,一致性,隔离性和持久性四个属性。统称为ACID属性。
A:Atomicity 原子性(不可分性)
原子性:指事务必须是原子工作单元,不可分隔性,即对于事务所进行数据修改,要么全部执行,要么全都不执行。
C:Consistency 一致性
指事务在完成时,必须使所有的数据都保持一致性状态,而且在相关数据库中,所有规则都必须应用于事务的修改。以保持所有数据的完整性。
也就是说,如果有多个表中放有一个人的信息,那如果你要修改这个人的信息,就必须多个表中的信息都要修改,不能有的修改,有的不修改。
I:Isolation 隔离性
事务与其他事务是隔离的,也就是说一个事务的一项工作对数据进行修改时,如果整个事务还没有结束,其他事务就无法知道这个数据发生了修改。
D:Durability 持久性
指事务完成之后,它对于系统的影响是永久性的,即使系统出现故障也是如此。比如说,我们把一个人的记录放在磁盘上这后,停电了,这个人的记录已经存在磁盘上了,不可能来电以后又没有了。
事务的类型:隐式事务和显式事务
1.显式事务(Explicit Transaction)
显式事务是在程序中规定其提交、回滚。
SQL Server版本:
代码
using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["MySqlServer"].ConnectionString))
{
conn.Open();
using (SqlTransaction tran = conn.BeginTransaction())
{
using (SqlCommand cmd = new SqlCommand())
{
cmd.Connection = conn;
cmd.CommandType = CommandType.Text;
cmd.Transaction = tran;
try
{
cmd.CommandText = "insert into TranTable(Priority) values(1)";
cmd.ExecuteNonQuery();
cmd.CommandText = "insert into TranTable(Priority) values(256)";
cmd.ExecuteNonQuery();
tran.Commit();
Response.Write("Ok");
}
catch (SqlException ex)
{
tran.Rollback();
Response.Write("Error:" + ex.Message);
}
}
}
conn.Close();
}
{
conn.Open();
using (SqlTransaction tran = conn.BeginTransaction())
{
using (SqlCommand cmd = new SqlCommand())
{
cmd.Connection = conn;
cmd.CommandType = CommandType.Text;
cmd.Transaction = tran;
try
{
cmd.CommandText = "insert into TranTable(Priority) values(1)";
cmd.ExecuteNonQuery();
cmd.CommandText = "insert into TranTable(Priority) values(256)";
cmd.ExecuteNonQuery();
tran.Commit();
Response.Write("Ok");
}
catch (SqlException ex)
{
tran.Rollback();
Response.Write("Error:" + ex.Message);
}
}
}
conn.Close();
}
oracle版本:
代码
using Microsoft.Practices.EnterpriseLibrary.Data;
using Oracle.DataAccess.Client;
using System.Collections.Generic;
public class DepInfoDAL:IDepInfo
{
private Database db;
#region 构造函数
public DepInfoDAL()
{
db = DatabaseFactory.CreateDatabase("ConnectionString");
}
#endregion
#region
public bool Del(string depinfoid, EnumSchoolState state)
{
using (OracleConnection cn = (OracleConnection)db.CreateConnection())
{
cn.Open();
OracleTransaction transaction = cn.BeginTransaction();
try
{
Del(depinfoid, state, transaction);
AddNotice(depinfoid,transaction);
transaction.Commit();
return true;
}
catch (OracleException er)
{
transaction.Rollback();
return false;
}
}
}
#endregion
#region
public void Del(string depinfoid, EnumSchoolState state, OracleTransaction transaction)
{
string sql = "update depinfo set depstate=:PI_depstate where depinfoid=:PI_depinfoid";
OracleCommand dbCommend = (OracleCommand)db.GetSqlStringCommand(sql);
OracleParameter[] orap =
{
new OracleParameter("PI_depstate",OracleDbType.Varchar2,((int)state).ToString(),ParameterDirection.Input),
new OracleParameter("PI_Depinfoid",OracleDbType.Varchar2,depinfoid,ParameterDirection.Input),
};
foreach (OracleParameter parm in orap)
{
dbCommend.Parameters.Add(parm);
}
db.ExecuteNonQuery(dbCommend, transaction);
}
#endregion
#region
public bool AddNotice(string depinfoid)
{
using (OracleConnection cn = (OracleConnection)db.CreateConnection())
{
cn.Open();
OracleTransaction transaction = cn.BeginTransaction();
try
{
Del(depinfoid, state, transaction);
//notice
Add(depinfoid,state,transaction);
transaction.Commit();
return true;
}
catch (OracleException er)
{
transaction.Rollback();
return false;
}
}
}
#endregion
#region
public void AddNotice(string depinfoid, OracleTransaction transaction)
{
string sql = "Insert Into notice(noticeid,depinfoid,content) values (sq_notice_noticeid.nextval,:PI_depinfoid,:PI_content)";
OracleCommand dbCommend = (OracleCommand)db.GetSqlStringCommand(sql);
OracleParameter[] orap =
{
new OracleParameter("PI_depinfoid",OracleDbType.Varchar2,depinfoid,ParameterDirection.Input),
new OracleParameter("PI_content",OracleDbType.Varchar2,"11111",ParameterDirection.Input),
};
foreach (OracleParameter parm in orap)
{
dbCommend.Parameters.Add(parm);
}
db.ExecuteNonQuery(dbCommend, transaction);
}
#endregion
}
using Oracle.DataAccess.Client;
using System.Collections.Generic;
public class DepInfoDAL:IDepInfo
{
private Database db;
#region 构造函数
public DepInfoDAL()
{
db = DatabaseFactory.CreateDatabase("ConnectionString");
}
#endregion
#region
public bool Del(string depinfoid, EnumSchoolState state)
{
using (OracleConnection cn = (OracleConnection)db.CreateConnection())
{
cn.Open();
OracleTransaction transaction = cn.BeginTransaction();
try
{
Del(depinfoid, state, transaction);
AddNotice(depinfoid,transaction);
transaction.Commit();
return true;
}
catch (OracleException er)
{
transaction.Rollback();
return false;
}
}
}
#endregion
#region
public void Del(string depinfoid, EnumSchoolState state, OracleTransaction transaction)
{
string sql = "update depinfo set depstate=:PI_depstate where depinfoid=:PI_depinfoid";
OracleCommand dbCommend = (OracleCommand)db.GetSqlStringCommand(sql);
OracleParameter[] orap =
{
new OracleParameter("PI_depstate",OracleDbType.Varchar2,((int)state).ToString(),ParameterDirection.Input),
new OracleParameter("PI_Depinfoid",OracleDbType.Varchar2,depinfoid,ParameterDirection.Input),
};
foreach (OracleParameter parm in orap)
{
dbCommend.Parameters.Add(parm);
}
db.ExecuteNonQuery(dbCommend, transaction);
}
#endregion
#region
public bool AddNotice(string depinfoid)
{
using (OracleConnection cn = (OracleConnection)db.CreateConnection())
{
cn.Open();
OracleTransaction transaction = cn.BeginTransaction();
try
{
Del(depinfoid, state, transaction);
//notice
Add(depinfoid,state,transaction);
transaction.Commit();
return true;
}
catch (OracleException er)
{
transaction.Rollback();
return false;
}
}
}
#endregion
#region
public void AddNotice(string depinfoid, OracleTransaction transaction)
{
string sql = "Insert Into notice(noticeid,depinfoid,content) values (sq_notice_noticeid.nextval,:PI_depinfoid,:PI_content)";
OracleCommand dbCommend = (OracleCommand)db.GetSqlStringCommand(sql);
OracleParameter[] orap =
{
new OracleParameter("PI_depinfoid",OracleDbType.Varchar2,depinfoid,ParameterDirection.Input),
new OracleParameter("PI_content",OracleDbType.Varchar2,"11111",ParameterDirection.Input),
};
foreach (OracleParameter parm in orap)
{
dbCommend.Parameters.Add(parm);
}
db.ExecuteNonQuery(dbCommend, transaction);
}
#endregion
}
我们来看看显式事务的优缺点:
优点:(1)操作简单(主要是对象几个方法)和数据库事务差不多
(2)占用资源少、速度快
(3)独立于数据库 不同数据库专有代码被隐藏了
缺点:(1)事务不能跨多个数据库连接(分布式事务可以跨多个数据库)
(2)事务执行必须依靠一个存在的数据库连接,从Transaction对象生成就可以看出通过SqlConnection或OracleConnection对象获得。
(3)ADO.net中分布式事务可以跨多个数据库,如果其中一个是SQLServer数据库的话,通过SQLserver连接服务器连接别的数据库,但如果是DB2和Oracle之间就不行。
比如您要在一个业务中同时实现往SQLServer数据和Oracle数据库都插入数据的事务,就无法实现。
2.隐式事务
相对于显式事务,隐式事务不再有 Commit、Rollback 方法。只包含一个事务范围,在.net中可以使用System.Transactions 实现
SQL Server版本:
Oracle版本:
//业务层
代码
// scope.Dispose(); 使用using 会自动释放资源
}
}
}
}
public class scoreBLL
{
public static void Get(string userinfoid)
{
using (TransactionScope scope = new TransactionScope())
{
scoreDal SD = new scoreDal();
try
{
//你的业务代码
SD.Add(userinfoid, 1);
SD.reduce(userinfoid, 11);
scope.Complete();
}
catch (Exception e)
{
}
finally
{
{
public static void Get(string userinfoid)
{
using (TransactionScope scope = new TransactionScope())
{
scoreDal SD = new scoreDal();
try
{
//你的业务代码
SD.Add(userinfoid, 1);
SD.reduce(userinfoid, 11);
scope.Complete();
}
catch (Exception e)
{
}
finally
{
// scope.Dispose(); 使用using 会自动释放资源
}
}
}
}
//数据层
代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using wdxt_Score.IDAL;
using Microsoft.Practices.EnterpriseLibrary.Data;
using Oracle.DataAccess.Client;
using System.Data;
public class scoreDal : Iscore
{
private Database db;
public scoreDal()
{
db = DatabaseFactory.CreateDatabase("ConnectionString");
}
public void Add(string userinfoid, int basevalue)
{
string sql = "Insert Into TEXT";
sql += "(ID,VALUE)";
sql += "values(:PI_userinfoid,:PI_basevalue)";
OracleCommand dbCommend = (OracleCommand)db.GetSqlStringCommand(sql);
OracleParameter[] orap =
{
new OracleParameter("PI_userinfoid",OracleDbType.Varchar2,userinfoid,ParameterDirection.Input),
new OracleParameter("PI_basevalue",OracleDbType.Varchar2,basevalue,ParameterDirection.Input),
};
foreach (OracleParameter parm in orap)
{
dbCommend.Parameters.Add(parm);
}
db.ExecuteNonQuery(dbCommend);
}
public void reduce(string userinfoid, int basevalue)
{
string sql = "Insert Into TEXT";
sql += "(ID,VALUE)";
sql += "values(:PI_userinfoid,:PI_basevalue)";
OracleCommand dbCommend = (OracleCommand)db.GetSqlStringCommand(sql);
OracleParameter[] orap =
{
new OracleParameter("PI_userinfoid",OracleDbType.Varchar2,userinfoid,ParameterDirection.Input),
new OracleParameter("PI_basevalue",OracleDbType.Varchar2,basevalue,ParameterDirection.Input),
};
foreach (OracleParameter parm in orap)
{
dbCommend.Parameters.Add(parm);
}
db.ExecuteNonQuery(dbCommend);
}
}
using System.Collections.Generic;
using System.Linq;
using System.Text;
using wdxt_Score.IDAL;
using Microsoft.Practices.EnterpriseLibrary.Data;
using Oracle.DataAccess.Client;
using System.Data;
public class scoreDal : Iscore
{
private Database db;
public scoreDal()
{
db = DatabaseFactory.CreateDatabase("ConnectionString");
}
public void Add(string userinfoid, int basevalue)
{
string sql = "Insert Into TEXT";
sql += "(ID,VALUE)";
sql += "values(:PI_userinfoid,:PI_basevalue)";
OracleCommand dbCommend = (OracleCommand)db.GetSqlStringCommand(sql);
OracleParameter[] orap =
{
new OracleParameter("PI_userinfoid",OracleDbType.Varchar2,userinfoid,ParameterDirection.Input),
new OracleParameter("PI_basevalue",OracleDbType.Varchar2,basevalue,ParameterDirection.Input),
};
foreach (OracleParameter parm in orap)
{
dbCommend.Parameters.Add(parm);
}
db.ExecuteNonQuery(dbCommend);
}
public void reduce(string userinfoid, int basevalue)
{
string sql = "Insert Into TEXT";
sql += "(ID,VALUE)";
sql += "values(:PI_userinfoid,:PI_basevalue)";
OracleCommand dbCommend = (OracleCommand)db.GetSqlStringCommand(sql);
OracleParameter[] orap =
{
new OracleParameter("PI_userinfoid",OracleDbType.Varchar2,userinfoid,ParameterDirection.Input),
new OracleParameter("PI_basevalue",OracleDbType.Varchar2,basevalue,ParameterDirection.Input),
};
foreach (OracleParameter parm in orap)
{
dbCommend.Parameters.Add(parm);
}
db.ExecuteNonQuery(dbCommend);
}
}
上一个项目用三层架构事务都放在数据层,其实应该用隐式事务,放在业务层是最合适的。
这篇写的都是在.net中的事务,还有在数据库中实现,利用com组件等,在数据库中使用事务又有所不同,
有兴趣可以看看这篇文章Oracle与SQL Server事务处理的比较 。
参考:1、.NET 事务技术
4、三种事务处理