Java 执行 SQL 脚本文件

来源:互联网 发布:滴滴php面试题 编辑:程序博客网 时间:2024/05/13 08:17

假定Java 程序中要定期执行 SQL 语句,因需求变更应修改原有 SQL 语句或者加上更多的语句时,不得不修改源代码,然后再次编译。要是把 SQL 语句写在单独的 SQL 脚本文件中,由 Java 程序来定时加载执行,那么每次改动时仅仅修改 SQL 脚本文件就行了。

Java 没有提供现成的东西,所以自己写了一个这样的 SQL 脚本执行类 SqlFileExecutor。支持通用的 SQL 脚本文件,"--" 作为注释前导符,分号 ";" 分隔语句。不支持 MySQL 的 /*...*/ 形式的注释格式。对于 Windows 和 Linux/Unix 下编辑的脚本文件都测试通过。这两个系统文件中的换行符不一样,Windows 是 "\r\n",Linux/Unix 是 "\n"。

  1. package com.unmi.db;   
  2.   
  3. import java.io.FileInputStream;   
  4. import java.io.InputStream;   
  5. import java.sql.Connection;   
  6. import java.sql.Statement;   
  7. import java.util.ArrayList;   
  8. import java.util.Arrays;   
  9. import java.util.List;   
  10.   
  11. /**
  12. * 读取 SQL 脚本并执行
  13. * @author Unmi
  14. */  
  15. public class SqlFileExecutor {   
  16.   
  17.     /**
  18.       * 读取 SQL 文件,获取 SQL 语句
  19.       * @param sqlFile SQL 脚本文件
  20.       * @return List<sql> 返回所有 SQL 语句的 List
  21.       * @throws Exception
  22.       */  
  23.     private List<String> loadSql(String sqlFile) throws Exception {   
  24.          List<String> sqlList = new ArrayList<String>();   
  25.   
  26.         try {   
  27.              InputStream sqlFileIn = new FileInputStream(sqlFile);   
  28.   
  29.              StringBuffer sqlSb = new StringBuffer();   
  30.             byte[] buff = new byte[1024];   
  31.             int byteRead = 0;   
  32.             while ((byteRead = sqlFileIn.read(buff)) != -1) {   
  33.                  sqlSb.append(new String(buff, 0, byteRead));   
  34.              }   
  35.   
  36.             // Windows 下换行是 \r\n, Linux 下是 \n   
  37.              String[] sqlArr = sqlSb.toString().split("(;\\s*\\r\\n)|(;\\s*\\n)");   
  38.             for (int i = 0; i < sqlArr.length; i++) {   
  39.                  String sql = sqlArr[i].replaceAll("--.*""").trim();   
  40.                 if (!sql.equals("")) {   
  41.                      sqlList.add(sql);   
  42.                  }   
  43.              }   
  44.             return sqlList;   
  45.          } catch (Exception ex) {   
  46.             throw new Exception(ex.getMessage());   
  47.          }   
  48.      }   
  49.   
  50.     /**
  51.       * 传入连接来执行 SQL 脚本文件,这样可与其外的数据库操作同处一个事物中
  52.       * @param conn 传入数据库连接
  53.       * @param sqlFile SQL 脚本文件
  54.       * @throws Exception
  55.       */  
  56.     public void execute(Connection conn, String sqlFile) throws Exception {   
  57.          Statement stmt = null;   
  58.          List<String> sqlList = loadSql(sqlFile);   
  59.          stmt = conn.createStatement();   
  60.         for (String sql : sqlList) {   
  61.              stmt.addBatch(sql);   
  62.          }   
  63.         int[] rows = stmt.executeBatch();   
  64.          System.out.println("Row count:" + Arrays.toString(rows));   
  65.      }   
  66.   
  67.     /**
  68.       * 自建连接,独立事物中执行 SQL 文件
  69.       * @param sqlFile SQL 脚本文件
  70.       * @throws Exception
  71.       */  
  72.     public void execute(String sqlFile) throws Exception {   
  73.          Connection conn = DBCenter.getConnection();   
  74.          Statement stmt = null;   
  75.          List<String> sqlList = loadSql(sqlFile);   
  76.         try {   
  77.              conn.setAutoCommit(false);   
  78.              stmt = conn.createStatement();   
  79.             for (String sql : sqlList) {   
  80.                  stmt.addBatch(sql);   
  81.              }   
  82.             int[] rows = stmt.executeBatch();   
  83.              System.out.println("Row count:" + Arrays.toString(rows));   
  84.              DBCenter.commit(conn);   
  85.          } catch (Exception ex) {   
  86.              DBCenter.rollback(conn);   
  87.             throw ex;   
  88.          } finally {   
  89.              DBCenter.close(null, stmt, conn);   
  90.          }   
  91.      }   
  92.   
  93.     public static void main(String[] args) throws Exception {   
  94.          List<String> sqlList = new SqlFileExecutor().loadSql(args[0]);   
  95.          System.out.println("size:" + sqlList.size());   
  96.         for (String sql : sqlList) {   
  97.              System.out.println(sql);   
  98.          }   
  99.      }   
  100. }  

程序功能:加载 SQL 脚本文件,去除注释行,分离出 SQL 语句;提供两个 execute() 执行方法,分别是传数据库连接与不传连接的。传入连接的方法可以让它与外部数据库操作同处一个事物中,当然如果能用其他机制保证事物的原子性也行。另一个是自己管理数据库资源,例子中的 DBCenter 类留给读者自己来实现,包括获取、关闭连接,提交、回滚事物方法。

原创粉丝点击