好一段时间没写博客了,这次我们来一起谈谈SQL文件执行器的功能实现,在ERP软件升级时往往在客户端程序更新的同时也要对数据库进行升级,ERP程序开发人员会对数据库升级的执行代码在开发的过程中以SQL文件的形式记录下来或者保存到特定格式的文件中供软件升级时使用,有些ERP软件会附带开发数据库升级工具来方便实施人员执行软件升级操作或者ERP软件内置数据库升级功能,不管使用什么样的方式能达到软件升级的目的就是好方法,这次我们就来剥离这部分的功能来实现一个SQL文件执行器,不特定于SQL文件,只要文件里面包含有SQL语法,而且能正常得到执行,在本执行器中就能正确的执行它(本次我们主要争对SQL文件,其他格式文件只要把相关控制去掉就好了,只是得不到很好的控制比较乱,或者你有更好的方法)。介绍性引入就到此为止了,接下来我们开始进入主题,研究一下SQL执行器的原理及设计思路吧。

一、SQL文件执行器原理分析

在分析原理之前,我们先来规范一下SQL文档的书写,我们在一个SQL语句结束的时候换行来个GO关键字再换行继续书写下一个SQL语句,遇到“USE [数据库名] ”语句时希望能把此语句单独放一行。做到以上书写规范我们开始原理分析:

1.上述SQL规范居然都做到了但是SQL文件里面的内容还不是我想要的,我想重新规范一下我的SQL文档,我想理想化它,所以我需要对SQL文件进行重新洗牌,我想我应该一行一行的阅读它,并把它提取出来去掉前后的空格,我应该重组改文件的内容并且在读取每一行的同时在其末尾写入一个换行回车符,而且我还想统计出每一个SQL文件中的SQL语句的个数(循环时会用到),我用GO关键字来标记了SQL语句的个数,在阅读到一行去掉首尾空格后只剩下不区分大小写的GO时我的统计会+1(统计从1开始),哦,这还永远不够,我还没考虑到USE关键字的处理,通常会选择一个数据库来执行相应的SQL文件,USE关键字在切换着数据库,我需要在检测到USE语句时切换数据库为USE后面跟着的数据库来执行后面的代码,所以我要把USE语句单独剥离开来以待做特殊的处理,往往我们写SQL文件的时候在USE语句的前后都不带GO关键字的,我需要给它加上。有一个需要注意的地方:USE [数据库名]  后面直接跟着SQL语句的(没有回车换行),这种写法在语法上是完全正确的,但是看上去就不是很美观了,这种方式我这边就不做处理了,请遵守上述规范吧,再处理下去程序性能就严重下降啦,本程序在数据库切换时是从USE 之后的字符开始到回车换行符结束来取数据库名的,这种写法会引发SQL异常。我需要构建一个这样的方法。

2.在第一点里面我们对SQL文件进行了格式化,现在开始我希望以GO关键字作为分割点,把SQL文件里面的SQL语法进行分段,我希望一段段的得到执行并返回执行结果,此时我需要一个循环来遍历文件中的SQL语句并执行它。本工具名字叫做SQL文件执行器很显然是争对批量SQL文件的处理的,所以一个循环是永远不够的,我还得在外面再套一个循环来遍历所有的SQL文件,对每个SQL文件进行分析并遍历其中的SQL语句执行它,这样就达到我们的目的了。貌似还有一个问题未处理,比如在执行到一半的时候我不执行了需要强制停止他这如何是好呢,强制关闭程序很显然是不可取的很容易引发未知的数据库异常或者造成数据丢失这些状况都是我们不想看到的,那么有什么好办法呢?此时我启用了臭名远扬的goto语句来从深层嵌套循环中跳出循环,我让他在用户发出停止指令后在执行完当前的SQL语法段后跳出循环,从而停止接下来的SQL语法的执行,这样子保障了SQL数据的安全,在SQL文件执行的期间,程序是不允许关闭的,除非向程序发出停止指令,并成功停止的时候,才允许程序关闭。

