從文件中讀取SQL語句並批量執行(從ant的taskdefs中SQLExec類提取代碼)


簡述:同時使用spring的jdbcTemplate和ant的taskdefs來執行SQL語句,但是這樣不能把所有操作放在一個事務中。所以把ant的taskdefs中解析SQL語句的代碼提取出來,再使用jdbcTemplate來指執行。

 

現有批量執行文件中的SQL語句可以使用Ant的TaskDefs中的SQLExec類。如:

http://blog.csdn.net/scorpio3k/article/details/4024983 (個人覺得完全沒有必要去把這個類提取出來,不值得花那個時間,一個JAR包也就1M到2M。直接用就行。)

http://ant.apache.org/manual/Tasks/sql.html

 

單獨使用這個方法時沒問題,但是如果和其他事務集成時就有問題了。

比如,有的SQL語句放在XML里,有的放在.SQL文件里 ,總之很多SQL語句放在不同的地方。而且這些SQL都需要放一個事務里執行。

假定使用spring的DataSourceTransactionManager,spring會管理創建並管理連接。

由於SQLExec是自己管理創建並管理連接的,而spring也是這樣。同時使用的時候,其實是通過他們各自的連接更新數據庫,所以並不能放到一個數據庫事務里。

注:我的理解為,事務通過數據庫連接來管理,不同的連接不能放在同一個事務里。還沒有做深入研究,現在看來是這樣。有待深入研究。

 

那么實現同時使用jdbcTemplate和SQLExec來執行SQL,並且要把所有操作放在一個事務里是不現實的。

既然SQLExec能以文件為單位執行SQL,那么里面一定有讀取文件中所有SQL的方法。把這個方法提取出來,然后再用jdbcTemplate執行SQL,就可以把所有SQL放在一個事務里了。

