DbHelper.cs 44 KB

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