很简单的一个程序,我就大致的做以上两点的原理分析吧,接下来我上传下我的程序界面设计图吧,大家参考下:

接下来我贴上来一些主要源代码供参考,代码可能看上去有些难懂,表述性不是很好,期待大家来改进它:

这是对SQL文件中的语法进行重新洗牌的方法

  1. /// <summary>
  2. /// 读取文件内容(SQL关键字特殊处理主要针对GO关键字)
  3. /// </summary>
  4. /// <param name="path">文件路径</param>
  5. /// <param name="keywords">关键字</param>
  6. /// <param name="str">输出字符串</param>
  7. /// <param name="i">keywords的个数</param>
  8. public void FileReader(string path,string keywords,out int i,out string str)
  9. {
  10. bool useplusgo = false;//use后面是否跟着go
  11. bool goplususe = false;//use前面是否存在go
  12. StreamReader sr = new StreamReader(path, Encoding.GetEncoding("GB2312"));
  13. //str = sr.ReadToEnd();
  14. string s = null;
  15. string temp = null;
  16. int x = 0;
  17. while ((temp = sr.ReadLine()) != null)
  18. {
  19. if (temp.Trim().ToUpper() == keywords.ToUpper())
  20. {
  21. useplusgo = false;//use语句后面跟着go则关闭use判断
  22. goplususe = true;//use前面存在go
  23. x++;
  24. s += "\r\n" + keywords + "\r\n \r\n";
  25. }
  26. else if (temp.Trim().Length >= 4 && temp.Trim().ToUpper().Substring(0, 4).Trim() == "USE")
  27. {
  28. temp = temp.Trim().Replace("[", "").Replace("]", "");
  29. //如果use前面不存在go则加上
  30. if (!goplususe && s != "\r\n" && s != null)
  31. {
  32. x++;
  33. s += "\r\n" + keywords + "\r\n\r\n" + temp + "\r\n";
  34. }
  35. else
  36. {
  37. s += temp + "\r\n";
  38. }
  39. useplusgo = true;
  40. }
  41. else
  42. {
  43. goplususe = false;//go后面不跟use关闭判断
  44. //如果use后面不跟go则加上go
  45. if (useplusgo)
  46. {
  47. x++;
  48. s += "\r\n" + keywords + "\r\n" + temp + "\r\n";
  49. useplusgo = false;//关闭use判断
  50. }
  51. else
  52. {
  53. s += temp + "\r\n";
  54. }
  55. }
  56. }
  57. i = x;
  58. str = s;
  59. sr.Close();//关闭当前打开的文件
  60. }

这个是处理USE语句的方法

  1. /// <summary>
  2. /// 获取use后面的数据库名称
  3. /// </summary>
  4. /// <param name="str">use字符串行</param>
  5. /// <returns></returns>
  6. public string UseStatementProcessing(string str)
  7. {
  8. string[] strSplit = Regex.Split(str, "\r\n", RegexOptions.IgnoreCase);
  9. int x = strSplit.Length;
  10. string s = "";
  11. if (/*strSplit[0].ToUpper().IndexOf("USE ", 0) >= 0*/Regex.IsMatch(strSplit[0].ToUpper(), "USE ", RegexOptions.IgnoreCase))
  12. {
  13. s = strSplit[0].Substring(4, strSplit[0].Length - 4).Trim();
  14. }
  15. else if (/*strSplit[1].ToUpper().IndexOf("USE ", 0) >= 0*/Regex.IsMatch(strSplit[1].ToUpper(), "USE ", RegexOptions.IgnoreCase))
  16. {
  17. s = strSplit[1].Substring(4, strSplit[1].Length - 4).Trim();
  18. }
  19. else
  20. {
  21. s = "";
  22. }
  23. return s;
  24. }

这次话题就到此为止吧,这程序比较简单,大家可以写写玩,当作练练手也不错,主要在于文件的操作和字符串的处理。