代碼如下:

  1  public  class SQLExtractor {
  2 
  3      private  static SQLExtractor instance;
  4 
  5      /**
  6       * Encoding to use when reading SQL statements from a file
  7        */
  8      private String encoding =  null;
  9 
 10      /**
 11       * Keep the format of a sql block?
 12        */
 13      private  boolean keepformat =  false;
 14 
 15      /**
 16       * delimiters must match in case and whitespace is significant.
 17        */
 18      private  boolean strictDelimiterMatching =  true;
 19 
 20      /**
 21       * SQL Statement delimiter
 22        */
 23      private String delimiter = ";";
 24 
 25      /**
 26       * keep the delimiter in sql or not
 27        */
 28      private  boolean keepDelimiter =  true;
 29 
 30      /**
 31       * The delimiter type indicating whether the delimiter will only be recognized on a line by itself
 32        */
 33      private String delimiterType = DelimiterType.NORMAL;
 34 
 35      /**
 36       * delimiters we support, "normal" and "row"
 37        */
 38      public  static  class DelimiterType  extends EnumeratedAttribute {
 39          /**  The enumerated strings  */
 40          public  static  final String NORMAL = "normal", ROW = "row";
 41 
 42          /**   @return  the enumerated strings  */
 43          public String[] getValues() {
 44              return  new String[] { NORMAL, ROW };
 45         }
 46     }
 47 
 48      private SQLExtractor() {
 49 
 50     }
 51 
 52      public  static  synchronized SQLExtractor getInstance() {
 53          if (instance ==  null) {
 54             instance =  new SQLExtractor();
 55         }
 56          return instance;
 57     }
 58 
 59      public List<String> extract(InputStream is)  throws IOException {
 60         Reader reader =  null;
 61          try {
 62             reader = (encoding ==  null) ?  new InputStreamReader(is) :  new InputStreamReader(is, encoding);
 63              return extract(reader);
 64         }  finally {
 65             FileUtils.close(is);
 66             FileUtils.close(reader);
 67         }
 68     }
 69 
 70      public List<String> extract(Reader reader)  throws IOException {
 71         List<String> sqlList =  new ArrayList<String>();
 72         StringBuffer sql =  new StringBuffer();
 73         String line;
 74 
 75         BufferedReader in =  new BufferedReader(reader);
 76 
 77          while ((line = in.readLine()) !=  null) {
 78              if (!keepformat) {
 79                 line = line.trim();
 80             }
 81              //  if (expandProperties) {
 82               //  line = getProject().replaceProperties(line);
 83               //  }
 84 
 85              if (!keepformat) {
 86                  if (line.startsWith("//")) {
 87                      continue;
 88                 }
 89                  if (line.startsWith("--")) {
 90                      continue;
 91                 }
 92                 StringTokenizer st =  new StringTokenizer(line);
 93                  if (st.hasMoreTokens()) {
 94                     String token = st.nextToken();
 95                      if ("REM".equalsIgnoreCase(token)) {
 96                          continue;
 97                     }
 98                 }
 99             }
100 
101             sql.append(keepformat ? "\n" : " ").append(line);
102 
103              //  SQL defines "--" as a comment to EOL
104               //  and in Oracle it may contain a hint
105               //  so we cannot just remove it, instead we must end it
106               if (!keepformat && line.indexOf("--") >= 0) {
107                 sql.append("\n");
108             }
109              int lastDelimPos = lastDelimiterPosition(sql, line);
110              if (lastDelimPos > -1) {
111                  //  execSQL(sql.substring(0, lastDelimPos), out);
112                  String sqlStr = keepDelimiter ? sql.toString() : eliminateLastColon(sql.toString());
113                 sqlList.add(sqlStr);
114                 sql.replace(0, sql.length(), "");
115             }
116         }
117 
118          //  Catch any statements not followed by ;
119           if (sql.length() > 0) {
120              //  execSQL(sql.toString(), out);
121              sqlList.add(sql.toString());
122         }
123 
124          return sqlList;
125     }
126 
127      private String eliminateLastColon(String sql) {
128         sql = sql.trim();
129          if (org.apache.commons.lang.StringUtils.endsWith(sql, ";")) {
130              return sql.substring(0, sql.length() - 1);
131         }
132          return sql;
133     }
134 
135      private  int lastDelimiterPosition(StringBuffer buf, String currentLine) {
136          if (strictDelimiterMatching) {
137              if ((delimiterType.equals(DelimiterType.NORMAL) && StringUtils.endsWith(buf, delimiter))
138                     || (delimiterType.equals(DelimiterType.ROW) && currentLine.equals(delimiter))) {
139                  return buf.length() - delimiter.length();
140             }
141              //  no match
142               return -1;
143         }  else {
144             String d = delimiter.trim().toLowerCase(Locale.ENGLISH);
145              if (delimiterType.equals(DelimiterType.NORMAL)) {
146                  //  still trying to avoid wasteful copying, see
147                   //  StringUtils.endsWith
148                   int endIndex = delimiter.length() - 1;
149                  int bufferIndex = buf.length() - 1;
150                  while (bufferIndex >= 0 && Character.isWhitespace(buf.charAt(bufferIndex))) {
151                     --bufferIndex;
152                 }
153                  if (bufferIndex < endIndex) {
154                      return -1;
155                 }
156                  while (endIndex >= 0) {
157                      if (buf.substring(bufferIndex, bufferIndex + 1).toLowerCase(Locale.ENGLISH).charAt(0) != d.charAt(endIndex)) {
158                          return -1;
159                     }
160                     bufferIndex--;
161                     endIndex--;
162                 }
163                  return bufferIndex + 1;
164             }  else {
165                  return currentLine.trim().toLowerCase(Locale.ENGLISH).equals(d) ? buf.length() - currentLine.length() : -1;
166             }
167         }
168     }
169 
170      //  --------------------------------------------------------------------------------
171       //
172       //  getter and setter
173       //
174       //  --------------------------------------------------------------------------------
175 
176      public String getEncoding() {
177          return encoding;
178     }
179 
180      public  void setEncoding(String encoding) {
181          this.encoding = encoding;
182     }
183 
184      public  boolean isKeepformat() {
185          return keepformat;
186     }
187 
188      public  void setKeepformat( boolean keepformat) {
189          this.keepformat = keepformat;
190     }
191 
192      public  boolean isStrictDelimiterMatching() {
193          return strictDelimiterMatching;
194     }
195 
196      public  void setStrictDelimiterMatching( boolean strictDelimiterMatching) {
197          this.strictDelimiterMatching = strictDelimiterMatching;
198     }
199 
200      public String getDelimiter() {
201          return delimiter;
202     }
203 
204      public  void setDelimiter(String delimiter) {
205          this.delimiter = delimiter;
206     }
207 
208      public  boolean isKeepDelimiter() {
209          return keepDelimiter;
210     }
211 
212      public  void setKeepDelimiter( boolean keepDelimiter) {
213          this.keepDelimiter = keepDelimiter;
214     }
215 

216 } 

 

注:這里添加了一個選項,keepDelimite。SQL語句中是否保存結束標記。

比如有的數據庫驅動執行結尾帶";"的SQL語句會報錯(我碰到的是ojdbc6的oracle thin驅動連接oracle 11g r2),必須要把";"去掉。

 

測試代碼: 
public  static  void main(String[] args)  throws Exception {
        ClassPathResource res =  new ClassPathResource("test.sql");
        SQLExtractor ext = SQLExtractor.getInstance();
        List<String> list = ext.extract(res.getInputStream());
         for (String s : list) {
            System.out.println(s);
        }

}  

批量執行SQL的代碼(性能有待優化):

/**
     * batch execute sql
     * 
     * 
@param  sqlList sql statement list
     * 
@param  batch sql count in each batch
     
*/
     private  void batchUpdate(List<String> sqlList,  int batch)  throws Exception {
        List<String> sqls =  new LinkedList<String>();
         int index = 0;
         int i = 0;

         while (index < sqlList.size()) {
             if (i == batch) {
                jdbcTemplate.batchUpdate(sqls.toArray( new String[0]));

                i = 0;
                sqls =  new LinkedList<String>();
            }

            sqls.add(sqlList.get(index));

             if (index == sqlList.size() - 1) {
                jdbcTemplate.batchUpdate(sqls.toArray( new String[0]));
            }

            ++index;
            ++i;
        }

    } 

 

所有文件:SQLExtractor.zip 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM