ZhiYeJianKang_PeiXun/cyqdata-master/DAL/DalBase.cs

1450 lines
50 KiB
C#
Raw Normal View History

2025-02-20 15:41:53 +08:00
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;
using CYQ.Data.Orm;
using System.IO;
using CYQ.Data.Json;
namespace CYQ.Data
{
/// <summary>
/// 数据库操作基类 模板模式Template Method
/// 属性管理
/// </summary>
internal abstract partial class DalBase : IDisposable
{
#region
/// <summary>
/// 记录SQL语句信息
/// </summary>
public System.Text.StringBuilder DebugInfo = new System.Text.StringBuilder();
/// <summary>
/// 执行命令时所受影响的行数(-2为发生异常
/// </summary>
public int RecordsAffected = 0;
/// <summary>
/// 当前是否开启事务
/// </summary>
public bool IsOpenTrans = false;
/// <summary>
/// 原生态传进来的配置名(或链接)
/// </summary>
public string ConnName
{
get
{
return !ConnObj.Master.IsBackup ? ConnObj.Master.ConnName : ConnObj.BackUp.ConnName;
}
}
/// <summary>
/// 数据库主从备链接管理对象;
/// </summary>
public ConnObject ConnObj;
/// <summary>
/// 当前使用中的链接对象
/// </summary>
public ConnBean UsingConnBean;
/// <summary>
/// 获得链接的数据库名称
/// </summary>
public virtual string DataBaseName
{
get
{
if (!string.IsNullOrEmpty(_con.Database))
{
return _con.Database;
}
else
{
return System.IO.Path.GetFileNameWithoutExtension(_con.DataSource);
}
}
}
/// <summary>
/// 获得链接的模式名称
/// </summary>
public virtual string SchemaName
{
get { return DataBaseName; }
}
private static MDictionary<string, string> _VersionCache = new MDictionary<string, string>();
private string _Version = string.Empty;
/// <summary>
/// 数据库的版本号
/// </summary>
public string Version
{
get
{
if (string.IsNullOrEmpty(_Version))
{
if (_VersionCache.ContainsKey(ConnName))
{
_Version = _VersionCache[ConnName];
}
else
{
if (IsOpenTrans && UsingConnBean.IsSlave)// && 事务操作时,如果在从库,切回主库
{
ResetConn(ConnObj.Master);
}
if (OpenCon(UsingConnBean, AllowConnLevel.MaterBackupSlave))//这里可能切换链接
{
_Version = _con.ServerVersion;
if (!_VersionCache.ContainsKey(ConnName))
{
_VersionCache.Set(ConnName, _Version);
}
if (!IsOpenTrans)//避免把事务给关闭了。
{
CloseCon();
}
}
}
}
return _Version;
}
}
/// <summary>
/// 当前操作的数据库类型
/// </summary>
public DataBaseType DataBaseType
{
get
{
return ConnObj.Master.ConnDataBaseType;
}
}
#endregion
/// <summary>
/// 是否允许进入写日志中模块(默认true)
/// </summary>
public bool IsWriteLogOnError = true;
protected bool isUseUnsafeModeOnSqlite = false;
//private bool isAllowResetConn = true;//如果执行了非查询之后为了数据的一致性不允许切换到Slave数据库链接
private string tempSql = string.Empty;//附加信息,包括调试信息
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 DbConnection Con
{
get
{
return _con;
}
}
public DbCommand Com
{
get
{
return _com;
}
}
private bool _IsRecordDebugInfo = true;
/// <summary>
/// 是否允许记录SQL语句 (内部操作会关掉此值为False
/// </summary>
public bool IsRecordDebugInfo
{
get
{
return _IsRecordDebugInfo && (AppConfig.Debug.IsEnable || AppConfig.DB.PrintSql >= 0 || AppDebug.IsRecording);
}
set
{
_IsRecordDebugInfo = value;
}
}
public DalBase(ConnObject co)
{
this.ConnObj = co;
this.UsingConnBean = co.Master;
_fac = GetFactory();
_con = _fac.CreateConnection();
try
{
_con.ConnectionString = co.Master.ConnString;
//if (DataBaseName.Contains("dm"))
//{
//}
}
catch (Exception err)
{
Error.Throw("check the connectionstring is be ok!" + AppConst.BR + "error:" + err.Message + AppConst.BR + ConnName);
}
_com = _con.CreateCommand();
if (_com != null)//Txt| Xml 时返回Null
{
_com.Connection = _con;
_com.CommandTimeout = AppConfig.DB.CommandTimeout;
}
if (IsRecordDebugInfo)//开启秒表计算
{
_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 abstract DbProviderFactory GetFactory();
#region
public virtual Dictionary<string, string> GetTables()
{
return GetSchemaDic(GetUVPSql("U"), "U", false);
}
public virtual Dictionary<string, string> GetTables(bool isIgnoreCache)
{
return GetSchemaDic(GetUVPSql("U"), "U", isIgnoreCache);
}
public virtual Dictionary<string, string> GetViews()
{
return GetSchemaDic(GetUVPSql("V"), "V", false);
}
public virtual Dictionary<string, string> GetViews(bool isIgnoreCache)
{
return GetSchemaDic(GetUVPSql("V"), "V", isIgnoreCache);
}
public virtual Dictionary<string, string> GetProcs()
{
return GetSchemaDic(GetUVPSql("P"), "P", false);
}
public virtual Dictionary<string, string> GetProcs(bool isIgnoreCache)
{
return GetSchemaDic(GetUVPSql("P"), "P", isIgnoreCache);
}
protected Dictionary<string, string> GetSchemaDic(string sql, string type, bool isIgnoreCache)
{
if (string.IsNullOrEmpty(sql))
{
return null;
}
Dictionary<string, string> dic = null;
string key = ConnBean.GetHashKey(ConnName) + "_" + DataBaseName + "_" + type + "_" + StaticTool.GetHashKey(sql);
#region
dic = Cache.DistributedCache.Local.Get(key) as Dictionary<string, string>;//缓存3秒避免后台线程和代码重复读取
if (dic != null) { return dic; }
#endregion
#region
if (!isIgnoreCache)
{
if (!string.IsNullOrEmpty(AppConfig.DB.SchemaMapPath))
{
string fullPath = AppConfig.WebRootPath + AppConfig.DB.SchemaMapPath.Trim('/', '\\') + "/" + key + ".json";
if (System.IO.File.Exists(fullPath))
{
string json = IOHelper.ReadAllText(fullPath);
if (!string.IsNullOrEmpty(json))
{
dic = JsonHelper.ToEntity<Dictionary<string, string>>(json);
if (dic != null && dic.Count > 0)
{
return dic;
}
}
}
}
}
#endregion
lock (sql)
{
//锁住后,读取缓存,避免后台线程和代码重复读取
dic = Cache.DistributedCache.Local.Get(key) as Dictionary<string, string>;
if (dic != null)
{
return dic;
}
dic = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
IsRecordDebugInfo = false || AppDebug.IsContainSysSql;
DbDataReader sdr = ExeDataReader(sql, false);
IsRecordDebugInfo = true;
if (sdr != null)
{
while (sdr.Read())
{
string tableName = Convert.ToString(sdr["TableName"]).Trim();
if (!dic.ContainsKey(tableName))
{
dic.Add(tableName, Convert.ToString(sdr["Description"]));
}
}
sdr.Close();
sdr = null;
}
#region
if (dic != null)
{
Cache.DistributedCache.Local.Set(key, dic, 0.05);//缓存3秒避免后台线程和代码重复读取
}
#endregion
}
#region
if (dic != null && dic.Count > 0)
{
if (!string.IsNullOrEmpty(AppConfig.DB.SchemaMapPath))
{
//缓存写入硬盘
Thread thread = new Thread(() =>
{
string fullPath = AppConfig.WebRootPath + AppConfig.DB.SchemaMapPath.Trim('/', '\\') + "/" + key + ".json";
string folder = Path.GetDirectoryName(fullPath);
if (!System.IO.Directory.Exists(folder))
{
System.IO.Directory.CreateDirectory(folder);
}
string json = JsonHelper.ToJson(dic);
IOHelper.Write(fullPath, json);
});
thread.Start();
}
}
#endregion
return dic;
}
/// <summary>
/// 读取表名、视图、存储过程列表
/// </summary>
/// <param name="type">U、V、P</param>
/// <returns></returns>
protected virtual string GetUVPSql(string type)
{
return "";
}
#endregion
#region
/// <summary>
/// 切换数据库(修改数据库链接)
/// </summary>
internal DBResetResult ChangeDatabase(string dbName)
{
if (_con.State == ConnectionState.Closed && !IsOpenTrans)//事务中。。不允许切换
{
try
{
if (IsExistsDbNameWithCache(dbName))//新的数据库不存在。。不允许切换
{
string newConnString = GetConnString(dbName);
_con.ConnectionString = newConnString;
ConnObj = ConnObject.Create(dbName + "Conn");
ConnObj.Master.ConnName = dbName + "Conn";
ConnObj.Master.ConnString = newConnString;
return DBResetResult.Yes;
}
else
{
return DBResetResult.No_DBNoExists;
}
}
catch (Exception err)
{
Log.Write(err, LogType.DataBase);
}
}
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 DalBase ResetDalBase(string dbTableName)
{
if (IsOwnerOtherDb(dbTableName))//是其它数据库名称。
{
if (_con.State != ConnectionState.Closed)//事务中。。创建新链接切换
{
string dbName = dbTableName.Split('.')[0];
return DalCreate.CreateDal(GetConnString(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(DataBaseName, dbName, StringComparison.OrdinalIgnoreCase) != 0 && ConnName.IndexOf(DataBaseName) == ConnName.LastIndexOf(DataBaseName))
{
return true;
}
}
return false;
}
protected string GetConnString(string dbName)
{
string newConn = AppConfig.GetConn(dbName + "Conn");
if (!string.IsNullOrEmpty(newConn))
{
ConnBean bean = ConnBean.Create(newConn);
if (bean != null)
{
return bean.ConnString;
}
return "";
}
return UsingConnBean.ConnString.Replace(DataBaseName, dbName);
}
static MDictionary<string, bool> dbList = new MDictionary<string, bool>(3);
private bool IsExistsDbNameWithCache(string dbName)
{
try
{
string key = DataBaseType.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
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 (DataBaseType == DataBaseType.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 == null)
{
return false;
}
if (Com.Parameters.Contains(parameterName))//已经存在,不添加
{
return false;
}
DbParameter para = _com.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 (DataBaseType == DataBaseType.MsSql && time == DateTime.MinValue.ToString())
{
para.Value = SqlDateTime.MinValue;
}
else if (DataBaseType == DataBaseType.MySql && (time == SqlDateTime.MinValue.ToString() || time == DateTime.MinValue.ToString()))
{
para.Value = DateTime.MinValue;
}
}
para.DbType = dbType;
}
if (dbType == DbType.Binary && DataBaseType == DataBaseType.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 > 0)
{
if (size != para.Size)
{
para.Size = size;
}
}
para.Direction = direction;
if (para.DbType == DbType.String && para.Value != null)
{
para.Value = Convert.ToString(para.Value);
}
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 (_com == null && DebugInfo.Length > 0)
{
throw new Exception("DalBase.SetCommandText stop running because : " + DebugInfo.ToString());
}
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, DataBaseType, false);
if (!isProc)
{
if (DataBaseType == DataBaseType.SQLite && _com.CommandText.Contains("charindex"))
{
_com.CommandText += " COLLATE NOCASE";//忽略大小写
}
//else if (DataBaseType == DataBaseType.DaMeng && !string.IsNullOrEmpty(DataBaseName))
//{
// _com.CommandText = "set schema " + DataBaseName + ";" + _com.CommandText;
//}
}
_com.CommandType = isProc ? CommandType.StoredProcedure : CommandType.Text;
//if (isProc)
//{
// if (commandText.Contains("SelectBase") && !_com.Parameters.Contains("ReturnValue"))
// {
// AddReturnPara();
// //检测是否存在分页存储过程,若不存在,则创建。
// Tool.DBTool.CreateSelectBaseProc(DataBaseType, ConnName);//内部分检测是否已创建过。
// }
//}
//else
//{
//上面if代码被注释了下面代码忘了加!isProc判断现补上。 取消多余的参数,新加的小贴心,过滤掉用户不小心写多的参数。
if (!isProc && _com != null && _com.Parameters != null && _com.Parameters.Count > 0)
{
bool needToReplace = (DataBaseType == DataBaseType.Oracle || DataBaseType == DataBaseType.MySql || DataBaseType == Data.DataBaseType.PostgreSQL) && _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 (DataBaseType)
{
case DataBaseType.Oracle:
case DataBaseType.MySql:
case Data.DataBaseType.PostgreSQL:
_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 (IsRecordDebugInfo)
{
tempSql = GetParaInfo(_com.CommandText) + AppConst.BR + "execute time is: ";
}
}
#endregion
#region
private string GetParaInfo(string commandText)
{
string paraInfo = DataBaseType + "." + DataBaseName + ".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 (IsRecordDebugInfo && _watch != null)
{
_watch.Stop();
double ms = _watch.Elapsed.TotalMilliseconds;
_watch.Reset();
tempSql += ms + " (ms)" + AppConst.HR;
if (AppConfig.Debug.IsEnable)
{
DebugInfo.Append(tempSql);
}
if (AppDebug.IsRecording && ms >= AppDebug.InfoFilter)
{
AppDebug.Add(tempSql);
}
if (AppConfig.DB.PrintSql >= 0 && ms >= AppConfig.DB.PrintSql)
{
Log.WriteLogToTxt(tempSql, LogType.Debug + "_PrintSql");
}
tempSql = null;
}
}
#endregion
#region
public bool EndTransaction()
{
IsOpenTrans = false;
if (_tran != null)
{
try
{
if (_tran.Connection == null)
{
return false;//上一个执行语句发生了异常特殊情况在ExeReader guid='xxx' 但不抛异常)
}
_tran.Commit();
return true;
}
catch (Exception err)
{
RollBack();
WriteError("EndTransaction():" + err.Message);
}
finally
{
_tran = null;
CloseCon();
}
}
return false;
}
/// <summary>
/// 事务(有则)回滚
/// </summary>
/// <returns></returns>
public bool RollBack()
{
if (_tran != null)
{
try
{
if (_tran.Connection != null)
{
_tran.Rollback();
return true;
}
}
catch (Exception err)
{
WriteError("RollBack():" + err.Message);
}
finally
{
_tran = null;//以便重启事务,避免无法二次回滚。
}
}
return false;
}
#endregion
#region
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 = DataBaseType + " Call Function::" + err;
if (_watch != null && _watch.IsRunning)
{
_watch.Stop();
_watch.Reset();
}
RollBack();
if (IsWriteLogOnError)
{
Log.Write(err + AppConst.BR + DebugInfo, LogType.DataBase);
}
if (OnExceptionEvent != null)
{
try
{
OnExceptionEvent(err);
}
catch
{
}
}
if (IsOpenTrans)
{
Dispose();//事务中发生语句语法错误,直接关掉资源,避免因后续代码继续执行。
}
}
#endregion
public void Dispose()
{
string key = StaticTool.GetTransationKey(UsingConnBean.ConnName);
if (DBFast.HasTransation(key))
{
return;//全局事务由全局控制全局事务会在移除key后重新调用
}
if (_con != null)
{
CloseCon();
_con = null;
}
if (_com != null)
{
_com.Dispose();
_com = null;
}
if (_watch != null)
{
_watch = null;
}
}
}
/// <summary>
/// 执行管理
/// </summary>
internal abstract partial class DalBase
{
private DbDataReader ExeDataReaderSQL(string cmdText, bool isProc)
{
RecordsAffected = -2;
DbDataReader sdr = null;
ConnBean coSlave = null;
if (!IsOpenTrans)// && _IsAllowRecordSql
{
coSlave = ConnObj.GetSlave();
}
else if (UsingConnBean.IsSlave)// && 事务操作时,如果在从库,切回主库
{
ResetConn(ConnObj.Master);
}
if (OpenCon(coSlave, AllowConnLevel.MaterBackupSlave))
{
try
{
CommandBehavior cb = CommandBehavior.CloseConnection;
if (_IsRecordDebugInfo)//外部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 || UsingConnBean.IsSlave)// && 事务操作时,如果在从库,切回主库
{
ResetConn(ConnObj.Master);
}
if (OpenCon())//这里也会切库了同时设置了10秒切到主库。
{
try
{
if (UsingConnBean.ConnString != ConnObj.Master.ConnString)
{
// 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 && DataBaseType == DataBaseType.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 result = ExeNonQuerySQL(cmdText, isProc);
WriteTime();
return result;
}
private object ExeScalarSQL(string cmdText, bool isProc)
{
RecordsAffected = -2;
object returnValue = null;
ConnBean coSlave = null;
//mssql 有 insert into ...select 操作。
bool isSelectSql = !IsOpenTrans && !cmdText.ToLower().TrimStart().StartsWith("insert ");//&& _IsAllowRecordSql
bool isOpenOK;
if (isSelectSql)
{
coSlave = ConnObj.GetSlave();
isOpenOK = OpenCon(coSlave, AllowConnLevel.MaterBackupSlave);
}
else
{
if (UsingConnBean.IsSlave) // 如果是在从库,切回主库。(insert ...select 操作)
{
ResetConn(ConnObj.Master);
}
isOpenOK = OpenCon();
}
if (isOpenOK)
{
try
{
if (!isSelectSql && UsingConnBean.ConnString != ConnObj.Master.ConnString)
{
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)
{
RecordsAffected = -2;
string msg = "ExeScalar():" + err.Message;
DebugInfo.Append(msg + AppConst.BR);
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;
}
*/
}
/// <summary>
/// 链接管理
/// </summary>
internal abstract partial class DalBase
{
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 = ConnObj;
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);
}
if (openOKFlag == -1 && DebugInfo.Length == 0)
{
if (obj.Master != null && !string.IsNullOrEmpty(obj.Master.ErrorMsg))
{
DebugInfo.Append(obj.Master.ErrorMsg);
}
}
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)
{
if (connBean.TryTestConn() && openOKFlag != 1)
{
openOKFlag = 1;
_Version = connBean.Version;//设置版本号。
ResetConn(connBean);//切到正常的去。
}
else
{
errorCount++;
DebugInfo.Append(connBean.ErrorMsg);
}
}
}
/// <summary>
/// 切换链接
/// </summary>
private bool ResetConn(ConnBean cb)//, bool isAllowReset
{
if (cb != null && cb.IsOK && _con != null && _con.State != ConnectionState.Open && UsingConnBean.ConnString != cb.ConnString)
{
UsingConnBean = cb;
_con.ConnectionString = cb.ConnString;
return true;
}
return false;
}
/// <summary>
/// 打开链接,只切主备(同时有N秒的主库定位)
/// </summary>
/// <returns></returns>
internal bool OpenCon()
{
ConnBean master = ConnObj.Master;
if (!master.IsOK && ConnObj.BackUp != null && ConnObj.BackUp.IsOK)
{
master = ConnObj.BackUp;
ConnObj.InterChange();//主从换位置
}
if (master.IsOK || (ConnObj.BackUp != null && ConnObj.BackUp.IsOK))
{
bool result = OpenCon(master, AllowConnLevel.MasterBackup);
if (result && _IsRecordDebugInfo)
{
ConnObj.SetFocusOnMaster();
//isAllowResetConn = false;
}
return result;
}
if (!DebugInfo.ToString().EndsWith(master.ErrorMsg))
{
DebugInfo.Append(master.ErrorMsg);
}
return false;
}
/// <summary>
/// 打开链接,允许切从。
/// </summary>
internal bool OpenCon(ConnBean cb, AllowConnLevel leve)
{
try
{
if (cb == null)
{
cb = UsingConnBean;
if (IsOpenTrans && cb.IsSlave)
{
ResetConn(ConnObj.Master);
}
}
if (!cb.IsOK)
{
if ((int)leve > 1 && ConnObj.BackUp != null && ConnObj.BackUp.IsOK)
{
ResetConn(ConnObj.BackUp);//重置链接。
ConnObj.InterChange();//主从换位置
return OpenCon(ConnObj.Master, leve);
}
else if ((int)leve > 2)
{
//主挂了,备也挂了(因为备会替主)
ConnBean nextSlaveBean = ConnObj.GetSlave();
if (nextSlaveBean != null)
{
ResetConn(nextSlaveBean);//重置链接。
return OpenCon(nextSlaveBean, leve);
}
}
}
else if (!IsOpenTrans && cb != UsingConnBean && ConnObj.IsAllowSlave())//&& isAllowResetConn
{
ResetConn(cb);//,_IsAllowRecordSql只有读数据错误才切表结构错误不切
}
if (UsingConnBean.IsOK)
{
Open();//异常抛
}
else
{
WriteError(UsingConnBean.ConnDataBaseType + ".OpenCon():" + UsingConnBean.ErrorMsg);
}
if (IsRecordDebugInfo && _watch != null)
{
_watch.Start();
}
return UsingConnBean.IsOK;
}
catch (DbException err)
{
UsingConnBean.IsOK = false;
UsingConnBean.ErrorMsg = err.Message;
return OpenCon(null, leve);
}
}
protected virtual void AfterOpen() { }
private void Open()
{
if (_con.State == ConnectionState.Closed)
{
if (DataBaseType == DataBaseType.Sybase)
{
_com.Connection = _con;//重新赋值Sybase每次Close后命令的Con都丢失
}
_con.Open();
AfterOpen();
//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);
}
}
}
}