最近在工做中遇到了这样一个问题:前台的客户端程序须要在后台指定程序更新后清空本地的缓存,后台程序的数量不止一个。这个问题的症结在于客户端程序并不知道后台程序是何时更新的,为了解决这个问题,我想了以下的办法:java
一、在配置表中设立配置项,保存后台程序的版本号,每次后台程序更新时,将这个版本号也同步更新sql
二、前台客户端程序也保存一组后台程序的版本号,每次登陆程序后读取配置表中的版本号,两者进行比较,若是有一组版本号不匹配,则说明后台程序有变更,前台客户端就须要清空本地的缓存数据了缓存
本次制做的小工具,功能就是在上面的第1步时,根据XML的配置生成若干个SQL语句(merge语句),用于更新配置表中的对应配置项。设计这个工具的目的,一是在修改SQL语句的时候能够避免因马虎等因素形成的语句书写错误,二是同时生成一次语句后能够分享给多我的在多个环境上同时进行升级。app
这个小工具是用Java语言写的,工程以下:函数
文件version.xml存储了咱们准备配置的版本号信息工具
<?xml version="1.0" encoding="UTF-8"?> <systems author="Tsybius2014" output="updateVer.sql" remark="none"> <!-- 系统1 --> <system config_no="110020" name="System1" version="v1.2.0.1" enabled="true" /> <!-- 系统2 --> <system config_no="110021" name="System2" version="v1.2.3.4" enabled="true" /> <!-- 系统3 --> <system config_no="110022" name="System3" version="v1.0.0.1" enabled="false" /> </systems>
各配置项说明以下:ui
一、output为输出的sql文件路径spa
二、author为做者信息、remark为备注信息,这两个信息会出如今生出的sql脚本的首部,以注释形式出现设计
三、每一个system节点配置了一个系统,config_no为配置项编号,name为配置项说明,version为该系统的版本号,enabled为程序执行时是否生成该系统的MergeInto语句调试
要将version.xml的内容生成为MergeInto语句,还须要一个模板,我将它放在文件template.txt中,内容以下:
MERGE INTO INTERINS.SYS_CONFIG CONFIG USING (SELECT #{config_no} AS CONFIG_NO, '11' AS SUB_SYS_CODE, #{name} AS CONFIG_NAME, '0' AS MANAGE_LEVEL, '0' AS ACCESS_LEVEL, '2' AS DATA_TYPE, #{version} AS STR_CONFIG, '1' AS CONFIG_STATUS, TO_CHAR(SYSDATE,'yyyy-MM-dd HH:mm:ss') AS DATETIME FROM DUAL) INPUT ON (CONFIG.CONFIG_NO = INPUT.CONFIG_NO) WHEN MATCHED THEN UPDATE SET CONFIG.SUB_SYS_CODE = INPUT.SUB_SYS_CODE, CONFIG.CONFIG_NAME = INPUT.CONFIG_NAME, CONFIG.DATA_TYPE = INPUT.DATA_TYPE, CONFIG.STR_CONFIG = INPUT.STR_CONFIG, CONFIG.CONFIG_STATUS = INPUT.CONFIG_STATUS, CONFIG.REMARK = 'UPDATE BY GEN_MERGE_INTOS ON ' || INPUT.DATETIME WHEN NOT MATCHED THEN INSERT (CONFIG_NO, SUB_SYS_CODE, CONFIG_NAME, MANAGE_LEVEL, ACCESS_LEVEL, DATA_TYPE, STR_CONFIG, CONFIG_STATUS, REMARK) VALUES (INPUT.CONFIG_NO, INPUT.SUB_SYS_CODE, INPUT.CONFIG_NAME, INPUT.MANAGE_LEVEL, INPUT.ACCESS_LEVEL, INPUT.DATA_TYPE, INPUT.STR_CONFIG, INPUT.CONFIG_STATUS, 'INSERT BY GEN_MERGE_INTOS ON ' || INPUT.DATETIME);
其中,用config_no替换#{config_no},用name替换#{name},用version替换#{version},就能够生成对应的MergeInto语句了。
GenMergeIntos.java代码以下:
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.Date; import java.util.LinkedList; import java.util.Queue; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /** * SQL脚本生成工具 - 用于系统版本升级后刷新缓存 * * @文件名称 GenMergeIntos.java * @文件做者 Tsybius2014 * @建立时间 2016年2月15日 上午11:01:51 */ public class GenMergeIntos { // 输出文件地址(需从配置文件中读取) static String outputPath = ""; // 输出文件做者(需从配置文件中读取) static String author = ""; // 备注信息(需从配置文件中读取) static String remark = ""; // 配置文件地址 - 调试时请修改成 src\\version.xml static String configPath = "version.xml"; // 模板文件地址 - 调试时请修改成 src\\template.xml static String templatePath = "template.txt"; // 生成的SQL语句暂存于此 static Queue<String> mergeIntos = null; public static void main(String[] args) { //mergeInto语句模板 final String template = getTemplate(templatePath); //存储mergeInto语句 mergeIntos = new LinkedList<String>(); // 设置句柄 DefaultHandler handler = new DefaultHandler() { // XML文档开始读取时触发 public void startDocument() { System.out.println("---------XML文档解析开始---------"); } // XML文档读取结束时触发 public void endDocument() { System.out.println("---------XML文档解析结束---------"); } // 读取到某一元素时触发 public void startElement(String namespaceURI, String lname, String qname, Attributes attrs) { if (qname.equals("systems")) { System.out.println("文件输出路径:" + attrs.getValue("output")); outputPath = attrs.getValue("output"); System.out.println("做者:" + attrs.getValue("author")); author = attrs.getValue("author"); System.out.println("备注:" + attrs.getValue("remark")); remark = attrs.getValue("remark"); } else if (qname.equals("system")) { if (attrs.getValue("enabled").toLowerCase().equals("true")) { System.out.print("读取配置:" + attrs.getValue("name") + "; "); System.out.print("版本号:" + attrs.getValue("version") + "; "); System.out.println("配置号:" + attrs.getValue("config_no")); mergeIntos.add(getMergeInto(template, attrs.getValue("name"), attrs.getValue("version"), attrs.getValue("config_no"))); } } } }; // 使用SAX解析XML SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setNamespaceAware(false); try { File configFile = new File(configPath); SAXParser saxParser = factory.newSAXParser(); saxParser.parse(configFile, handler); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } outputMergeIntos(); System.out.println("程序运行结束"); } /** * 获取模板 * * @param templatePath * @return */ public static String getTemplate(String templatePath) { String template = ""; try { System.out.println("正在输出到文件" + outputPath); StringBuilder buffer = new StringBuilder(); InputStream is = new FileInputStream(templatePath); String line; BufferedReader reader = new BufferedReader( new InputStreamReader(is)); line = reader.readLine(); while (line != null) { buffer.append(line); buffer.append("\n"); line = reader.readLine(); } template = buffer.toString(); reader.close(); is.close(); System.out.println("输出完毕" + outputPath); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return template; } /** * 经过模板生成对应SQL语句 * * @param template * 模板 * @param name * 配置名 * @param version * 版本号 * @param configNo * 配置号 * @return */ public static String getMergeInto(String template, String name, String version, String configNo) { String result = template; result = result.replaceAll("\\#\\{name\\}", "'" + name + "'"); result = result.replaceAll("\\#\\{version\\}", "'" + version + "'"); result = result.replaceAll("\\#\\{config_no\\}", "'" + configNo + "'"); return result; } /** * 将数据输出到文件 */ public static void outputMergeIntos() { try { System.out.println("正在导出到文件:" + outputPath); File outputFile = new File(outputPath); BufferedWriter bw = new BufferedWriter(new PrintWriter(outputFile)); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String currDateTime = sdf.format(new Date()); bw.append("-----------------------------------------------------\n"); bw.append("-- 各子系统相关版本号配置项更新\n"); bw.append("-- 建立时间:" + currDateTime + "\n"); bw.append("-- 建立人员:" + author + "\n"); bw.append("-- 备注信息:" + remark + "\n"); bw.append("-----------------------------------------------------\n"); bw.newLine(); for (String mergeInto : mergeIntos) { bw.append(mergeInto); bw.newLine(); } bw.append("-- 完"); bw.close(); System.out.println("导出完毕"); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
生成jar包并使用的步骤以下:
一、鼠标右键单击项目,在弹出菜单中点击Export
二、向导页第一页,选择Java→JAR file,点击Next
三、选择刚才正在修改的项目,并在下方“JAR file”位置指定输出的Jar包所在的地址,点击Next
四、这一步直接点击Next
五、点击Browse按钮,指定JAR包入口点
六、找到main函数所在的类,点击OK按钮
七、生成的jar包旁边,创建一个bat文件“GenMergeIntos.bat”,代码以下:
@java -jar GenMergeIntos.jar @pause
八、运行这个bat文件,运行效果以下:
九、生成的sql文件(updateVer.sql)以下
END