DbHelper.cs 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882
  1. using Oracle.ManagedDataAccess.Client;
  2. using SevenZip;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Data;
  6. using System.Data.Common;
  7. using System.Diagnostics;
  8. using System.IO;
  9. using System.Linq;
  10. using System.Text;
  11. using System.Threading.Tasks;
  12. using System.Xml.Linq;
  13. namespace Oracle11
  14. {
  15. /// <summary>
  16. /// 数据库备份还原类(不支持并行调用)
  17. /// </summary>
  18. public static class DbHelper
  19. {
  20. #region 备份及还原
  21. /// <summary>
  22. /// 全量备份(返回一个7z压缩文件)
  23. /// </summary>
  24. /// <param name="oracleAddr">oracle地址(127.0.0.1:1521)</param>
  25. /// <param name="user">用户名(不区分大小写)</param>
  26. /// <param name="pwd">密码</param>
  27. /// <param name="serviceName">服务名称(orcl)</param>
  28. /// <param name="tables">要备份的表名(默认备份所有表)</param>
  29. public static string BackupDb(string dbAddr, string user, string pwd, string serviceName = "orcl", List<string> tables = null)
  30. {
  31. Directory.CreateDirectory("Backup");
  32. user = user.ToUpper();
  33. string connString = $"Data Source={dbAddr}/{serviceName}; User Id={user}; Password={pwd};";
  34. if (tables == null || tables.Count == 0)
  35. tables = GetAllTable(dbAddr, user, pwd, serviceName);
  36. DirectoryInfo dir = new DirectoryInfo("Backup");
  37. var delFiles = dir.GetFiles();
  38. foreach (var item in delFiles)
  39. {
  40. if (!item.Name.ToUpper().EndsWith(".SQL") && !item.Name.ToUpper().EndsWith(".DAT") && !item.Name.ToUpper().EndsWith(".TXT"))
  41. continue;
  42. item.Delete();
  43. }
  44. List<string> sqls = new List<string>();
  45. foreach (var item in tables)
  46. {
  47. var sql = $"select dbms_metadata.get_ddl('TABLE','{item}') createTableSql from dual";
  48. var createTableSql = OracleHelper.ExecuteScalar(connString, sql).ToString();
  49. createTableSql = createTableSql.Replace("\"", "").Replace($"{user}.", "").Trim().Trim("\n".ToCharArray());
  50. sqls.Add($"-- ----------------------------\r\n-- 创建表{item}\r\n-- ----------------------------\r\n{createTableSql}");
  51. }
  52. File.WriteAllText("Backup\\tables.sql", $"{string.Join("\r\n/\r\n", sqls)}");
  53. sqls.Clear();
  54. var seqs = GetAllSequenceSql(dbAddr, user, pwd, serviceName);
  55. foreach (var item in seqs)
  56. {
  57. var sql = item.Value.Replace("\"", "").Replace($"{user}.", "").Trim().Trim("\n".ToCharArray());
  58. sqls.Add($"-- ----------------------------\r\n-- 创建序列{item.Key}\r\n-- ----------------------------\r\n{sql}");
  59. }
  60. File.WriteAllText("Backup\\sequences.sql", $"{string.Join("\r\n/\r\n", sqls)}");
  61. sqls.Clear();
  62. var triggers = GetAllTriggerSql(dbAddr, user, pwd, serviceName);
  63. foreach (var item in triggers)
  64. {
  65. var sql = item.Value.Replace("\"", "").Replace($"{user}.", "")
  66. .Replace($"ALTER TRIGGER {item.Key} ENABLE", "").Trim().Trim("\n".ToCharArray());
  67. sqls.Add($"-- ----------------------------\r\n-- 创建触发器{item.Key}\r\n-- ----------------------------\r\n{sql}");
  68. }
  69. File.WriteAllText("Backup\\triggers.sql", $"{string.Join("\r\n/\r\n", sqls)}");
  70. sqls.Clear();
  71. var indexs = GetAllIndexSql(dbAddr, user, pwd, serviceName);
  72. foreach (var item in indexs)
  73. {
  74. var sql = item.Value.Replace("\"", "").Replace($"{user}.", "").Trim().Trim("\n".ToCharArray());
  75. sqls.Add($"-- ----------------------------\r\n-- 创建索引{item.Key}\r\n-- ----------------------------\r\n{sql}");
  76. }
  77. File.WriteAllText("Backup\\indexes.sql", $"{string.Join("\r\n/\r\n", sqls)}");
  78. sqls.Clear();
  79. foreach (var item in tables)
  80. {
  81. var pkColumn = GetPkColumn(item, dbAddr, user, pwd, serviceName);
  82. if (!string.IsNullOrWhiteSpace(pkColumn))
  83. {
  84. var pkMax = GetMaxPk(item, pkColumn, dbAddr, user, pwd, serviceName);
  85. if (string.IsNullOrWhiteSpace(pkMax))
  86. pkMax = "0";
  87. File.AppendAllText("Backup\\MaxInfo.txt", $"{item} {pkColumn} {pkMax}\r\n");
  88. }
  89. var sql = $"select * from {item}";
  90. var dt = OracleHelper.ExecuteDataTable(connString, sql);
  91. if (dt.Rows.Count > 0)
  92. {
  93. string file = $"Backup\\{item}.dat";
  94. using (BinaryWriter br = new BinaryWriter(new FileStream(file, FileMode.Create), Encoding.UTF8))
  95. {
  96. Dictionary<int, Type> dic = new Dictionary<int, Type>();
  97. for (int i = 0; i < dt.Columns.Count; i++)
  98. {
  99. dic.Add(i, dt.Columns[i].DataType);
  100. }
  101. br.Write(dt.Columns.Count);
  102. foreach (DataRow dr in dt.Rows)
  103. {
  104. for (int i = 0; i < dt.Columns.Count; i++)
  105. {
  106. if (dr[i] == DBNull.Value)
  107. {
  108. br.Write((byte)100);
  109. }
  110. else if (dic[i] == typeof(string))
  111. {
  112. br.Write((byte)0);
  113. br.Write(dr[i].ToString());
  114. }
  115. else if (dic[i] == typeof(DateTime))
  116. {
  117. br.Write((byte)1);
  118. br.Write(((DateTime)dr[i]).ToBinary());
  119. }
  120. else if (dic[i] == typeof(long))
  121. {
  122. br.Write((byte)2);
  123. br.Write((long)dr[i]);
  124. }
  125. else if (dic[i] == typeof(int))
  126. {
  127. br.Write((byte)3);
  128. br.Write((int)dr[i]);
  129. }
  130. else if (dic[i] == typeof(short))
  131. {
  132. br.Write((byte)4);
  133. br.Write((short)dr[i]);
  134. }
  135. else if (dic[i] == typeof(byte))
  136. {
  137. br.Write((byte)5);
  138. br.Write((byte)dr[i]);
  139. }
  140. else if (dic[i] == typeof(decimal))
  141. {
  142. br.Write((byte)6);
  143. br.Write(Convert.ToDecimal(dr[i]));
  144. }
  145. else if (dic[i] == typeof(float))
  146. {
  147. br.Write((byte)7);
  148. br.Write((float)dr[i]);
  149. }
  150. else if (dic[i] == typeof(double))
  151. {
  152. br.Write((byte)8);
  153. br.Write((double)dr[i]);
  154. }
  155. else if (dic[i] == typeof(byte[]))
  156. {
  157. br.Write((byte)9);
  158. var data = (byte[])dr[i];
  159. br.Write(data.Length);
  160. br.Write(data);
  161. }
  162. else
  163. {
  164. throw new Exception($"不支持类型{dic[i]}的转换");
  165. }
  166. }
  167. }
  168. }
  169. }
  170. }
  171. string zipDir = dir.FullName;
  172. string zipFile = Path.Combine(zipDir, $"all-{DateTime.Now:yyyyMMddHHmmss}.7z");
  173. SevenZipUtil.ZipLargeFiles(zipDir, zipFile, new string[] { "*.sql", "*.dat", "*.txt" }, true);
  174. return zipFile;
  175. }
  176. /// <summary>
  177. /// 增量备份(返回一个7z压缩文件)
  178. /// </summary>
  179. /// <param name="backup7zFile">全量备份的文件</param>
  180. /// <param name="dbAddr">oracle地址(127.0.0.1:1521</param>
  181. /// <param name="user">用户名(不区分大小写)</param>
  182. /// <param name="pwd">密码</param>
  183. /// <param name="serviceName">服务名称(orcl)</param>
  184. /// <param name="tables">>要备份的表名(默认备份所有表)</param>
  185. public static string BackupIncrementDb(string backup7zFile, string dbAddr, string user, string pwd, string serviceName = "orcl", List<string> tables = null)
  186. {
  187. string prefix = Path.GetFileNameWithoutExtension(backup7zFile);
  188. FileInfo f = new FileInfo(backup7zFile);
  189. string dirString = f.DirectoryName;
  190. user = user.ToUpper();
  191. string connString = $"Data Source={dbAddr}/{serviceName}; User Id={user}; Password={pwd};";
  192. if (tables == null || tables.Count == 0)
  193. tables = GetAllTable(dbAddr, user, pwd, serviceName);
  194. DirectoryInfo dir = new DirectoryInfo(dirString);
  195. var delFiles = dir.GetFiles();
  196. foreach (var item in delFiles)
  197. {
  198. if (!item.Name.ToUpper().EndsWith(".SQL") && !item.Name.ToUpper().EndsWith(".DAT") && !item.Name.ToUpper().EndsWith(".TXT"))
  199. continue;
  200. item.Delete();
  201. }
  202. //获取全量备份的文件和其相关的增量备份文件 fileName like [all-20240926104545] or [all-20240926104545-Increment-20240926150000]
  203. var fileNames = Directory.GetFiles(dirString, "*.7z").Where(p => Path.GetFileNameWithoutExtension(p).StartsWith(prefix)).Select(p => Path.GetFileNameWithoutExtension(p));
  204. //获取最后一个备份的文件
  205. var maxFileName = fileNames.OrderByDescending(p =>
  206. {
  207. var idx = p.LastIndexOf("-");
  208. var time = DateTime.ParseExact(p.Substring(idx + 1, 14), "yyyyMMddHHmmss", null);
  209. return time;
  210. }).FirstOrDefault();
  211. var maxFile = Path.Combine(dirString, maxFileName + ".7z");
  212. SevenZipUtil.UnZipFile(maxFile, "*.txt");
  213. string maxInfoFile = Path.Combine(dirString, maxFileName.Contains("Increment") ? "MaxInfo-Increment.txt" : "MaxInfo.txt");
  214. bool hasNew = false;
  215. if (File.Exists(maxInfoFile))
  216. {
  217. var lines = File.ReadAllLines(maxInfoFile);
  218. File.WriteAllText(maxInfoFile, "");
  219. foreach (var item in lines)
  220. {
  221. var arr = item.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
  222. var tbName = arr[0];
  223. var colName = arr[1];
  224. var maxPk = arr[2];
  225. string sql = $"select * from {tbName} where {colName}>{maxPk}";
  226. var dt = OracleHelper.ExecuteDataTable(connString, sql);
  227. if (dt.Rows.Count > 0)
  228. {
  229. hasNew = true;
  230. sql = $"select max({colName}) from {tbName}";
  231. var maxPkNew = OracleHelper.ExecuteScalar(connString, sql).ToString();
  232. File.AppendAllText(Path.Combine(dirString, "MaxInfo-Increment.txt"), $"{tbName} {colName} {maxPkNew}\r\n");
  233. string file = Path.Combine(dirString, $"{tbName}-Increment.dat");
  234. using (BinaryWriter br = new BinaryWriter(new FileStream(file, FileMode.Create), Encoding.UTF8))
  235. {
  236. Dictionary<int, Type> dic = new Dictionary<int, Type>();
  237. for (int i = 0; i < dt.Columns.Count; i++)
  238. {
  239. dic.Add(i, dt.Columns[i].DataType);
  240. }
  241. br.Write(dt.Columns.Count);
  242. foreach (DataRow dr in dt.Rows)
  243. {
  244. for (int i = 0; i < dt.Columns.Count; i++)
  245. {
  246. if (dr[i] == DBNull.Value)
  247. {
  248. br.Write((byte)100);
  249. }
  250. else if (dic[i] == typeof(string))
  251. {
  252. br.Write((byte)0);
  253. br.Write(dr[i].ToString());
  254. }
  255. else if (dic[i] == typeof(DateTime))
  256. {
  257. br.Write((byte)1);
  258. br.Write(((DateTime)dr[i]).ToBinary());
  259. }
  260. else if (dic[i] == typeof(long))
  261. {
  262. br.Write((byte)2);
  263. br.Write((long)dr[i]);
  264. }
  265. else if (dic[i] == typeof(int))
  266. {
  267. br.Write((byte)3);
  268. br.Write((int)dr[i]);
  269. }
  270. else if (dic[i] == typeof(short))
  271. {
  272. br.Write((byte)4);
  273. br.Write((short)dr[i]);
  274. }
  275. else if (dic[i] == typeof(byte))
  276. {
  277. br.Write((byte)5);
  278. br.Write((byte)dr[i]);
  279. }
  280. else if (dic[i] == typeof(decimal))
  281. {
  282. br.Write((byte)6);
  283. br.Write(Convert.ToDecimal(dr[i]));
  284. }
  285. else if (dic[i] == typeof(float))
  286. {
  287. br.Write((byte)7);
  288. br.Write((float)dr[i]);
  289. }
  290. else if (dic[i] == typeof(double))
  291. {
  292. br.Write((byte)8);
  293. br.Write((double)dr[i]);
  294. }
  295. else if (dic[i] == typeof(byte[]))
  296. {
  297. br.Write((byte)9);
  298. var data = (byte[])dr[i];
  299. br.Write(data.Length);
  300. br.Write(data);
  301. }
  302. else
  303. {
  304. throw new Exception($"不支持类型{dic[i]}的转换");
  305. }
  306. }
  307. }
  308. }
  309. }
  310. else
  311. {
  312. File.AppendAllText(Path.Combine(dirString, "MaxInfo-Increment.txt"), $"{tbName} {colName} {maxPk}\r\n");
  313. }
  314. }
  315. }
  316. string zipFile = null;
  317. if (hasNew)
  318. {
  319. zipFile = Path.Combine(dirString, $"{prefix}-Increment-{DateTime.Now:yyyyMMddHHmmss}.7z");
  320. SevenZipUtil.ZipLargeFiles(dirString, zipFile, new string[] { "*Increment.dat", "*Increment.txt" }, true);
  321. }
  322. dir = new DirectoryInfo(dirString);
  323. delFiles = dir.GetFiles();
  324. foreach (var item in delFiles)
  325. {
  326. if (!item.Name.ToUpper().EndsWith(".SQL") && !item.Name.ToUpper().EndsWith(".DAT") && !item.Name.ToUpper().EndsWith(".TXT"))
  327. continue;
  328. item.Delete();
  329. }
  330. return zipFile;
  331. }
  332. /// <summary>
  333. /// 获取用户下所有表
  334. /// </summary>
  335. /// <param name="dbAddr">数据库地址(127.0.0.1:1521)</param>
  336. /// <param name="user">用户名(不区分大小写)</param>
  337. /// <param name="pwd">密码</param>
  338. /// <param name="serviceName">服务名称(orcl)</param>
  339. /// <returns></returns>
  340. public static List<string> GetAllTable(string dbAddr, string user, string pwd, string serviceName = "orcl")
  341. {
  342. user = user.ToUpper();
  343. string connString = $"Data Source={dbAddr}/{serviceName}; User Id={user}; Password={pwd};";
  344. var table = OracleHelper.ExecuteDataTable(connString, $"select table_name from all_tables where owner = '{user}'");
  345. var list = table.TableToListBcl<string>();
  346. return list;
  347. }
  348. /// <summary>
  349. /// 从全量备份压缩文件中还原数据库
  350. /// </summary>
  351. /// <param name="dbZipFile"></param>
  352. /// <param name="dbAddr"></param>
  353. /// <param name="user"></param>
  354. /// <param name="pwd"></param>
  355. /// <param name="sysPwd"></param>
  356. /// <param name="serviceName"></param>
  357. public static void RestoreDb(string dbZipFile, string dbAddr, string user, string pwd, string sysPwd, string serviceName = "orcl")
  358. {
  359. try
  360. {
  361. FileInfo f = new FileInfo(dbZipFile);
  362. dbZipFile = f.FullName;
  363. user = user.ToUpper();
  364. ClearUserObj(dbAddr, user, sysPwd, serviceName);
  365. CreateUserIfNotExit(dbAddr, user, pwd, sysPwd, serviceName);
  366. var dir = SevenZipUtil.UnZipFile(dbZipFile);
  367. string connString = $"Data Source={dbAddr}/{serviceName}; User Id={user}; Password={pwd};";
  368. var sequences = File.ReadAllText(Path.Combine(dir, "sequences.sql"));
  369. var triggers = File.ReadAllText(Path.Combine(dir, "triggers.sql"));
  370. var tables = File.ReadAllText(Path.Combine(dir, "tables.sql"));
  371. var indexes = File.ReadAllText(Path.Combine(dir, "indexes.sql"));
  372. var seqsDic = GetAllSequenceSql(dbAddr, user, pwd, serviceName);
  373. var tablesDic = GetAllTableSql(dbAddr, user, pwd, serviceName);
  374. var triggersDic = GetAllTriggerSql(dbAddr, user, pwd, serviceName);
  375. var indexesDic = GetAllIndexSql(dbAddr, user, pwd, serviceName);
  376. foreach (var item in sequences.Split("/".ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
  377. {
  378. string name = FindTextName(item, "-- 创建序列");
  379. if (seqsDic.ContainsKey(name)) continue;
  380. OracleHelper.ExecuteNonQuery(connString, item);
  381. }
  382. foreach (var item in tables.Split("/".ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
  383. {
  384. string name = FindTextName(item, "-- 创建表");
  385. if (tablesDic.ContainsKey(name)) continue;
  386. OracleHelper.ExecuteNonQuery(connString, item);
  387. }
  388. foreach (var item in triggers.Split("/".ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
  389. {
  390. string name = FindTextName(item, "-- 创建触发器");
  391. if (triggersDic.ContainsKey(name)) continue;
  392. OracleHelper.ExecuteNonQuery(connString, item);
  393. }
  394. foreach (var item in indexes.Split("/".ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
  395. {
  396. //唯一索引在创建表时会自动创建,这里只需要创建普通索引
  397. string name = FindTextName(item, "-- 创建索引");
  398. if (indexesDic.ContainsKey(name)) continue;
  399. OracleHelper.ExecuteNonQuery(connString, item);
  400. }
  401. DisableAllFk(dbAddr, user, pwd, serviceName);//导入数据前禁用所有外键约束
  402. DisableAllTrigger(dbAddr, user, pwd, serviceName);//导入数据前禁用所有触发器
  403. var datFiles = Directory.GetFiles(dir, "*.dat");
  404. foreach (var item in datFiles)
  405. {
  406. var con = new OracleConnection(connString);
  407. con.Open();
  408. var trans = con.BeginTransaction();
  409. try
  410. {
  411. string tableName = Path.GetFileNameWithoutExtension(item);
  412. using (BinaryReader br = new BinaryReader(new FileStream(item, FileMode.Open), Encoding.UTF8))
  413. {
  414. if (br.BaseStream.Position >= br.BaseStream.Length) continue;
  415. int columnCount = br.ReadInt32();
  416. while (br.BaseStream.Position < br.BaseStream.Length)
  417. {
  418. StringBuilder sb = new StringBuilder();
  419. sb.Append($"insert into {tableName} values(");
  420. OracleParameter[] parameters = new OracleParameter[columnCount];
  421. for (int i = 0; i < columnCount; i++)
  422. {
  423. parameters[i] = new OracleParameter();
  424. parameters[i].ParameterName = $"val{i}";
  425. if (i != 0)
  426. sb.Append(",");
  427. sb.Append($":val{i}");
  428. var colType = br.ReadByte();
  429. if (colType == 100)//DBNull.Value
  430. {
  431. parameters[i].Value = null;
  432. }
  433. if (colType == 0)//string
  434. {
  435. var val = br.ReadString();
  436. parameters[i].Value = val;
  437. }
  438. else if (colType == 1)//DateTime
  439. {
  440. var val = br.ReadInt64();
  441. var time = DateTime.FromBinary(val);
  442. parameters[i].Value = time;
  443. }
  444. else if (colType == 2)//long
  445. {
  446. var val = br.ReadInt64();
  447. parameters[i].Value = val;
  448. }
  449. else if (colType == 3)//int
  450. {
  451. var val = br.ReadInt32();
  452. parameters[i].Value = val;
  453. }
  454. else if (colType == 4)//short
  455. {
  456. var val = br.ReadInt16();
  457. parameters[i].Value = val;
  458. }
  459. else if (colType == 5)//byte
  460. {
  461. var val = br.ReadByte();
  462. parameters[i].Value = val;
  463. }
  464. else if (colType == 6)//decimal
  465. {
  466. var val = br.ReadDecimal();
  467. parameters[i].Value = val;
  468. }
  469. else if (colType == 7)//float
  470. {
  471. var val = br.ReadSingle();
  472. parameters[i].Value = val;
  473. }
  474. else if (colType == 8)//double
  475. {
  476. var val = br.ReadDouble();
  477. parameters[i].Value = val;
  478. }
  479. else if (colType == 9)//byte[]
  480. {
  481. var len = br.ReadInt32();
  482. var val = br.ReadBytes(len);
  483. parameters[i].Value = val;
  484. }
  485. }
  486. sb.Append(")");
  487. var insertSql = sb.ToString();
  488. OracleHelper.BatchInsert(con, trans, insertSql, parameters);
  489. //OracleHelper.ExecuteNonQuery(connString, insertSql, parameters);
  490. }
  491. }
  492. trans.Commit();
  493. con.Dispose();
  494. }
  495. catch (Exception ex)
  496. {
  497. trans.Rollback();
  498. throw;
  499. }
  500. }
  501. EnableAllFk(dbAddr, user, pwd, serviceName);//导入数据后启用所有外键约束
  502. EnableAllTrigger(dbAddr, user, pwd, serviceName);//导入数据后启用所有触发器
  503. var delFile = Directory.GetFiles(dir);
  504. foreach (var item in delFile)
  505. {
  506. if (item.ToUpper().EndsWith(".DAT") || item.ToUpper().EndsWith(".SQL") || item.ToUpper().EndsWith(".TXT"))
  507. {
  508. File.Delete(item);
  509. }
  510. }
  511. }
  512. finally
  513. {
  514. OracleConnection.ClearAllPools();
  515. }
  516. }
  517. /// <summary>
  518. /// 从增量备份压缩文件中恢复数据
  519. /// </summary>
  520. /// <param name="dbZipFile"></param>
  521. /// <param name="dbAddr"></param>
  522. /// <param name="user"></param>
  523. /// <param name="pwd"></param>
  524. /// <param name="sysPwd"></param>
  525. /// <param name="serviceName"></param>
  526. public static void RestoreIncrementDb(string dbZipFile, string dbAddr, string user, string pwd, string sysPwd, string serviceName = "orcl")
  527. {
  528. user = user.ToUpper();
  529. FileInfo file = new FileInfo(dbZipFile);
  530. dbZipFile = file.FullName;
  531. var dir = SevenZipUtil.UnZipFile(dbZipFile);
  532. string connString = $"Data Source={dbAddr}/{serviceName}; User Id={user}; Password={pwd};";
  533. DisableAllFk(dbAddr, user, pwd, serviceName);//导入数据前禁用所有外键约束
  534. DisableAllTrigger(dbAddr, user, pwd, serviceName);//导入数据前禁用所有触发器
  535. var datFiles = Directory.GetFiles(dir, "*.dat");
  536. var maxInfo = Path.Combine(dir, "MaxInfo-Increment.txt");
  537. var maxArr = File.ReadAllLines(maxInfo);
  538. List<(string, string, string)> list = new List<(string, string, string)>();
  539. foreach (var item in maxArr)
  540. {
  541. var arr = item.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
  542. var tbName = arr[0];
  543. var colName = arr[1];
  544. var maxPk = arr[2];
  545. list.Add((tbName, colName, maxPk));
  546. }
  547. foreach (var item in datFiles)
  548. {
  549. string tableName = Path.GetFileNameWithoutExtension(item).Replace("-Increment", "");
  550. var tupItem = list.First(p => p.Item1 == tableName);
  551. string maxSql = $"select max({tupItem.Item2}) from {tupItem.Item1}";
  552. var maxObj = OracleHelper.ExecuteScalar(connString, maxSql);
  553. if (maxObj != DBNull.Value && Convert.ToInt64(maxObj) >= Convert.ToInt64(tupItem.Item3))
  554. continue;//数据已存在,不要重复导入
  555. var con = new OracleConnection(connString);
  556. con.Open();
  557. var trans = con.BeginTransaction();
  558. try
  559. {
  560. using (BinaryReader br = new BinaryReader(new FileStream(item, FileMode.Open), Encoding.UTF8))
  561. {
  562. if (br.BaseStream.Position >= br.BaseStream.Length) continue;
  563. int columnCount = br.ReadInt32();
  564. while (br.BaseStream.Position < br.BaseStream.Length)
  565. {
  566. StringBuilder sb = new StringBuilder();
  567. sb.Append($"insert into {tableName} values(");
  568. OracleParameter[] parameters = new OracleParameter[columnCount];
  569. for (int i = 0; i < columnCount; i++)
  570. {
  571. parameters[i] = new OracleParameter();
  572. parameters[i].ParameterName = $"val{i}";
  573. if (i != 0)
  574. sb.Append(",");
  575. sb.Append($":val{i}");
  576. var colType = br.ReadByte();
  577. if (colType == 100)//DBNull.Value
  578. {
  579. parameters[i].Value = null;
  580. }
  581. if (colType == 0)//string
  582. {
  583. var val = br.ReadString();
  584. parameters[i].Value = val;
  585. }
  586. else if (colType == 1)//DateTime
  587. {
  588. var val = br.ReadInt64();
  589. var time = DateTime.FromBinary(val);
  590. parameters[i].Value = time;
  591. }
  592. else if (colType == 2)//long
  593. {
  594. var val = br.ReadInt64();
  595. parameters[i].Value = val;
  596. }
  597. else if (colType == 3)//int
  598. {
  599. var val = br.ReadInt32();
  600. parameters[i].Value = val;
  601. }
  602. else if (colType == 4)//short
  603. {
  604. var val = br.ReadInt16();
  605. parameters[i].Value = val;
  606. }
  607. else if (colType == 5)//byte
  608. {
  609. var val = br.ReadByte();
  610. parameters[i].Value = val;
  611. }
  612. else if (colType == 6)//decimal
  613. {
  614. var val = br.ReadDecimal();
  615. parameters[i].Value = val;
  616. }
  617. else if (colType == 7)//float
  618. {
  619. var val = br.ReadSingle();
  620. parameters[i].Value = val;
  621. }
  622. else if (colType == 8)//double
  623. {
  624. var val = br.ReadDouble();
  625. parameters[i].Value = val;
  626. }
  627. else if (colType == 9)//byte[]
  628. {
  629. var len = br.ReadInt32();
  630. var val = br.ReadBytes(len);
  631. parameters[i].Value = val;
  632. }
  633. }
  634. sb.Append(")");
  635. var insertSql = sb.ToString();
  636. OracleHelper.BatchInsert(con, trans, insertSql, parameters);
  637. //OracleHelper.ExecuteNonQuery(connString, insertSql, parameters);
  638. }
  639. }
  640. trans.Commit();
  641. con.Dispose();
  642. }
  643. catch
  644. {
  645. trans.Rollback();
  646. throw;
  647. }
  648. }
  649. EnableAllFk(dbAddr, user, pwd, serviceName);//导入数据后启用所有外键约束
  650. EnableAllTrigger(dbAddr, user, pwd, serviceName);//导入数据后启用所有触发器
  651. var delFile = Directory.GetFiles(dir);
  652. foreach (var item in delFile)
  653. {
  654. if (item.ToUpper().EndsWith(".DAT") || item.ToUpper().EndsWith(".SQL") || item.ToUpper().EndsWith(".TXT"))
  655. {
  656. File.Delete(item);
  657. }
  658. }
  659. }
  660. #endregion
  661. #region 数据库连接测试
  662. /// <summary>
  663. /// 测试数据库连接
  664. /// </summary>
  665. /// <param name="oracleAddr">oracle地址(127.0.0.1:1521)</param>
  666. /// <param name="user">用户名(不区分大小写)</param>
  667. /// <param name="pwd">密码</param>
  668. /// <param name="serviceName">服务名称(orcl)</param>
  669. public static void TestConnection(string dbAddr, string user, string pwd, string serviceName = "orcl")
  670. {
  671. Directory.CreateDirectory("Backup");
  672. user = user.ToUpper();
  673. string connString = $"Data Source={dbAddr}/{serviceName}; User Id={user}; Password={pwd};";
  674. OracleHelper.TestConnection(connString);
  675. }
  676. /// <summary>
  677. /// 测试数据库连接
  678. /// </summary>
  679. /// <param name="oracleAddr">oracle地址(127.0.0.1:1521)</param>
  680. /// <param name="sysPwd">SYS账户密码</param>
  681. /// <param name="serviceName">服务名称(orcl)</param>
  682. public static void TestSysConnection(string dbAddr, string sysPwd, string serviceName = "orcl")
  683. {
  684. Directory.CreateDirectory("Backup");
  685. string connString = $"Data Source={dbAddr}/orcl; User Id=SYS; Password={sysPwd};DBA Privilege=SYSDBA;";
  686. OracleHelper.TestConnection(connString);
  687. }
  688. #endregion
  689. #region private function
  690. //创建用户并授权
  691. private static void CreateUserIfNotExit(string dbAddr, string user, string pwd, string sysPwd, string serviceName = "orcl")
  692. {
  693. user = user.ToUpper();
  694. string connString = $"Data Source={dbAddr}/orcl; User Id=SYS; Password={sysPwd};DBA Privilege=SYSDBA;";
  695. //1.创建用户
  696. string sql = "SELECT username FROM dba_users WHERE username = :username";
  697. var userObj = OracleHelper.ExecuteScalar(connString, sql,
  698. new OracleParameter("username", user));
  699. if (userObj == null)
  700. {
  701. sql = $"create user {user} identified by {pwd} default tablespace USERS temporary tablespace TEMP profile DEFAULT password expire";
  702. OracleHelper.ExecuteNonQuery(connString, sql);
  703. }
  704. //2.给用户权限
  705. sql = $"grant dba to {user}";
  706. OracleHelper.ExecuteNonQuery(connString, sql);
  707. sql = $"grant create session to {user}";
  708. OracleHelper.ExecuteNonQuery(connString, sql);
  709. sql = $"grant unlimited tablespace to {user}";
  710. OracleHelper.ExecuteNonQuery(connString, sql);
  711. //新用户需要修改一次密码才能登录
  712. sql = $"alter user {user} identified by {pwd} account unlock";
  713. OracleHelper.ExecuteNonQuery(connString, sql);
  714. }
  715. //获取用户下所有表创建SQL
  716. private static Dictionary<string, string> GetAllTableSql(string dbAddr, string user, string pwd, string serviceName = "orcl")
  717. {
  718. user = user.ToUpper();
  719. string connString = $"Data Source={dbAddr}/{serviceName}; User Id={user}; Password={pwd};";
  720. var table = OracleHelper.ExecuteDataTable(connString, $"select table_name,DBMS_METADATA.GET_DDL('TABLE',table_name) FROM all_tables where owner='{user}'");
  721. return table.TableToDictionary();
  722. }
  723. //获取用户下所有序列创建SQL
  724. private static Dictionary<string, string> GetAllSequenceSql(string dbAddr, string user, string pwd, string serviceName = "orcl")
  725. {
  726. user = user.ToUpper();
  727. string connString = $"Data Source={dbAddr}/{serviceName}; User Id={user}; Password={pwd};";
  728. var table = OracleHelper.ExecuteDataTable(connString, $"select sequence_name,DBMS_METADATA.GET_DDL('SEQUENCE',sequence_name) FROM all_sequences where sequence_owner='{user}'");
  729. return table.TableToDictionary();
  730. }
  731. //获取用户下所有触发器创建SQL
  732. private static Dictionary<string, string> GetAllTriggerSql(string dbAddr, string user, string pwd, string serviceName = "orcl")
  733. {
  734. user = user.ToUpper();
  735. string connString = $"Data Source={dbAddr}/{serviceName}; User Id={user}; Password={pwd};";
  736. var table = OracleHelper.ExecuteDataTable(connString, $"select trigger_name,DBMS_METADATA.GET_DDL('TRIGGER',trigger_name) FROM all_triggers where owner='{user}'");
  737. return table.TableToDictionary();
  738. }
  739. //获取用户下所有索引创建SQL(不含唯一索引)
  740. private static Dictionary<string, string> GetAllIndexSql(string dbAddr, string user, string pwd, string serviceName = "orcl")
  741. {
  742. user = user.ToUpper();
  743. string connString = $"Data Source={dbAddr}/{serviceName}; User Id={user}; Password={pwd};";
  744. string sql = $"select index_name,DBMS_METADATA.GET_DDL('INDEX', index_name ) FROM all_indexes WHERE owner = '{user}' AND index_name IN( SELECT user_ind_columns.index_name FROM user_ind_columns, user_indexes WHERE user_ind_columns.index_name = user_indexes.index_name AND user_indexes.uniqueness = 'NONUNIQUE' )";
  745. var table = OracleHelper.ExecuteDataTable(connString, sql);
  746. return table.TableToDictionary();
  747. }
  748. //启用据库所有外键约束
  749. private static void EnableAllFk(string dbAddr, string user, string pwd, string serviceName = "orcl")
  750. {
  751. user = user.ToUpper();
  752. string connString = $"Data Source={dbAddr}/{serviceName}; User Id={user}; Password={pwd};";
  753. string sql = "select 'alter table '||table_name||' enable constraint '||constraint_name from user_constraints where constraint_type='R'";
  754. var sqls = OracleHelper.ExecuteDataTable(connString, sql).TableToListBcl<string>();
  755. sql = string.Join("/", sqls);
  756. OracleHelper.ExecuteNonQuery(connString, sql);
  757. }
  758. //禁用据库所有外键约束
  759. private static void DisableAllFk(string dbAddr, string user, string pwd, string serviceName = "orcl")
  760. {
  761. user = user.ToUpper();
  762. string connString = $"Data Source={dbAddr}/{serviceName}; User Id={user}; Password={pwd};";
  763. string sql = "select 'alter table '||table_name||' disable constraint '||constraint_name from user_constraints where constraint_type='R'";
  764. var sqls = OracleHelper.ExecuteDataTable(connString, sql).TableToListBcl<string>();
  765. sql = string.Join("/", sqls);
  766. OracleHelper.ExecuteNonQuery(connString, sql);
  767. }
  768. //启用据库所有触发器
  769. private static void EnableAllTrigger(string dbAddr, string user, string pwd, string serviceName = "orcl")
  770. {
  771. string connString = $"Data Source={dbAddr}/{serviceName}; User Id={user}; Password={pwd};";
  772. var triggers = GetAllTriggerSql(dbAddr, user, pwd, serviceName).Keys.ToList();
  773. String sql = String.Empty;
  774. foreach (var t in triggers)
  775. {
  776. sql += $"alter trigger {t} enable/";
  777. }
  778. OracleHelper.ExecuteNonQuery(connString, sql);
  779. }
  780. //禁用据库所有触发器
  781. private static void DisableAllTrigger(string dbAddr, string user, string pwd, string serviceName = "orcl")
  782. {
  783. string connString = $"Data Source={dbAddr}/{serviceName}; User Id={user}; Password={pwd};";
  784. var triggers = GetAllTriggerSql(dbAddr, user, pwd, serviceName).Keys.ToList();
  785. String sql = String.Empty;
  786. foreach (var t in triggers)
  787. {
  788. sql += $"alter trigger {t} disable/";
  789. }
  790. OracleHelper.ExecuteNonQuery(connString, sql);
  791. }
  792. //删除用户信息
  793. private static void ClearUserObj(string dbAddr, string deluser, string sysPwd, string serviceName = "orcl")
  794. {
  795. string connString = $"Data Source={dbAddr}/orcl; User Id=SYS; Password={sysPwd};DBA Privilege=SYSDBA;";
  796. //1.创建用户
  797. string sql = "SELECT username FROM dba_users WHERE username = :username";
  798. var userObj = OracleHelper.ExecuteScalar(connString, sql,
  799. new OracleParameter("username", deluser));
  800. if (userObj != null)
  801. {
  802. OracleHelper.ExecuteNonQuery(connString, $"drop user {deluser} cascade");
  803. }
  804. }
  805. //获取表的主键列名(没有主键返回null)
  806. private static string GetPkColumn(string tableName, string dbAddr, string user, string pwd, string serviceName = "orcl")
  807. {
  808. user = user.ToUpper();
  809. tableName = tableName.ToUpper();
  810. string connString = $"Data Source={dbAddr}/{serviceName}; User Id={user}; Password={pwd};";
  811. string sql = $"select column_name from user_cons_columns cu, user_constraints au where cu.constraint_name = au.constraint_name and au.constraint_type = 'P' and au.table_name = '{tableName}' AND au.OWNER='{user}'";
  812. var columns = OracleHelper.ExecuteDataTable(connString, sql).TableToListBcl<string>();
  813. return columns.FirstOrDefault();
  814. }
  815. private static string GetMaxPk(string tableName, string pkColumn, string dbAddr, string user, string pwd, string serviceName = "orcl")
  816. {
  817. user = user.ToUpper();
  818. tableName = tableName.ToUpper();
  819. string connString = $"Data Source={dbAddr}/{serviceName}; User Id={user}; Password={pwd};";
  820. string sql = $"select max({pkColumn}) from {tableName}";
  821. var valObj = OracleHelper.ExecuteScalar(connString, sql);
  822. var maxPk = valObj.ToString();
  823. return maxPk;
  824. }
  825. private static string FindTextName(string text, string filter)
  826. {
  827. var lines = text.Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
  828. foreach (var line in lines)
  829. {
  830. if (line.StartsWith(filter))
  831. {
  832. return line.Substring(filter.Length).ToUpper();
  833. }
  834. }
  835. return null;
  836. }
  837. #endregion
  838. }
  839. }