Chinaunix首页 | 论坛 | 博客
  • 博客访问: 780392
  • 博文数量: 372
  • 博客积分: 10063
  • 博客等级: 中将
  • 技术积分: 4220
  • 用 户 组: 普通用户
  • 注册时间: 2012-02-24 11:36
文章分类

全部博文(372)

文章存档

2012年(372)

分类: 系统运维

2012-03-30 20:51:06

简述:同时使用spring的jdbcTemplate和ant的taskdefs来执行SQL语句,但是这样不能把所有操作放在一个事务中。所以把ant的taskdefs中解析SQL语句的代码提取出来,再使用jdbcTemplate来指执行。

现有批量执行文件中的SQL语句可以使用Ant的TaskDefs中的SQLExec类。如:

http://blog.csdn.net/scorpio3k/article/details/4024983 (个人觉得完全没有必要去把这个类提取出来,不值得花那个时间,一个JAR包也就1M到2M。直接用就行。)


单独使用这个方法时没问题,但是如果和其他事务集成时就有问题了。

比如,有的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 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 extract(Reader reader) throws IOException {
71 List sqlList = new ArrayList();
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语句中是否保存结束标记。

比如jtds (net.sourceforge.jtds.jdbc.Driver,SQLSERVER的JDBC驱动) ,执行结尾带";"的SQL语句会报错,必须要把";"去掉。

测试代码:

public static void main(String[] args) throws Exception {
ClassPathResource res = new ClassPathResource("test.sql");
SQLExtractor ext = SQLExtractor.getInstance();
List 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 sqlList, int batch) throws Exception {
List sqls = new LinkedList();
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();
}

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

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

++index;
++i;
}

}

阅读(812) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~