tijian_tieying/web/cyqdata-master/DAL/DbBase.cs
2025-02-20 12:14:39 +08:00

1267 lines
44 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Data.Common;
using System.Data;
using System.Diagnostics;
using CYQ.Data.SQL;
using System.Collections.Generic;
using CYQ.Data.Tool;
using System.Data.SqlTypes;
using System.Threading;
namespace CYQ.Data
{
/// <summary>
/// 数据库操作基类 模板模式Template Method
/// </summary>
internal abstract class DbBase : IDisposable
{
// private static MDictionary<string, bool> _dbOperator = new MDictionary<string, bool>();//数据库是否更新中
/// <summary>
/// 记录SQL语句信息
/// </summary>
internal System.Text.StringBuilder debugInfo = new System.Text.StringBuilder();
/// <summary>
/// 是否允许进入写日志中模块
/// </summary>
internal bool isAllowInterWriteLog = true;
// internal bool isErrorOnExeCommand;
internal int recordsAffected = 0;//执行命令时所受影响的行数(-2为发生异常
internal bool isWriteLog = false;//默认不启用由AppSetting中配置控制出现是为不用配置文件内部手动控制启用。
internal bool isUseUnsafeModeOnSqlite = false;
internal bool isOpenTrans = false;
internal DalType dalType = DalType.MsSql;
private bool isAllowResetConn = true;//如果执行了非查询之后为了数据的一致性不允许切换到Slave数据库链接
internal string tempSql = string.Empty;//附加信息,包括调试信息
internal string conn = string.Empty;//原生态传进来的链接
internal string providerName = string.Empty;//传进来的名称
/// <summary>
/// 数据库链接实体(创建的时候被赋值);
/// </summary>
internal ConnObject connObject;
/// <summary>
/// 当前使用的链接对象
/// </summary>
internal ConnBean useConnBean;
private IsolationLevel _TranLevel = IsolationLevel.ReadCommitted;
internal IsolationLevel TranLevel
{
get
{
if (_tran != null && _com != null && _com.Transaction != null)
{
return _com.Transaction.IsolationLevel;
}
return _TranLevel;
}
set
{
if (_tran != null && _com != null && _com.Transaction != null)
{
Error.Throw("IsolationLevel is readonly when transaction is begining!");
}
else
{
_TranLevel = value;
}
}
}
protected DbProviderFactory _fac = null;
protected DbConnection _con = null;
protected DbCommand _com;
internal DbTransaction _tran;
private Stopwatch _watch;
/// <summary>
/// 获得链接的数据库名称
/// </summary>
public virtual string DataBase
{
get
{
if (!string.IsNullOrEmpty(_con.Database))
{
return _con.Database;
}
else if (dalType == DalType.Oracle)
{
// (DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=127.0.0.1)(PORT = 1521)))(CONNECT_DATA =(SID = Aries)))
int i = _con.DataSource.LastIndexOf('=') + 1;
return _con.DataSource.Substring(i).Trim(' ', ')');
}
else
{
return System.IO.Path.GetFileNameWithoutExtension(_con.DataSource);
}
}
}
public static MDictionary<string, string> _VersionCache = new MDictionary<string, string>();
private string _Version = string.Empty;
/// <summary>
/// 数据库的版本号
/// </summary>
public string Version
{
get
{
if (string.IsNullOrEmpty(_Version))
{
switch (dalType)
{
case DalType.Txt:
_Version = "txt2.0";
break;
case DalType.Xml:
_Version = "xml2.0";
break;
default:
if (_VersionCache.ContainsKey(conn))
{
_Version = _VersionCache[conn];
}
else
{
if (isOpenTrans && useConnBean.IsSlave)// && 事务操作时,如果在从库,切回主库
{
ResetConn(connObject.Master);
}
if (OpenCon(useConnBean, AllowConnLevel.MaterBackupSlave))//这里可能切换链接
{
_Version = _con.ServerVersion;
if (!_VersionCache.ContainsKey(conn))
{
_VersionCache.Set(conn, _Version);
}
if (!isOpenTrans)//避免把事务给关闭了。
{
CloseCon();
}
}
}
break;
}
}
return _Version;
}
}
public DbConnection Con
{
get
{
return _con;
}
}
public DbCommand Com
{
get
{
return _com;
}
}
private bool _IsAllowRecordSql = true;
/// <summary>
/// 是否允许记录SQL语句 (内部操作会关掉此值为False
/// </summary>
internal bool IsAllowRecordSql
{
get
{
return (AppConfig.Debug.OpenDebugInfo || AppConfig.Debug.SqlFilter > -1) && _IsAllowRecordSql;
}
set
{
_IsAllowRecordSql = value;
}
}
public DbBase(ConnObject co)
{
this.connObject = co;
this.useConnBean = co.Master;
this.conn = co.Master.Conn;
this.providerName = co.Master.ProviderName;
dalType = co.Master.ConnDalType;
_fac = GetFactory(providerName);
_con = _fac.CreateConnection();
try
{
_con.ConnectionString = DalCreate.FormatConn(dalType, conn);
}
catch (Exception err)
{
Error.Throw("check the connectionstring is be ok!" + AppConst.BR + "error:" + err.Message + AppConst.BR + conn);
}
_com = _con.CreateCommand();
if (_com != null)//Txt| Xml 时返回Null
{
_com.Connection = _con;
_com.CommandTimeout = AppConfig.DB.CommandTimeout;
}
if (IsAllowRecordSql)//开启秒表计算
{
_watch = new Stopwatch();
}
//if (AppConfig.DB.LockOnDbExe && dalType == DalType.Access)
//{
// string dbName = DataBase;
// if (!_dbOperator.ContainsKey(dbName))
// {
// try
// {
// _dbOperator.Add(dbName, false);
// }
// catch
// {
// }
// }
//}
//_com.CommandTimeout = 1;
}
protected virtual DbProviderFactory GetFactory(string providerName)
{
return DbProviderFactories.GetFactory(providerName);
}
#region
/// <summary>
/// 切换数据库(修改数据库链接)
/// </summary>
/// <param name="dbName"></param>
/// <returns></returns>
internal DbResetResult ChangeDatabase(string dbName)
{
if (_con.State == ConnectionState.Closed)//事务中。。不允许切换
{
try
{
if (IsExistsDbNameWithCache(dbName))//新的数据库不存在。。不允许切换
{
conn = GetNewConn(dbName);
_con.ConnectionString = DalCreate.FormatConn(dalType, conn);
connObject = DalCreate.GetConnObject(dbName + "Conn");
connObject.Master.ConfigName = dbName + "Conn";
connObject.Master.Conn = conn;
return DbResetResult.Yes;
}
else
{
return DbResetResult.No_DBNoExists;
}
}
catch (Exception err)
{
Log.WriteLogToTxt(err);
}
}
return DbResetResult.No_Transationing;
}
//检测并切换数据库链接。
internal DbResetResult ChangeDatabaseWithCheck(string dbTableName)//----------
{
if (IsOwnerOtherDb(dbTableName))//数据库名称变化了。
{
string dbName = dbTableName.Split('.')[0];
return ChangeDatabase(dbName);
}
return DbResetResult.No_SaveDbName;
}
internal DbBase ResetDbBase(string dbTableName)
{
if (IsOwnerOtherDb(dbTableName))//是其它数据库名称。
{
if (_con.State != ConnectionState.Closed)//事务中。。创建新链接切换
{
string dbName = dbTableName.Split('.')[0];
return DalCreate.CreateDal(GetNewConn(dbName));
}
}
return this;
}
/// <summary>
/// 是否数据库名称变化了
/// </summary>
/// <param name="dbTableName"></param>
/// <returns></returns>
private bool IsOwnerOtherDb(string dbTableName)
{
int index = dbTableName.IndexOf('.');//DBName.TableName
if (index > 0 && !dbTableName.Contains(" ")) //排除视图语句
{
string dbName = dbTableName.Split('.')[0];
if (string.Compare(DataBase, dbName, StringComparison.OrdinalIgnoreCase) != 0 && conn.IndexOf(DataBase) == conn.LastIndexOf(DataBase))
{
return true;
}
}
return false;
}
protected string GetNewConn(string dbName)
{
string newConn = AppConfig.GetConn(dbName + "Conn");
if (!string.IsNullOrEmpty(newConn))
{
return newConn;
}
return conn.Replace(DataBase, dbName);
}
static MDictionary<string, bool> dbList = new MDictionary<string, bool>(3);
private bool IsExistsDbNameWithCache(string dbName)
{
try
{
string key = dalType.ToString() + "." + dbName;
if (dbList.ContainsKey(key))
{
return dbList[key];
}
bool result = IsExistsDbName(dbName);
dbList.Add(key, result);
return result;
}
catch
{
return true;
}
}
protected abstract bool IsExistsDbName(string dbName);
#endregion
private int returnValue = -1;
/// <summary>
/// 存储过程返回值。
/// </summary>
public int ReturnValue
{
get
{
if (returnValue == -1 && _com != null && _com.Parameters != null && _com.Parameters.Count > 0)
{
for (int i = _com.Parameters.Count - 1; i >= 0; i--)
{
if (_com.Parameters[i].Direction == ParameterDirection.ReturnValue)
{
int.TryParse(Convert.ToString(_com.Parameters[i].Value), out returnValue);
break;
}
}
}
return returnValue;
}
set
{
returnValue = value;
}
}
/// <summary>
/// 存储过程OutPut输出参数值。
/// 如果只有一个输出,则为值;
/// 如果有多个输出则为Dictionary。
/// </summary>
public object OutPutValue
{
get
{
if (_com != null && _com.Parameters != null && _com.Parameters.Count > 0)
{
Dictionary<string, object> opValues = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
object outPutValue = null;
foreach (DbParameter para in _com.Parameters)
{
if (para.Direction == ParameterDirection.Output)
{
opValues.Add(para.ParameterName, para.Value);
outPutValue = para.Value;
}
}
if (opValues.Count < 2)
{
opValues = null;
return outPutValue;
}
return opValues;
}
return null;
}
}
public virtual char Pre
{
get
{
return '@';
}
}
#region
/// <summary>
/// 并发操作检测
/// </summary>
/// <returns></returns>
//private bool CheckIsConcurrent()
//{
// int waitTimes = 500;//5秒
// while (_dbOperator.ContainsKey(DataBase) && _dbOperator[DataBase] && waitTimes > -1)
// {
// waitTimes--;
// System.Threading.Thread.Sleep(10);
// if (waitTimes == 0)
// {
// return true;
// }
// }
// return false;
//}
private DbDataReader ExeDataReaderSQL(string cmdText, bool isProc)
{
DbDataReader sdr = null;
ConnBean coSlave = null;
if (!isOpenTrans)// && _IsAllowRecordSql
{
coSlave = connObject.GetSlave();
}
else if (useConnBean.IsSlave)// && 事务操作时,如果在从库,切回主库
{
ResetConn(connObject.Master);
}
if (OpenCon(coSlave, AllowConnLevel.MaterBackupSlave))
{
try
{
CommandBehavior cb = CommandBehavior.CloseConnection;
if (_IsAllowRecordSql)//外部SQL带表结构返回
{
cb = isOpenTrans ? CommandBehavior.KeyInfo : CommandBehavior.CloseConnection | CommandBehavior.KeyInfo;
}
else if (isOpenTrans)
{
cb = CommandBehavior.Default;//避免事务时第一次拿表结构链接被关闭。
}
sdr = _com.ExecuteReader(cb);
if (sdr != null)
{
recordsAffected = sdr.RecordsAffected;
}
}
catch (DbException err)
{
string msg = "ExeDataReader():" + err.Message;
debugInfo.Append(msg + AppConst.BR);
recordsAffected = -2;
WriteError(msg + (isProc ? "" : AppConst.BR + GetParaInfo(cmdText)));
}
//finally
//{
// if (coSlave != null)
// {
// ChangeConn(connObject.Master);//恢复链接。
// }
//}
}
return sdr;
}
public DbDataReader ExeDataReader(string cmdText, bool isProc)
{
SetCommandText(cmdText, isProc);
DbDataReader sdr = null;
//if (_dbOperator.ContainsKey(DataBase))
//{
// if (!CheckIsConcurrent())
// {
// // dbOperator[DataBase] = true;
// sdr = ExeDataReaderSQL(cmdText, isProc);
// // dbOperator[DataBase] = false;
// }
//}
//else
//{
sdr = ExeDataReaderSQL(cmdText, isProc);
//}
WriteTime();
return sdr;
}
private int ExeNonQuerySQL(string cmdText, bool isProc)
{
recordsAffected = -2;
if (isOpenTrans && useConnBean.IsSlave)// && 事务操作时,如果在从库,切回主库
{
ResetConn(connObject.Master);
}
if (OpenCon())//这里也会切库了。
{
try
{
if (useConnBean.Conn != connObject.Master.Conn)
{
// recordsAffected = -2;//从库不允许执行非查询操作。
string msg = "You can't do ExeNonQuerySQL() on Slave DataBase!";
debugInfo.Append(msg + AppConst.BR);
WriteError(msg + (isProc ? "" : AppConst.BR + GetParaInfo(cmdText)));
}
else
{
if (isUseUnsafeModeOnSqlite && !isProc && dalType == DalType.SQLite && !isOpenTrans)
{
_com.CommandText = "PRAGMA synchronous=Off;" + _com.CommandText;
}
recordsAffected = _com.ExecuteNonQuery();
}
}
catch (DbException err)
{
string msg = "ExeNonQuery():" + err.Message;
debugInfo.Append(msg + AppConst.BR);
//recordsAffected = -2;
WriteError(msg + (isProc ? "" : AppConst.BR + GetParaInfo(cmdText)));
}
finally
{
if (!isOpenTrans)
{
CloseCon();
}
}
}
return recordsAffected;
}
public int ExeNonQuery(string cmdText, bool isProc)
{
SetCommandText(cmdText, isProc);
int rowCount = 0;
//if (_dbOperator.ContainsKey(DataBase))
//{
// if (!CheckIsConcurrent())
// {
// _dbOperator[DataBase] = true;
// rowCount = ExeNonQuerySQL(cmdText, isProc);
// _dbOperator[DataBase] = false;
// }
//}
//else
//{
rowCount = ExeNonQuerySQL(cmdText, isProc);
//}
WriteTime();
return rowCount;
}
private object ExeScalarSQL(string cmdText, bool isProc)
{
object returnValue = null;
ConnBean coSlave = null;
//mssql 有 insert into ...select 操作。
bool isSelectSql = !isOpenTrans && !cmdText.ToLower().TrimStart().StartsWith("insert ");//&& _IsAllowRecordSql
if (isSelectSql)
{
coSlave = connObject.GetSlave();
}
else if (useConnBean.IsSlave) // 如果是在从库,切回主库。(insert ...select 操作)
{
ResetConn(connObject.Master);
}
if (OpenCon(coSlave, AllowConnLevel.MaterBackupSlave))
{
try
{
if (!isSelectSql && useConnBean.Conn != connObject.Master.Conn)
{
recordsAffected = -2;//从库不允许执行非查询操作。
string msg = "You can't do ExeScalarSQL(with transaction or insert) on Slave DataBase!";
debugInfo.Append(msg + AppConst.BR);
WriteError(msg + (isProc ? "" : AppConst.BR + GetParaInfo(cmdText)));
}
else
{
returnValue = _com.ExecuteScalar();
recordsAffected = returnValue == null ? 0 : 1;
}
}
catch (DbException err)
{
string msg = "ExeScalar():" + err.Message;
debugInfo.Append(msg + AppConst.BR);
recordsAffected = -2;
WriteError(msg + (isProc ? "" : AppConst.BR + GetParaInfo(cmdText)));
}
finally
{
if (!isOpenTrans)
{
CloseCon();
}
}
}
return returnValue;
}
public object ExeScalar(string cmdText, bool isProc)
{
SetCommandText(cmdText, isProc);
object returnValue = null;
//if (_dbOperator.ContainsKey(DataBase))
//{
// if (!CheckIsConcurrent())
// {
// returnValue = ExeScalarSQL(cmdText, isProc);
// }
//}
//else
//{
returnValue = ExeScalarSQL(cmdText, isProc);
//}
WriteTime();
return returnValue;
}
/*
private DataTable ExeDataTableSQL(string cmdText, bool isProc)
{
DbDataAdapter sdr = _fac.CreateDataAdapter();
sdr.SelectCommand = _com;
DataTable dataTable = null;
if (OpenCon())
{
try
{
dataTable = new DataTable();
recordsAffected = sdr.Fill(dataTable);
}
catch (DbException err)
{
recordsAffected = -2;
WriteError("ExeDataTable():" + err.Message + (isProc ? "" : AppConst.BR + GetParaInfo(cmdText)));
}
finally
{
sdr.Dispose();
if (!isOpenTrans)
{
CloseCon();
}
}
}
return dataTable;
}
public DataTable ExeDataTable(string cmdText, bool isProc)
{
SetCommandText(cmdText, isProc);
DataTable dataTable = null;
//if (_dbOperator.ContainsKey(DataBase))
//{
// if (!CheckIsConcurrent())
// {
// dataTable = ExeDataTableSQL(cmdText, isProc);
// }
//}
//else
//{
dataTable = ExeDataTableSQL(cmdText, isProc);
//}
WriteTime();
return dataTable;
}
*/
#endregion
public bool AddParameters(string parameterName, object value)
{
return AddParameters(parameterName, value, DbType.String, -1, ParameterDirection.Input);
}
public virtual bool AddParameters(string parameterName, object value, DbType dbType, int size, ParameterDirection direction)
{
if (dalType == DalType.Oracle)
{
parameterName = parameterName.Replace(":", "").Replace("@", "");
if (dbType == DbType.String && size > 4000)
{
AddCustomePara(parameterName, size == int.MaxValue ? ParaType.CLOB : ParaType.NCLOB, value, null);
return true;
}
}
else
{
parameterName = parameterName.Substring(0, 1) == Pre.ToString() ? parameterName : Pre + parameterName;
}
if (Com.Parameters.Contains(parameterName))//已经存在,不添加
{
return false;
}
DbParameter para = _fac.CreateParameter();
para.ParameterName = parameterName;
para.Value = value == null ? DBNull.Value : value;
if (dbType == DbType.Time)// && dalType != DalType.MySql
{
para.DbType = DbType.String;
}
else
{
if (dbType == DbType.DateTime && value != null)
{
string time = Convert.ToString(value);
if (dalType == DalType.MsSql && time == DateTime.MinValue.ToString())
{
para.Value = SqlDateTime.MinValue;
}
else if (dalType == DalType.MySql && (time == SqlDateTime.MinValue.ToString() || time == DateTime.MinValue.ToString()))
{
para.Value = DateTime.MinValue;
}
}
para.DbType = dbType;
}
if (dbType == DbType.Binary && dalType == DalType.MySql)//mysql不能设定长度否则会报索引超出了数组界限错误【已过时旧版本的MySql.Data.dll不能指定长度】
{
if (value != null)
{
byte[] bytes = value as byte[];
para.Size = bytes.Length;//新版本的MySql.Data.dll 修正了长度指定不指定就没数据进去所以又要指定长度Shit
}
else
{
para.Size = -1;
}
}
else if (dbType != DbType.Binary && size > -1)
{
if (size != para.Size)
{
para.Size = size;
}
}
para.Direction = direction;
Com.Parameters.Add(para);
return true;
}
internal virtual void AddCustomePara(string paraName, ParaType paraType, object value, string typeName)
{
switch (paraType)
{
case ParaType.OutPut:
AddParameters(paraName, null, DbType.String, 2000, ParameterDirection.Output);
break;
case ParaType.InputOutput:
AddParameters(paraName, null, DbType.String, 2000, ParameterDirection.InputOutput);
break;
case ParaType.ReturnValue:
AddParameters(paraName, null, DbType.Int32, 32, ParameterDirection.ReturnValue);
break;
}
}
//internal virtual void AddCustomePara(string paraName, ParaType paraType, object value)
//{
//}
//public abstract DbParameter GetNewParameter();
public void ClearParameters()
{
if (_com != null && _com.Parameters != null)
{
_com.Parameters.Clear();
}
}
/// <summary>
/// 处理内置的MSSQL和Oracle两种存储过程分页
/// </summary>
protected virtual void AddReturnPara() { }
private void SetCommandText(string commandText, bool isProc)
{
if (OracleDal.clientType > 0)
{
Type t = _com.GetType();
System.Reflection.PropertyInfo pi = t.GetProperty("BindByName");
if (pi != null)
{
pi.SetValue(_com, true, null);
}
}
_com.CommandText = isProc ? commandText : SqlFormat.Compatible(commandText, dalType, false);
if (!isProc && dalType == DalType.SQLite && _com.CommandText.Contains("charindex"))
{
_com.CommandText += " COLLATE NOCASE";//忽略大小写
}
//else if (isProc && dalType == DalType.MySql)
//{
// _com.CommandText = "Call " + _com.CommandText;
//}
_com.CommandType = isProc ? CommandType.StoredProcedure : CommandType.Text;
if (isProc)
{
if (commandText.Contains("SelectBase") && !_com.Parameters.Contains("ReturnValue"))
{
AddReturnPara();
//检测是否存在分页存储过程,若不存在,则创建。
Tool.DBTool.CreateSelectBaseProc(dalType, conn);//内部分检测是否已创建过。
}
}
else
{
//取消多余的参数,新加的小贴心,过滤掉用户不小心写多的参数。
if (_com != null && _com.Parameters != null && _com.Parameters.Count > 0)
{
bool needToReplace = (dalType == DalType.Oracle || dalType == DalType.MySql) && _com.CommandText.Contains("@");
string paraName;
for (int i = 0; i < _com.Parameters.Count; i++)
{
paraName = _com.Parameters[i].ParameterName.TrimStart(Pre);//默认自带前缀的,取消再判断
if (needToReplace && _com.CommandText.IndexOf("@" + paraName) > -1)
{
//兼容多数据库的参数(虽然提供了=:?"为兼容语法,但还是贴心的再处理一下)
switch (dalType)
{
case DalType.Oracle:
case DalType.MySql:
_com.CommandText = _com.CommandText.Replace("@" + paraName, Pre + paraName);
break;
}
}
if (_com.CommandText.IndexOf(Pre + paraName, StringComparison.OrdinalIgnoreCase) == -1)
{
_com.Parameters.RemoveAt(i);
i--;
}
}
}
}
//else
//{
// string checkText = commandText.ToLower();
// //int index=
// //if (checkText.IndexOf("table") > -1 && (checkText.IndexOf("delete") > -1 || checkText.IndexOf("drop") > -1 || checkText.IndexOf("truncate") > -1))
// //{
// // Log.WriteLog(commandText);
// //}
//}
if (IsAllowRecordSql)
{
tempSql = GetParaInfo(_com.CommandText) + AppConst.BR + "execute time is: ";
}
}
private string GetParaInfo(string commandText)
{
string paraInfo = dalType + "." + DataBase + ".SQL: " + AppConst.BR + commandText;
foreach (DbParameter item in _com.Parameters)
{
paraInfo += AppConst.BR + "Para: " + item.ParameterName + "-> " + (item.Value == DBNull.Value ? "DBNull.Value" : item.Value);
}
return paraInfo;
}
/// <summary>
/// 记录执行时间
/// </summary>
private void WriteTime()
{
if (IsAllowRecordSql && _watch != null)
{
_watch.Stop();
double ms = _watch.Elapsed.TotalMilliseconds;
tempSql += ms + " (ms)" + AppConst.HR;
if (AppConfig.Debug.OpenDebugInfo)
{
debugInfo.Append(tempSql);
if (AppDebug.IsRecording && ms >= AppConfig.Debug.InfoFilter)
{
AppDebug.Add(tempSql);
}
}
if (AppConfig.Debug.SqlFilter >= 0 && ms >= AppConfig.Debug.SqlFilter)
{
Log.WriteLogToTxt(tempSql, "SqlFilter_");
}
_watch.Reset();
tempSql = null;
}
}
#region IDisposable
public void Dispose()
{
if (_con != null)
{
CloseCon();
_con = null;
}
if (_com != null)
{
_com = null;
}
if (_watch != null)
{
_watch = null;
}
}
int threadCount = 0;
/// <summary>
/// 测试链接
/// </summary>
/// <param name="allowLevel">1只允许当前主链接2允许主备链接3允许主备从链接</param>
/// <returns></returns>
internal bool TestConn(AllowConnLevel allowLevel)
{
threadCount = 0;
openOKFlag = -1;
ConnObject obj = connObject;
if (obj.Master != null && obj.Master.IsOK && (int)allowLevel >= 1)
{
threadCount++;
Thread thread = new Thread(new ParameterizedThreadStart(TestOpen));
thread.Start(obj.Master);
}
Thread.Sleep(30);
if (openOKFlag == -1 && obj.BackUp != null && obj.BackUp.IsOK && (int)allowLevel >= 2)
{
threadCount++;
Thread.Sleep(30);
Thread thread = new Thread(new ParameterizedThreadStart(TestOpen));
thread.Start(obj.BackUp);
}
if (openOKFlag == -1 && obj.Slave != null && obj.Slave.Count > 0 && (int)allowLevel >= 3)
{
for (int i = 0; i < obj.Slave.Count; i++)
{
Thread.Sleep(30);
if (openOKFlag == -1 && obj.Slave[i].IsOK)
{
threadCount++;
Thread thread = new Thread(new ParameterizedThreadStart(TestOpen));
thread.Start(obj.Slave[i]);
}
}
}
int sleepTimes = 0;
while (openOKFlag == -1)
{
sleepTimes += 30;
if (sleepTimes > 3000 || threadCount == errorCount)
{
break;
}
Thread.Sleep(30);
}
return openOKFlag == 1;
}
private int openOKFlag = -1;
private int errorCount = 0;
private void TestOpen(object para)
{
ConnBean connBean = para as ConnBean;
if (connBean != null && connBean.IsOK && openOKFlag == -1)
{
string v = connBean.TryTestConn();//顺带设置版本号。
if (connBean.IsOK && openOKFlag != 1)
{
openOKFlag = 1;
_Version = v;
ResetConn(connBean);//切到正常的去。
}
else
{
errorCount++;
debugInfo.Append(connBean.ErrorMsg);
}
}
}
/// <summary>
/// 切换链接
/// </summary>
/// <param name="cb"></param>
private bool ResetConn(ConnBean cb)//, bool isAllowReset
{
if (cb != null && cb.IsOK && _con != null && _con.State != ConnectionState.Open && conn != cb.Conn)
{
useConnBean = cb;
conn = cb.Conn;//切换。
_con.ConnectionString = DalCreate.FormatConn(dalType, conn);
return true;
}
return false;
}
/// <summary>
/// 打开链接只切主备
/// </summary>
/// <returns></returns>
internal bool OpenCon()
{
ConnBean master = connObject.Master;
if (!master.IsOK && connObject.BackUp != null && connObject.BackUp.IsOK)
{
master = connObject.BackUp;
connObject.InterChange();//主从换位置
}
if (master.IsOK || (connObject.BackUp != null && connObject.BackUp.IsOK))
{
bool result = OpenCon(master, AllowConnLevel.MasterBackup);
if (result && _IsAllowRecordSql)
{
connObject.SetNotAllowSlave();
isAllowResetConn = false;
}
return result;
}
return false;
}
/// <summary>
/// 打开链接,允许切从。
/// </summary>
internal bool OpenCon(ConnBean cb, AllowConnLevel leve)
{
try
{
if (cb == null)
{
cb = useConnBean;
if (isOpenTrans && cb.IsSlave)
{
ResetConn(connObject.Master);
}
}
if (!cb.IsOK)
{
if ((int)leve > 1 && connObject.BackUp != null && connObject.BackUp.IsOK)
{
ResetConn(connObject.BackUp);//重置链接。
connObject.InterChange();//主从换位置
return OpenCon(connObject.Master, leve);
}
else if ((int)leve > 2)
{
//主挂了,备也挂了(因为备会替主)
ConnBean nextSlaveBean = connObject.GetSlave();
if (nextSlaveBean != null)
{
ResetConn(nextSlaveBean);//重置链接。
return OpenCon(nextSlaveBean, leve);
}
}
}
else if (!isOpenTrans && cb != useConnBean && isAllowResetConn && connObject.IsAllowSlave())
{
ResetConn(cb);//,_IsAllowRecordSql只有读数据错误才切表结构错误不切
}
if (useConnBean.IsOK)
{
Open();//异常抛
}
else
{
WriteError("OpenCon():" + useConnBean.ErrorMsg);
}
if (IsAllowRecordSql)
{
_watch.Start();
}
return useConnBean.IsOK;
}
catch (DbException err)
{
useConnBean.IsOK = false;
useConnBean.ErrorMsg = err.Message;
return OpenCon(null, leve);
}
}
private void Open()
{
if (_con.State == ConnectionState.Closed)
{
if (dalType == DalType.Sybase)
{
_com.Connection = _con;//重新赋值Sybase每次Close后命令的Con都丢失
}
_con.Open();
//if (useConnBean.ConfigName == "Conn")
//{
//System.Console.WriteLine(useConnBean.ConfigName);
//}
}
if (isOpenTrans)
{
if (_tran == null)
{
_tran = _con.BeginTransaction(TranLevel);
_com.Transaction = _tran;
}
else if (_tran.Connection == null)
{
//ADO.NET Bug在 guid='123' 时不抛异常,但自动关闭链接,不关闭对象,会引发后续的业务不在事务中。
Dispose();
Error.Throw("TransationLast execute command has syntax error" + debugInfo.ToString());
}
}
}
/*
private bool OpenConBak()
{
try
{
if (connObject.ProviderName == connObject.ProviderNameBak)//同种数据库链接。
{
conn = connObject.ConnBak;//切换到备用。
_con.ConnectionString = conn;//切换到备用。
Open();
//交换主从链接
connObject.ExchangeConn();
if (IsAllowRecordSql)
{
_watch.Start();
}
return true;
}
else
{
connObject.ExchangeConn();//不同种,切换链接后,本次操作直接抛异常
}
}
catch (DbException err)
{
WriteError("OpenConBak():" + err.Message);
}
return false;
}
*/
internal void CloseCon()
{
try
{
if (_con.State != ConnectionState.Closed)
{
if (_tran != null)
{
isOpenTrans = false;
if (_tran.Connection != null)
{
_tran.Commit();
}
_tran = null;
}
_con.Close();
}
}
catch (DbException err)
{
WriteError("CloseCon():" + err.Message);
}
}
public bool EndTransaction()
{
isOpenTrans = false;
if (_tran != null)
{
try
{
if (_tran.Connection == null)
{
return false;//上一个执行语句发生了异常特殊情况在ExeReader guid='xxx' 但不抛异常)
}
_tran.Commit();
}
catch (Exception err)
{
RollBack();
WriteError("EndTransaction():" + err.Message);
return false;
}
finally
{
_tran = null;
CloseCon();
}
}
return true;
}
/// <summary>
/// 事务(有则)回滚
/// </summary>
/// <returns></returns>
public bool RollBack()
{
if (_tran != null)
{
try
{
if (_tran.Connection != null)
{
_tran.Rollback();
}
}
catch (Exception)
{
return false;
}
finally
{
_tran = null;//以便重启事务,避免无法二次回滚。
}
}
return true;
}
internal delegate void OnException(string msg);
internal event OnException OnExceptionEvent;
internal bool IsOnExceptionEventNull
{
get
{
return OnExceptionEvent == null;
}
}
/// <summary>
/// 输出错误(若事务中,回滚事务)
/// </summary>
/// <param name="err"></param>
internal void WriteError(string err)
{
err = dalType + " Call Function::" + err;
if (_watch != null && _watch.IsRunning)
{
_watch.Stop();
_watch.Reset();
}
RollBack();
if (isAllowInterWriteLog)
{
Log.WriteLog(isWriteLog, err + AppConst.BR + debugInfo);
}
if (OnExceptionEvent != null)
{
try
{
OnExceptionEvent(err);
}
catch
{
}
}
if (isOpenTrans)
{
Dispose();//事务中发生语句语法错误,直接关掉资源,避免因后续代码继续执行。
}
}
#endregion
}
}