假定Java 程式中要定期執行 SQL 陳述式,因需求變更應修改原有 SQL 陳述式或者加上更多的語句時,不得不修改原始碼,然後再次編譯。要是把 SQL 陳述式寫在單獨的 SQL 指令檔中,由 Java 程式來定時載入執行,那麼每次改動時僅僅修改 SQL 指令檔就行了。
Java 沒有提供現成的東西,所以自己寫了一個這樣的 SQL 指令碼執行類 SqlFileExecutor。支援通用的 SQL 指令檔,"--" 作為注釋前置字元,分號 ";" 分隔語句。不支援 MySQL 的 /*...*/ 形式的注釋格式。對於 Windows 和 Linux/Unix 下編輯的指令檔都測試通過。這兩個系統檔案中的分行符號不一樣,Windows 是 "\r\n",Linux/Unix 是 "\n"。
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 類留給讀者自己來實現,包括擷取、關閉串連,提交、復原事物方法。