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
{
///
/// 数据库操作基类 (模板模式:Template Method)
///
internal abstract class DbBase : IDisposable
{
// private static MDictionary _dbOperator = new MDictionary();//数据库是否更新中
///
/// 记录SQL语句信息
///
internal System.Text.StringBuilder debugInfo = new System.Text.StringBuilder();
///
/// 是否允许进入写日志中模块
///
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;//传进来的名称
///
/// 数据库链接实体(创建的时候被赋值);
///
internal ConnObject connObject;
///
/// 当前使用的链接对象
///
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;
///
/// 获得链接的数据库名称
///
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 _VersionCache = new MDictionary();
private string _Version = string.Empty;
///
/// 数据库的版本号
///
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;
///
/// 是否允许记录SQL语句 (内部操作会关掉此值为False)
///
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 数据库链接切换相关逻辑
///
/// 切换数据库(修改数据库链接)
///
///
///
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;
}
///
/// 是否数据库名称变化了
///
///
///
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 dbList = new MDictionary(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;
///
/// 存储过程返回值。
///
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;
}
}
///
/// 存储过程OutPut输出参数值。
/// 如果只有一个输出,则为值;
/// 如果有多个输出,则为Dictionary。
///
public object OutPutValue
{
get
{
if (_com != null && _com.Parameters != null && _com.Parameters.Count > 0)
{
Dictionary opValues = new Dictionary(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 执行
///
/// 并发操作检测
///
///
//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();
}
}
///
/// 处理内置的MSSQL和Oracle两种存储过程分页
///
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;
}
///
/// 记录执行时间
///
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;
///
/// 测试链接
///
/// 1:只允许当前主链接;2:允许主备链接;3:允许主备从链接
///
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);
}
}
}
///
/// 切换链接
///
///
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;
}
///
/// 打开链接只切主备
///
///
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;
}
///
/// 打开链接,允许切从。
///
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("Transation:Last 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;
}
///
/// 事务(有则)回滚
///
///
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;
}
}
///
/// 输出错误(若事务中,回滚事务)
///
///
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
}
}