lith 4 жил өмнө
parent
commit
86dab07bc6

+ 1 - 16
Library/Vit.Db.DbMng/BaseDbMng.cs

@@ -324,22 +324,7 @@ namespace Vit.Db.DbMng
 
 
                 //确保conn打开
-                if (conn.State == ConnectionState.Open)
-                {
-                    runSql();
-                }
-                else
-                {
-                    try
-                    {
-                        conn.Open();
-                        runSql();
-                    }
-                    finally
-                    {
-                        conn.Close();
-                    }
-                }
+                conn.MakeSureOpen(runSql);
 
                 Log("     成功");
                 span = (DateTime.Now - lastTime);

+ 93 - 25
Library/Vit.Db.DbMng/Extendsions/IDbConnection_MsSqlExtensions.cs

@@ -5,6 +5,8 @@ using System.Data.SqlClient;
 using Vit.Extensions;
 using Vit.Core.Module.Log;
 using Vit.Orm.Dapper;
+using SqlConnection = System.Data.SqlClient.SqlConnection;
+using System.IO;
 
 namespace Vit.Db.DbMng.Extendsions
 {
@@ -37,24 +39,88 @@ if Exists(select top 1 * from sysObjects where Id=OBJECT_ID(N'sqler_temp_filebuf
              
              */
 
-        #region MsSql_ReadFileFromDisk    
+        #region MsSql_ReadFileFromDisk   
+
         /// <summary>
-        /// 从磁盘读取文件内容
+        /// 读取SqlServer所在服务器中的文件内容,存储到本地。
+        /// 若服务器中不存在指定的文件则抛异常。
+        /// (文件内容直接存储到文件,可读取超大文件)
+        /// </summary>
+        /// <param name="conn"></param>
+        /// <param name="serverFilePath"></param>
+        /// <param name="localFilePath"></param>
+        /// <returns>读取的文件大小。单位:byte</returns>
+        public static int ReadFileFromDisk(this SqlConnection conn, string serverFilePath, string localFilePath)
+        {
+            // Sql DataReader中读取大字段到文件的方法
+            // https://www.cnblogs.com/sundongxiang/archive/2009/09/14/1566443.html
+
+            // select BulkColumn  from OPENROWSET(BULK N'T:\机电合并.zip', SINGLE_BLOB) as content;      
+
+            return conn.MsSql_RunUseMaster((c) =>
+             {
+                 return c.MakeSureOpen((_) =>
+                 {
+                     var sql = " select BulkColumn  from OPENROWSET(BULK N'" + serverFilePath + "', SINGLE_BLOB) as content";
+
+                     int readedCount = 0;
+                     using (var cmd = new SqlCommand())
+                     {
+                         cmd.Connection = conn;
+                         cmd.CommandText = sql;
+
+                         if (DapperConfig.CommandTimeout.HasValue)
+                             cmd.CommandTimeout = DapperConfig.CommandTimeout.Value;
+
+                         using (var dr = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
+                         {
+                             if (dr.Read())
+                             {
+                                 Directory.CreateDirectory(Path.GetDirectoryName(localFilePath));
+
+                                 using (var output = new FileStream(localFilePath, FileMode.Create))
+                                 {
+                                     int bufferSize = 100 * 1024;
+                                     byte[] buff = new byte[bufferSize];
+
+                                     while (true)
+                                     {
+                                         int buffCount = (int)dr.GetBytes(0, readedCount, buff, 0, bufferSize);
+
+                                         output.Write(buff, 0, buffCount);
+                                         readedCount += buffCount;
+
+                                         if (buffCount < bufferSize) break;
+                                     }
+                                 }
+                             }
+                         }
+                     }
+                     return readedCount;
+                 });
+             });
+        }
+
+
+        /// <summary>
+        /// 从磁盘读取文件内容(文件内容会先缓存到内存,若读取超大文件,请使用ReadFileFromDisk代替)
         /// </summary>
         /// <param name="conn"></param>
         /// <param name="filePath"></param>
-        /// <returns></returns>
+        /// <returns>读取的文件的内容</returns>
         public static byte[] MsSql_ReadFileFromDisk(this IDbConnection conn, string filePath)
         {
-            /*        select BulkColumn  from OPENROWSET(BULK N'T:\机电合并.zip', SINGLE_BLOB) as content;                 
-             */
+            // select BulkColumn  from OPENROWSET(BULK N'T:\机电合并.zip', SINGLE_BLOB) as content;                 
+
             return conn.MsSql_RunUseMaster((c) =>
             {
                 return conn.ExecuteScalar<byte[]>(
-                " select BulkColumn  from OPENROWSET(BULK N'"+ filePath + "', SINGLE_BLOB) as content"
-                ,commandTimeout: DapperConfig.CommandTimeout);
+                " select BulkColumn  from OPENROWSET(BULK N'" + filePath + "', SINGLE_BLOB) as content"
+                , commandTimeout: DapperConfig.CommandTimeout);
             });
         }
+        //*/
+
         #endregion
 
 
@@ -66,8 +132,8 @@ if Exists(select top 1 * from sysObjects where Id=OBJECT_ID(N'sqler_temp_filebuf
         /// <param name="filePath"></param>
         /// <returns></returns>
         public static void MsSql_DeleteFileFromDisk(this IDbConnection conn, string filePath)
-        {            
-            conn.MsSql_Cmdshell("del \""+ filePath + "\"");
+        {
+            conn.MsSql_Cmdshell("del \"" + filePath + "\"");
         }
         #endregion
 
@@ -80,29 +146,30 @@ if Exists(select top 1 * from sysObjects where Id=OBJECT_ID(N'sqler_temp_filebuf
         /// <param name="conn"></param>
         /// <param name="filePath"></param>
         /// <param name="fileContent"></param>
-        public static void MsSql_WriteFileToDisk(this IDbConnection conn, string filePath,byte[]fileContent)
+        public static void MsSql_WriteFileToDisk(this IDbConnection conn, string filePath, byte[] fileContent)
         {
             string fmtFilePath = filePath + ".sqler.temp.fmt";
 
-            conn.MsSql_Cmdshell(runCmd => {
+            conn.MsSql_Cmdshell(runCmd =>
+            {
 
                 #region (x.1)把文件内容写入到临时表
                 conn.Execute(@"
 if Exists(select top 1 * from sysObjects where Id=OBJECT_ID(N'sqler_temp_filebuffer') and xtype='U')
 	drop table sqler_temp_filebuffer;
 select @fileContent as fileContent into sqler_temp_filebuffer;
-",new { fileContent }, commandTimeout: DapperConfig.CommandTimeout);
+", new { fileContent }, commandTimeout: DapperConfig.CommandTimeout);
                 #endregion
 
                 try
                 {
 
                     #region (x.2)写入二进制文件到磁盘
-                    var log1 = runCmd("bcp \"select null union all select '0' union all select '0' union all select null union all select 'n' union all select null \" queryout \""+ fmtFilePath + "\" /T /c");
-                    Logger.Info("[sqler]-MsSqlMng 写入文件到磁盘. 创建fmt文件,outlog: " + log1.Serialize());
+                    var log1 = runCmd("bcp \"select null union all select '0' union all select '0' union all select null union all select 'n' union all select null \" queryout \"" + fmtFilePath + "\" /T /c");
+                    Logger.Info("[sqler]-MsDbMng 写入文件到磁盘. 创建fmt文件,outlog: " + log1.Serialize());
 
                     var log2 = runCmd("BCP \"SELECT fileContent FROM sqler_temp_filebuffer\" queryout \"" + filePath + "\" -T -i \"" + fmtFilePath + "\"");
-                    Logger.Info("[sqler]-MsSqlMng 写入文件到磁盘.创建文件,outlog: " + log2.Serialize());
+                    Logger.Info("[sqler]-MsDbMng 写入文件到磁盘.创建文件,outlog: " + log2.Serialize());
 
                     #endregion
 
@@ -159,13 +226,14 @@ if Exists(select top 1 * from sysObjects where Id=OBJECT_ID(N'sqler_temp_filebuf
         public static DataTable MsSql_Cmdshell(this IDbConnection conn, string cmd)
         {
             DataTable dt = null;
-            conn.MsSql_Cmdshell( runCmd=>  dt = runCmd(cmd)   );
+            conn.MsSql_Cmdshell(runCmd => dt = runCmd(cmd));
             return dt;
         }
 
-        public static void MsSql_Cmdshell(this IDbConnection conn, Action<Func<string,DataTable>> handleToRun)
-        {            
-            conn.MsSql_RunUseMaster((c)=> {
+        public static void MsSql_Cmdshell(this IDbConnection conn, Action<Func<string, DataTable>> handleToRun)
+        {
+            conn.MsSql_RunUseMaster((c) =>
+            {
 
                 bool advancedOptionsIsOpened = false;
                 try
@@ -182,9 +250,9 @@ if Exists(select top 1 * from sysObjects where Id=OBJECT_ID(N'sqler_temp_filebuf
                     cmdshellIsOpened = c.ExecuteDataTable("EXEC SP_CONFIGURE 'xp_cmdshell'").Rows[0]["config_value"]?.Convert<string>() != "0";
                 }
                 catch (Exception)
-                {                     
+                {
                 }
-               
+
 
                 try
                 {
@@ -206,8 +274,8 @@ RECONFIGURE;
                 }
                 finally
                 {
-                    if(!cmdshellIsOpened)
-                    c.Execute(@"
+                    if (!cmdshellIsOpened)
+                        c.Execute(@"
 --关闭执行CMD命令
 EXEC SP_CONFIGURE 'xp_cmdshell', 0;
 RECONFIGURE;
@@ -221,9 +289,9 @@ RECONFIGURE;
 ", commandTimeout: Orm.Dapper.DapperConfig.CommandTimeout);
 
                 }
-              
+
             });
-            
+
         }
         #endregion
 

+ 74 - 73
Library/Vit.Db.DbMng/MsSql/MsSqlDbMng.cs

@@ -517,6 +517,27 @@ deallocate   cDblogin
 
 
 
+        #region BackupToLocalBak
+
+        /// <summary>
+        /// 备份数据库
+        /// </summary>
+        /// <param name="bakFilePath">备份的文件路径,若不指定则自动构建。demo:@"F:\\website\appdata\dbname_2020-02-02_121212.bak"</param>
+        /// <returns>备份的文件路径</returns>
+        public string BackupToLocalBak(string bakFilePath = null)
+        {
+            if (string.IsNullOrEmpty(bakFilePath)) bakFilePath = BackupFile_GetPathByName(GenerateBackupFileName(dbName));
+
+            return Exec((conn) =>
+            {
+                conn.Execute("backup database @database to disk = @filePath ", new { database = this.dbName, filePath = bakFilePath }, commandTimeout: Orm.Dapper.DapperConfig.CommandTimeout);
+                return bakFilePath;
+            });
+        }
+
+        #endregion
+
+
 
         #region BackupToBak 远程备份数据库
         /// <summary>
@@ -547,11 +568,14 @@ deallocate   cDblogin
             BackupToLocalBak(remote_bakFilePath);
             #endregion
 
-            #region (x.3)从远程数据库服务器 获取备份文件二进制内容,并删除临时备份文件
-            byte[] fileContent;
+            #region (x.3)从远程数据库服务器 获取备份文件二进制内容,存储备份文件到本地,并删除临时备份文件
+
+            if (string.IsNullOrEmpty(bakFilePath)) 
+                bakFilePath = BackupFile_GetPathByName(GenerateBackupFileName(dbName));
+
             try
             {
-                fileContent = conn.MsSql_ReadFileFromDisk(remote_bakFilePath);
+                conn.ReadFileFromDisk(remote_bakFilePath, bakFilePath);
             }
             finally
             {
@@ -560,14 +584,7 @@ deallocate   cDblogin
             }
             #endregion
 
-
-            #region (x.4)存储备份文件到本地
-            if (string.IsNullOrEmpty(bakFilePath)) bakFilePath = BackupFile_GetPathByName(GenerateBackupFileName(dbName));
-
-            Directory.CreateDirectory(Path.GetDirectoryName(bakFilePath));
-            File.WriteAllBytes(bakFilePath, fileContent);
-            return bakFilePath;
-            #endregion
+            return bakFilePath;            
         }
         #endregion
 
@@ -592,27 +609,6 @@ deallocate   cDblogin
         #endregion
 
 
-        #region BackupToLocalBak ByFilePath
-
-        /// <summary>
-        /// 备份数据库
-        /// </summary>
-        /// <param name="bakFilePath">备份的文件路径,若不指定则自动构建。demo:@"F:\\website\appdata\dbname_2020-02-02_121212.bak"</param>
-        /// <returns>备份的文件路径</returns>
-        public string BackupToLocalBak(string bakFilePath = null)
-        {
-            if (string.IsNullOrEmpty(bakFilePath)) bakFilePath = BackupFile_GetPathByName(GenerateBackupFileName(dbName));
-
-            return Exec((conn) =>
-            {
-                conn.Execute("backup database @database to disk = @filePath ", new { database = this.dbName, filePath = bakFilePath }, commandTimeout: Orm.Dapper.DapperConfig.CommandTimeout);
-                return bakFilePath;
-            });
-        }
-
-        #endregion
-
-
         #region GenerateBackupFileName
         static string GenerateBackupFileName(string dbName, string fileExtension = ".bak")
         {
@@ -623,47 +619,6 @@ deallocate   cDblogin
 
 
 
-        #region RestoreBak 通过bak远程还原
-        /// <summary>
-        /// 远程还原数据库   
-        /// </summary>
-        /// <param name="bakFilePath">数据库备份文件的路径</param>
-        /// <returns>备份文件的路径</returns>
-        public string RestoreBak(string bakFilePath)
-        {
-            //(x.1)若数据库不存在,则创建数据库
-            CreateDataBase();
-
-            #region (x.2)拼接在mdf同文件夹下的备份文件的路径
-            var remote_mdfDirectory = Path.GetDirectoryName(GetMdfPath());
-            var remote_bakFilePath = Path.Combine(remote_mdfDirectory, "sqler_temp_" + dbName + ".bak");
-            #endregion
-
-
-            #region (x.3)把本地备份文件写入到远程
-            conn.MsSql_WriteFileToDisk(remote_bakFilePath,File.ReadAllBytes(bakFilePath));            
-            #endregion
-
-            #region (x.4)还原远程数据库            
-            try
-            {
-                RestoreLocalBak(remote_bakFilePath);
-            }
-            finally
-            {
-                //远程删除文件
-                conn.MsSql_DeleteFileFromDisk(remote_bakFilePath);
-            }
-            #endregion
-
-
-            return bakFilePath;
-
-        }
-        #endregion
-
-        
-
 
         #region RestoreLocalBak
         /// <summary>
@@ -675,6 +630,7 @@ deallocate   cDblogin
         {
             //若数据库不存在,则创建数据库
             CreateDataBase();
+
             return Exec((conn) =>
             {
 
@@ -741,6 +697,51 @@ RESTORE DATABASE [Lit_Base1] FROM  DISK =@BakPath  WITH  FILE = 1,  RECOVERY ,
 
 
 
+        #region RestoreBak 通过bak远程还原
+        /// <summary>
+        /// 远程还原数据库   
+        /// </summary>
+        /// <param name="bakFilePath">数据库备份文件的路径</param>
+        /// <returns>备份文件的路径</returns>
+        public string RestoreBak(string bakFilePath)
+        {
+            //(x.1)若数据库不存在,则创建数据库
+            CreateDataBase();
+
+            #region (x.2)拼接在mdf同文件夹下的备份文件的路径
+            var remote_mdfDirectory = Path.GetDirectoryName(GetMdfPath());
+            var remote_bakFilePath = Path.Combine(remote_mdfDirectory, "sqler_temp_" + dbName + ".bak");
+            #endregion
+
+
+            #region (x.3)把本地备份文件写入到远程
+            conn.MsSql_WriteFileToDisk(remote_bakFilePath,File.ReadAllBytes(bakFilePath));            
+            #endregion
+
+            #region (x.4)还原远程数据库            
+            try
+            {
+                RestoreLocalBak(remote_bakFilePath);
+            }
+            finally
+            {
+                //远程删除文件
+                conn.MsSql_DeleteFileFromDisk(remote_bakFilePath);
+            }
+            #endregion
+
+
+            return bakFilePath;
+
+        }
+        #endregion
+
+        
+
+
+
+
+
 
 
         #region Restore

+ 2 - 4
Sqler/Module/Sqler/Controllers/SqlRun/SqlRunController.cs

@@ -41,10 +41,8 @@ namespace App.Module.Sqler.Controllers.SqlRun
 
         static void ExecSql( Action<EMsgType, String> sendMsg,string sqlCode)
         {
-
-            using (var conn = ConnectionFactory.GetConnection(SqlerHelp.sqlerConfig.GetByPath<Vit.Orm.Dapper.ConnectionInfo>("SqlRun.Config")))
-            {
-                conn.Open();
+            using (var conn = ConnectionFactory.GetOpenConnection(SqlerHelp.sqlerConfig.GetByPath<Vit.Orm.Dapper.ConnectionInfo>("SqlRun.Config")))
+            {               
                 using (var tran = conn.BeginTransaction())
                 {
                     try

+ 1 - 1
Sqler/Module/Sqler/Logical/SqlVersion/SqlVersionHelp.cs

@@ -34,7 +34,7 @@ namespace App.Module.Sqler.Logical.SqlVersion
                 () =>
                 {
                     var conn = ConnectionCreator();
-                    conn.Open();
+                    conn?.Open();
                     return conn;
                 };
             }