从文件中读取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