文档章节

一个用Java语言写的生成SQL(merge)脚本的小工具

北风其凉
 北风其凉
发布于 2016/02/17 00:13
字数 1566
阅读 793
收藏 9

一、工具的制作背景

最近在工作中遇到了这样一个问题:前台的客户端程序需要在后台指定程序更新后清空本地的缓存,后台程序的数量不止一个。这个问题的症结在于客户端程序并不知道后台程序是什么时候更新的,为了解决这个问题,我想了如下的办法:

1、在配置表中设立配置项,保存后台程序的版本号,每次后台程序更新时,将这个版本号也同步更新

2、前台客户端程序也保存一组后台程序的版本号,每次登录程序后读取配置表中的版本号,二者进行比较,如果有一组版本号不匹配,则说明后台程序有变动,前台客户端就需要清空本地的缓存数据了

本次制作的小工具,功能就是在上面的第1步时,根据XML的配置生成若干个SQL语句(merge语句),用于更新配置表中的对应配置项。设计这个工具的目的,一是在修改SQL语句的时候可以避免因马虎等因素造成的语句书写错误,二是同时生成一次语句后可以分享给多个人在多个环境上同时进行升级。

二、工具代码

这个小工具是用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>

各配置项说明如下:

1、output为输出的sql文件路径

2、author为作者信息、remark为备注信息,这两个信息会出现在生出的sql脚本的首部,以注释形式出现

3、每个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包并使用

生成jar包并使用的步骤如下:

1、鼠标右键单击项目,在弹出菜单中点击Export

2、向导页第一页,选择Java→JAR file,点击Next

3、选择刚才正在修改的项目,并在下方“JAR file”位置指定输出的Jar包所在的地址,点击Next

4、这一步直接点击Next

5、点击Browse按钮,指定JAR包入口点

6、找到main函数所在的类,点击OK按钮

7、生成的jar包旁边,建立一个bat文件“GenMergeIntos.bat”,代码如下:

@java -jar GenMergeIntos.jar
@pause

8、运行这个bat文件,运行效果如下:

9、生成的sql文件(updateVer.sql)如下

END

© 著作权归作者所有

共有 人打赏支持
北风其凉

北风其凉

粉丝 115
博文 498
码字总数 463468
作品 4
朝阳
程序员
私信 提问
Java 程序员在写 SQL 程序时候常犯的 10 个错误

Featured article by oschina reproduced with permission by Data Geekery GmbH. English content copyright © 2013 by Data Geekery GmbH. Java程序员编程时需要混合面向对象思维和一般命......

oschina
2013/08/03
14.3K
70
9个杀手级 JVM 编程语言

Java虚拟机已经不再是仅仅局限在 Java 了,很多语言提供了脚本转换,可以让其他的程序在java虚拟机上运行,这样能够让更多的开发者能够依靠JVM在Java平台上大有作为。而且虚拟机以及 对应的字...

junwong
2012/03/23
26.8K
12
美国创业公司所用到的Java开源建站工具

美国程序员Jon Scott Stevens,公布了他的创业公司所使用的开发工具清单。 他的语言平台是Java,开发项目是一个网站(还未上线)。所用到的工具都是开源的,可以免费得到。 在目前的创业者之中...

磊神Ray
2011/08/25
0
1
什么是编译性语言、解释性语言和脚本语言

什么是编译性语言、解释性语言和脚本语言   计算机不能直接理解高级语言,只能直接理解机器语言,所以必须要把高级语言翻译成机器语言,计算机才能值型高级语言编写的程序。  翻译的方式有...

AlphaJay
2010/08/18
0
0
关于 Java Scripting API 您不知道的 5 件事

现在,许多 Java 开发人员都喜欢在 Java 平台中使用脚本语言,但是使用编译到 Java 字节码中的动态语言有时是不可行的。在某些情况中,直接编写一个 Java 应用程序的脚本 部分 或者在一个脚本...

红薯
2010/09/12
494
2

没有更多内容

加载失败,请刷新页面

加载更多

phper必知必会(二)

  1.说说你对进程,线程以及协程的理解      进程:是系统进行资源分配和调度的基本单位,是基本操作系统结构的基础。进程是程序基本执行的实体。进程与进程之间是独立的,拥有完全独立...

SEOwhywhy
10分钟前
0
0
Ubuntu16.04下安装docker

[TOC] 本文开发环境为Ubuntu 16.04 LTS 64位系统,通过apt的docker官方源安装最新的Docker CE(Community Edition),即Docker社区版,是开发人员和小型团队的理想选择。 1. 开始安装 1.1 由于...

豫华商
今天
10
0
使用XShell工具密钥认证登录Linux系统

如果你是一名Linux运维,那么Linux服务器的系统安全问题,可能是你要考虑的,而系统登录方式有两种,密码和密钥。哪一种更加安全呢? 无疑是后者! 这里我为大家分享用Xshell利器使用密钥的方...

dragon_tech
今天
8
0
day178-2018-12-15-英语流利阅读-待学习

“真蛛奶茶”了解一下?蜘蛛也会产奶了 Lala 2018-12-15 1.今日导读 “蛋白质含量是牛奶的 4 倍,并有着更低的脂肪和含糖量”,听起来诱人又美味的并不是羊奶或豆奶,而是你可能打死都想不到...

飞鱼说编程
今天
13
0
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents

场景重现 npm install --verbose 安装依赖的时,出现如下警告 npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.4 (node_modules\fsevents):npm WARN notsup SKIPPING OPTIONA......

taadis
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部