C# SQL文件执行器的功能实现的更多相关文章

  1. SQL脚本文件执行器

    处于项目需求,需要能够批量执行SQL脚本文件,需要由前台页面操作触发执行. 查找相关资料,发现 Ant 提供了 SQLExec 组件可以支持SQL文件的执行,测试效果不错. 以下是对 SQLExec ...

  2. mysql 导入导出.sql文件

    备份数据库(包含全部表和全部存储过程):C:\Documents and Settings\Administrator>mysqldump -h localhost -u root -p -R ...

  3. 批量执行SQL文件

    原文:批量执行SQL文件 摘要:很多时候我们在做系统升级时需要将大量的.sql文件挨个执行,十分不方便.而且考虑到执行顺序和客服的操作方便性,能不能找到一种简单的方法来批量执行这些sql文件呢? 主要 ...

  4. SQL点滴7—使用SQL Server的attach功能出现错误及解决方法

    原文:SQL点滴7-使用SQL Server的attach功能出现错误及解决方法 今天用SQL Server 2008的attach功能附加一个数据库,出了点问题,提示的错误是: Unable to ...

  5. java 网络编程之TCP通信和简单的文件上传功能

    */ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...

  6. navicat导入.sql文件

    用Navicat for Mysql导入.sql文件   虽然这算不上什么难事,但是对于新手来说(比如说我),Navicat for MySQL里的导出连接.运行SQL文件.导入向导.还原备份.这些功 ...

  7. oracle导入大sql文件

    最近遇到一个需要导入大SQL文件的问题,最先直接用SQL developer 导入大SQL文件,结果报IO Exception,只好采用sqlplus 导入,操作过程如下: sqlplus 用户名/密 ...

  8. [.NET开发] C#实现的SQL备份与还原功能示例

    本文实例讲述了C#实现的SQL备份与还原功能.分享给大家供大家参考,具体如下: //记得加 folderBrowserDialog1 openFileDialog1 控件 using System.D ...

  9. PHP导出sql文件

    发现自己之前写的php导出sql数据为Excel文件在导出一些数据的时候出现了精度的问题,比如导出身份证号的时候会把后面变成0000.暂时先把这个问题留下,有空去看看到底是什么问题. 写了一个导出sq ...

随机推荐

  1. JNDI(转载)

    转自:http://javacrazyer.iteye.com/blog/759485 原理:         在DataSource中事先建立多个数据库连接,保存在数据库连接池中.当程序访问数据库时 ...

  2. chrome提供的功能

    chrome://chrome-urls/ List of Chrome URLs chrome://accessibility chrome://appcache-internals chrome: ...

  3. Magento WebServices SOAP API 创建和使用

    首先 SOAP 简介: http://baike.baidu.com/view/1695890.htm?fromtitle=SOAP 然后简单介绍下Magento API.Magento API干啥用 ...

  4. 深入理解java String 对象的不可变性

    下面我们通过一组图表来解释Java字符串的不可变性 1.声明一个String对象 String s = "abcd"; 2.将一个String变量赋值给另一个String变量 St ...

  5. Euro Efficiency(完全背包)

    Euro Efficiency Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 20000/10000K (Java/Other) Tot ...

  6. html系列教程--span style 及表格标签 title video

    <span> 标签:非块状元素,用于文本描述 <style> 标签:内联样式表标签定义样式信息,必须写明type类型为text/css,建议写在head中,不是必须 demo: ...

  7. hibernate 简单查询

    1. 查询整个映射对象所有字段 //直接from查询出来的是一个映射对象,即:查询整个映射对象所有字段           String hql = "from Users";   ...

  8. js实现睡眠

    //js暂停函数 function Pause(obj, iMinSecond) { if (window.eventList == null) window.eventList = new Arra ...

  9. Java语言导学笔记 Chapter 9 IO

    java.io 9.1.1 字符流 Reader为读取器(reader)提供API和部分实现,读取器是读取16位字符的流: Writer为写出器(writer)提供API和部分实现,写出器是写16位字 ...

  10. DevExpress中GridControl的属性设置

    1.隐藏最上面的GroupPanel gridView1.OptionsView.ShowGroupPanel=false; 2.得到当前选定记录某字段的值 sValue=Table.Rows[gri ...