C# 一个事务中的不同数据库
我正在将C# 一个事务中的不同数据库,c#,transactions,C#,Transactions,我正在将TransactionBlock代码用于在config中存储连接字符串的web应用程序 直到现在,我只需要写一个本地数据库,因此,这段代码是有效的。但是,我现在需要另一种数据访问方法,使用不同的连接字符串写入另一个数据库 我在配置文件中创建了一个新的连接字符串,但我不确定如何调用它并将其交换掉 到目前为止,我掌握的基本代码是: public class TransactionBlock : IDisposable { private readonly bool _mFirst
TransactionBlock
代码用于在config中存储连接字符串的web应用程序
直到现在,我只需要写一个本地数据库,因此,这段代码是有效的。但是,我现在需要另一种数据访问方法,使用不同的连接字符串写入另一个数据库
我在配置文件中创建了一个新的连接字符串,但我不确定如何调用它并将其交换掉
到目前为止,我掌握的基本代码是:
public class TransactionBlock : IDisposable
{
private readonly bool _mFirstTransactionBlock = false;
private bool _mDisposed = false;
public TransactionBlock(string connectionStringConfigKey = null)
{
if (connectionStringConfigKey != null && CurrentTransaction != null)
throw new Exception("Can't create a new transactionBlock with a specific connectionstring if you are already within a block.");
// Open a connection if we haven't yet already
if (CurrentTransaction == null) // we don't have a transaction yet so create one:
{
SqlConnection conn = new SqlConnection(ConnectionString); // Create a new connection object for the connection string.
try
{
conn.Open();
}
catch (SqlException ex)
{
// Severity 20 errors are returned when there are connection
// problems, so we only retry if the severity is 20.
// Don't worry about deadlock errors in here - we're just connecting
// to the database, not running anything which could be deadlocked.
if (ex.Class != 20) throw;
// Clear connection pool of all connections related to the given connection string.
SqlConnection.ClearPool(conn);
// Try to open the connection once again, catching any error.
try { conn.Open(); }
catch { conn = null; }
// If 2nd attempt failed, throw original exception.
if (conn == null) throw;
}
CurrentTransaction = conn.BeginTransaction();
_mFirstTransactionBlock = true;
}
}
public void Commit()
{
if (_mFirstTransactionBlock)
{
Dispose(true);
}
}
public void Dispose()
{
if (_mFirstTransactionBlock)
{
Dispose(false);
}
}
private void Dispose(bool commit)
{
if (_mDisposed)
return; // committed and cleaned up already.
try
{
var transaction = CurrentTransaction;
var connection = transaction.Connection; // taking a reference to the connection object as rollback will set it to null;
if (commit)
{
transaction.Commit();
}
else // rollback the transaction if it hasn't been commited.
{
transaction.Rollback();
}
if (connection != null)
{
connection.Close();
connection.Dispose();
}
transaction.Dispose();
}
finally // ensure that regardless of connection exceptions, the state is set to disposed.
{
// remove current transaction from context.
CurrentTransaction = null;
_mDisposed = true;
}
}
private static SqlTransaction CurrentTransaction
{
get
{
return CurrentContext.GetItem<SqlTransaction>("__Transaction");
}
set
{
CurrentContext.SetItem("__Transaction", value);
}
}
public static SqlConnection Connection
{
get { return CurrentTransaction.Connection; }
}
public static SqlTransaction Transaction
{
get { return CurrentTransaction; }
}
private static string connectionString;
public static string ConnectionString
{
get
{
if (string.IsNullOrEmpty(connectionString))
{
try
{
connectionString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString ?? "";
}
catch (Exception ex)
{
ServiceLogger.LogError("Database: Creating SQL Connection. Can not find connection string. Nothing will work until this is resolved.");
throw;
}
if (string.IsNullOrEmpty(connectionString))
ServiceLogger.LogError("Database: Creating SQL Connection. Can not find connection string. Nothing will work until this is resolved.");
else
ServiceLogger.LogInfo(String.Format("Database: Creating SQL Connection. Connection string: {0}", connectionString));
}
return connectionString;
}
}
#region CurrentContext Helper class
/// <summary>
/// Helper class for easy access to the appropriate context containers.
/// </summary>
private static class CurrentContext
{
public static T GetItem<T>(string key) where T : class
{
if (HttpContext.Current != null)
{
return (T)HttpContext.Current.Items[key];
}
else
{
return (T)CallContext.GetData(key);
}
}
public static void SetItem(string key, object value)
{
if (HttpContext.Current != null)
{
HttpContext.Current.Items[key] = value;
}
else
{
CallContext.SetData(key, value);
}
}
}
#endregion
/// <summary>
/// Adds the application name to the connection string, but only if it is missing.
/// </summary>
/// <param name="connectionString"></param>
/// <returns>Modified connection string</returns>
private static string AddApplicationNameIfMissing(string connectionString)
{
if (connectionString == null)
return null;
// If the connection string hasn't already been configured with an application name,
// then add one (assumes the application name is not 1st element, as unlikely to have a leading ';').
if (connectionString.IndexOf(";Application Name=", StringComparison.OrdinalIgnoreCase) >= 0)
return connectionString;
// TODO: if this turns out to be too slow to perform on each query then caching connection strings should be added.
// take site name if run from a website or webservice otherwise take process path.
string appName = System.Web.Hosting.HostingEnvironment.SiteName ?? Path.GetFileNameWithoutExtension(Environment.GetCommandLineArgs()[0]);
return connectionString += string.Format("{0}Application Name={1}", connectionString.EndsWith(";") ? "" : ";", appName);
}
private interface IStructuredParam
{
DataTable ToDataTable();
}
public SqlCommand CreateSpCommand(string sql)
{
if (string.IsNullOrWhiteSpace(sql)) throw new ArgumentNullException("sql");
SqlTransaction tran = CurrentTransaction;
if (tran == null) throw new NullReferenceException("CurrentTransaction");
SqlConnection conn = tran.Connection;
if (conn == null) throw new NullReferenceException("Connection");
SqlCommand cmd = conn.CreateCommand();
if (cmd == null) throw new NullReferenceException("Command");
cmd.CommandText = sql;
cmd.CommandType = CommandType.StoredProcedure;
cmd.Transaction = tran;
return cmd;
}
public void AddParameter(SqlCommand cmd, string name, SqlDbType type, int size, object value, bool isOutput)
{
var p = cmd.CreateParameter();
p.ParameterName = name;
p.SqlDbType = type;
p.Size = size;
if (value == null)
p.Value = DBNull.Value;
else if (type == SqlDbType.Structured)
p.Value = ((IStructuredParam)value).ToDataTable();
else
p.Value = value;
p.Direction = isOutput == false ? ParameterDirection.Input : ParameterDirection.Output;
cmd.Parameters.Add(p);
}
public void ExecuteAndMapReader(SqlCommand command, params Action<IDataReader>[] mappingMethods)
{
using (var reader = command.ExecuteReader())
{
int i = 0;
do
{
while (reader.Read())
{
if (reader.HasRows && mappingMethods != null && mappingMethods.Any())
mappingMethods[i](reader);
}
i++;
} while (reader.NextResult());
reader.Close();
}
}
}
公共类事务块:IDisposable
{
private readonly bool\u mFirstTransactionBlock=false;
private bool _mDisposed=false;
公共事务块(字符串连接StringConfigKey=null)
{
if(connectionStringConfigKey!=null&&CurrentTransaction!=null)
抛出新异常(“如果您已经在块中,则无法创建具有特定connectionstring的新transactionBlock。”);
//如果尚未打开连接,请打开连接
if(CurrentTransaction==null)//我们还没有事务,所以创建一个:
{
SqlConnection conn=newsqlconnection(ConnectionString);//为连接字符串创建一个新的连接对象。
尝试
{
conn.Open();
}
catch(SqlException-ex)
{
//存在连接时返回严重性为20的错误
//问题,因此我们仅在严重性为20时重试。
//这里不用担心死锁错误-我们只是在连接
//到数据库,不运行任何可能死锁的内容。
如果(ex.Class!=20)投掷;
//清除与给定连接字符串相关的所有连接的连接池。
SqlConnection.ClearPool(conn);
//再次尝试打开连接,捕获任何错误。
试试{conn.Open();}
捕获{conn=null;}
//如果第二次尝试失败,则引发原始异常。
如果(conn==null)抛出;
}
CurrentTransaction=conn.BeginTransaction();
_mFirstTransactionBlock=true;
}
}
公共无效提交()
{
if(mFirstTransactionBlock)
{
处置(真实);
}
}
公共空间处置()
{
if(mFirstTransactionBlock)
{
处置(虚假);
}
}
私有void Dispose(bool commit)
{
如果(_mDisposed)
return;//已提交并已清理。
尝试
{
var交易=当前交易;
var connection=transaction.connection;//将连接对象的引用作为回滚将其设置为null;
如果(提交)
{
Commit();
}
else//如果事务尚未提交,则回滚该事务。
{
transaction.Rollback();
}
if(连接!=null)
{
connection.Close();
connection.Dispose();
}
transaction.Dispose();
}
最后//确保无论连接异常如何,状态都设置为disposed。
{
//从上下文中删除当前事务。
CurrentTransaction=null;
_mDisposed=true;
}
}
私有静态SqlTransaction CurrentTransaction
{
得到
{
返回CurrentContext.GetItem(“\uu事务”);
}
设置
{
CurrentContext.SetItem(“\u事务”,值);
}
}
公共静态SqlConnection连接
{
获取{return CurrentTransaction.Connection;}
}
公共静态SqlTransaction事务
{
获取{return CurrentTransaction;}
}
私有静态字符串连接字符串;
公共静态字符串连接字符串
{
得到
{
if(string.IsNullOrEmpty(connectionString))
{
尝试
{
connectionString=ConfigurationManager.connectionString[“DefaultConnection”]。connectionString;
}
捕获(例外情况除外)
{
LogError(“数据库:正在创建SQL连接。找不到连接字符串。在解决此问题之前,任何操作都无效。”);
投掷;
}
if(string.IsNullOrEmpty(connectionString))
LogError(“数据库:正在创建SQL连接。找不到连接字符串。在解决此问题之前,任何操作都无效。”);
其他的
LogInfo(String.Format(“数据库:创建SQL连接。连接字符串:{0}”,connectionString));
}
返回连接字符串;
}
}
#区域CurrentContext助手类
///
///帮助器类,便于访问适当的上下文容器。
///
私有静态类CurrentContext
{
公共静态T GetItem(字符串键),其中T:class
{
if(HttpContext.Current!=null)
{
返回(T)HttpContext.Current.Items[key];
}
其他的
{
return(T)CallContext.GetData(key);
}
}
公共静态void SetItem(字符串键、对象值)
{
if(HttpContext.Current!=null)
{
HttpContext.Current.Items[key]=值;
}
其他的
{
SetData(键、值);
}
}
}
#端区
///
///将应用程序名称添加到连接字符串中,但仅当缺少该名称时。
///
///
///改良接头