) obj;
314 | } else if (obj instanceof String[]) {
315 | set = Arrays.asList((String[]) obj);
316 | }
317 | // 如果不是集合类型.
318 | if (set == null) {
319 | pstsParam.add(new ParameterPrepareStatement(sqlpos, String.valueOf(obj)));
320 | return "?";
321 | } else {
322 | if (set.size() > 0) {
323 | for (Object s : set) {
324 | String p = String.valueOf(s);
325 | pstsParam.add(new ParameterPrepareStatement(sqlpos, p));
326 | sqlbuf.append('?').append(',');
327 | }
328 | sqlbuf.deleteCharAt(sqlbuf.length() - 1);
329 | }
330 | return sqlbuf.toString();
331 | }
332 | }
333 |
334 | private String parseConcat() throws IOException, SqlParseException {
335 | curChar = readandsavepre();
336 | StringBuilder sqlbuf = new StringBuilder();
337 | ParameterEval paramName = null;
338 | switch (curChar) {
339 | case -1:
340 | sqlbuf.append((char) prechar);
341 | break;
342 | case '{':
343 | paramName = readParamerUntil(new char[] { '}' });
344 | break;
345 | default:
346 | sqlbuf.append((char) prechar).append((char) curChar);
347 | }
348 |
349 | // 已获取解析后的参数名
350 | if (paramName != null) {
351 | String tmp = (String) paramName.getValueFromMap(param);
352 | if (tmp != null) {
353 | sqlbuf.append(tmp);
354 | }
355 | }
356 | return sqlbuf.toString();
357 | }
358 |
359 | private String readUntil(char[] c, boolean isparseParamName) throws IOException, SqlParseException {
360 | curChar = readandsavepre();
361 | StringBuilder strbuf = new StringBuilder();
362 | while (curChar != -1 && search(c, curChar) == -1) {
363 |
364 | if (isparseParamName) {
365 | strbuf.append(parseParameter());
366 | } else {
367 | // 对于要丢弃的字符,不再解析
368 | strbuf.append('\\'==curChar ?escape():(char) curChar);
369 | }
370 |
371 | curChar = readandsavepre();
372 | }
373 | if (curChar == -1) {
374 | throw new SqlParseException(strbuf.append(
375 | " :position[" + (sqlpos - strbuf.length()) + "]\t expect {" + Arrays.toString(c) + "}").toString());
376 | } else {
377 | return strbuf.toString();
378 | }
379 | }
380 |
381 | private String parseParameter() throws SqlParseException, IOException {
382 | switch (curChar) {
383 | case '\r':
384 | case '\n':
385 | throw new SqlParseException("parameter contains '\\r' ,'\\n' ");
386 | case '\\':
387 | return escape();
388 | case '#':
389 | return parseConcat();
390 | default:
391 | return String.valueOf((char) curChar);
392 | }
393 | }
394 |
395 | private int search(char[] chars, int c) {
396 | if (chars == null || chars.length == 0)
397 | return -1;
398 | for (int i = 0; i < chars.length; i++) {
399 | if (c == chars[i]) {
400 | return i;
401 | }
402 | }
403 | return -1;
404 | }
405 |
406 | private ParameterEval readParamerUntil(char[] chars) throws IOException, SqlParseException {
407 | curChar = readandsavepre();
408 | StringBuilder strbuf = new StringBuilder();
409 | while (curChar != -1 && curChar != '|' && search(chars, curChar) == -1) {
410 | String tmp = parseParameter();
411 | strbuf.append(tmp);
412 | curChar = readandsavepre();
413 | }
414 | // 去掉参数名的空格
415 | String name = strbuf.toString().trim();
416 | // 参数名为空
417 | if (StringUtils.isEmpty(name)) {
418 | throw new SqlParseException(" after \"" + (char) prechar + (char) curChar
419 | + "\", Parameter Name is null at position : " + sqlpos);
420 | }
421 |
422 | if (curChar == -1) {
423 | throw new SqlParseException(strbuf.append(
424 | " :position[" + (sqlpos - strbuf.length()) + "]\t expect {" + Arrays.toString(chars) + "}")
425 | .toString());
426 | } else if (curChar == '|') {
427 |
428 | // 读取filter内容,应该是一段可执行的js脚本
429 | String jsCode = readUntil(chars, false);
430 |
431 | return new ParameterEval(name, jsCode, ParamType.Array.equals(paramtype));
432 | } else {
433 | return new ParameterEval(name, null, ParamType.Array.equals(paramtype));
434 | }
435 | }
436 |
437 | private int readandsavepre() throws IOException {
438 | prechar = curChar;
439 | curChar = in.read();
440 | sqlpos++;
441 | return curChar;
442 | }
443 |
444 | }
--------------------------------------------------------------------------------
/src/test/java/com/lihuanghe/DynamicScopes.java:
--------------------------------------------------------------------------------
1 | package com.lihuanghe;
2 |
3 | /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
4 | *
5 | * This Source Code Form is subject to the terms of the Mozilla Public
6 | * License, v. 2.0. If a copy of the MPL was not distributed with this
7 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 |
9 | import sun.org.mozilla.javascript.internal.Context;
10 | import sun.org.mozilla.javascript.internal.ContextFactory;
11 | import sun.org.mozilla.javascript.internal.Script;
12 | import sun.org.mozilla.javascript.internal.Scriptable;
13 | import sun.org.mozilla.javascript.internal.ScriptableObject;
14 |
15 | /**
16 | * Example of controlling the JavaScript with multiple scopes and threads.
17 | */
18 | public class DynamicScopes {
19 |
20 | static boolean useDynamicScope;
21 |
22 | static class MyFactory extends ContextFactory
23 | {
24 | @Override
25 | protected boolean hasFeature(Context cx, int featureIndex)
26 | {
27 | if (featureIndex == Context.FEATURE_DYNAMIC_SCOPE) {
28 | return useDynamicScope;
29 | }
30 | return super.hasFeature(cx, featureIndex);
31 | }
32 | }
33 |
34 | static {
35 | ContextFactory.initGlobal(new MyFactory());
36 | }
37 |
38 |
39 | /**
40 | * Main entry point.
41 | *
42 | * Set up the shared scope and then spawn new threads that execute
43 | * relative to that shared scope. Try to run functions with and
44 | * without dynamic scope to see the effect.
45 | *
46 | * The expected output is
47 | *
48 | * sharedScope
49 | * nested:sharedScope
50 | * sharedScope
51 | * nested:sharedScope
52 | * sharedScope
53 | * nested:sharedScope
54 | * thread0
55 | * nested:thread0
56 | * thread1
57 | * nested:thread1
58 | * thread2
59 | * nested:thread2
60 | *
61 | * The final three lines may be permuted in any order depending on
62 | * thread scheduling.
63 | */
64 | public static void main(String[] args)
65 | {
66 | Context cx = Context.enter();
67 | try {
68 | // Precompile source only once
69 | String source = ""
70 | +"var x = 'sharedScope';\n"
71 | +"function f() { return x; }\n"
72 | // Dynamic scope works with nested function too
73 | +"function initClosure(prefix) {\n"
74 | +" return function test() { return prefix+x; }\n"
75 | +"}\n"
76 | +"var closure = initClosure('nested:');\n"
77 | +"";
78 | Script script = cx.compileString(source, "sharedScript", 1, null);
79 |
80 | useDynamicScope = false;
81 | runScripts(cx, script);
82 | useDynamicScope = true;
83 | runScripts(cx, script);
84 | } finally {
85 | Context.exit();
86 | }
87 | }
88 |
89 | static void runScripts(Context cx, Script script)
90 | {
91 | // Initialize the standard objects (Object, Function, etc.)
92 | // This must be done before scripts can be executed. The call
93 | // returns a new scope that we will share.
94 | ScriptableObject sharedScope = cx.initStandardObjects(null, true);
95 |
96 | // Now we can execute the precompiled script against the scope
97 | // to define x variable and f function in the shared scope.
98 | script.exec(cx, sharedScope);
99 |
100 | // Now we spawn some threads that execute a script that calls the
101 | // function 'f'. The scope chain looks like this:
102 | //
103 | // ------------------ ------------------
104 | // | per-thread scope | -prototype-> | shared scope |
105 | // ------------------ ------------------
106 | // ^
107 | // |
108 | // parentScope
109 | // |
110 | // ------------------
111 | // | f's activation |
112 | // ------------------
113 | //
114 | // Both the shared scope and the per-thread scope have variables 'x'
115 | // defined in them. If 'f' is compiled with dynamic scope enabled,
116 | // the 'x' from the per-thread scope will be used. Otherwise, the 'x'
117 | // from the shared scope will be used. The 'x' defined in 'g' (which
118 | // calls 'f') should not be seen by 'f'.
119 | final int threadCount = 3;
120 | Thread[] t = new Thread[threadCount];
121 | for (int i=0; i < threadCount; i++) {
122 | String source2 = ""
123 | +"function g() { var x = 'local'; return f(); }\n"
124 | +"java.lang.System.out.println(g());\n"
125 | +"function g2() { var x = 'local'; return closure(); }\n"
126 | +"java.lang.System.out.println(g2());\n"
127 | +"";
128 | t[i] = new Thread(new PerThread(sharedScope, source2,
129 | "thread" + i));
130 | }
131 | for (int i=0; i < threadCount; i++)
132 | t[i].start();
133 | // Don't return in this thread until all the spawned threads have
134 | // completed.
135 | for (int i=0; i < threadCount; i++) {
136 | try {
137 | t[i].join();
138 | } catch (InterruptedException e) {
139 | }
140 | }
141 | }
142 |
143 | static class PerThread implements Runnable {
144 |
145 | PerThread(Scriptable sharedScope, String source, String x) {
146 | this.sharedScope = sharedScope;
147 | this.source = source;
148 | this.x = x;
149 | }
150 |
151 | public void run() {
152 | // We need a new Context for this thread.
153 | Context cx = Context.enter();
154 | try {
155 | // We can share the scope.
156 | Scriptable threadScope = cx.newObject(sharedScope);
157 | threadScope.setPrototype(sharedScope);
158 |
159 | // We want "threadScope" to be a new top-level
160 | // scope, so set its parent scope to null. This
161 | // means that any variables created by assignments
162 | // will be properties of "threadScope".
163 | threadScope.setParentScope(null);
164 |
165 | // Create a JavaScript property of the thread scope named
166 | // 'x' and save a value for it.
167 | threadScope.put("x", threadScope, x);
168 | cx.evaluateString(threadScope, source, "threadScript", 1, null);
169 | } finally {
170 | Context.exit();
171 | }
172 | }
173 | private Scriptable sharedScope;
174 | private String source;
175 | private String x;
176 | }
177 |
178 | }
179 |
--------------------------------------------------------------------------------
/src/test/java/com/lihuanghe/SqlTemplateParserTest.java:
--------------------------------------------------------------------------------
1 | package com.lihuanghe;
2 |
3 | import java.io.IOException;
4 | import java.util.ArrayList;
5 | import java.util.Arrays;
6 | import java.util.Date;
7 | import java.util.HashMap;
8 | import java.util.List;
9 | import java.util.Map;
10 |
11 | import org.apache.commons.lang.time.DateFormatUtils;
12 | import org.junit.Assert;
13 | import org.junit.Test;
14 |
15 | import com.lihuanghe.SqlTemplateParser.SqlParseException;
16 |
17 |
18 | public class SqlTemplateParserTest {
19 |
20 | @Test
21 | public void testsql() throws SqlParseException, IOException
22 | {
23 | String sql = "select * from shops_#{month} \nwhere 1=1 @[Ids: \nand id in ('Nouse',@{Ids}) ] \nand status = 1";
24 | Map map = new HashMap();
25 | map.put("Ids", new String[]{"2","3","4"});
26 | map.put("month", "201503");
27 | List param = new ArrayList();
28 | String pstsSql = SqlTemplateParser.parseString(sql, map, param);
29 | String expect = "select * from shops_201503 \nwhere 1=1 \nand id in ('Nouse',?,?,?) \nand status = 1";
30 | System.out.println(Arrays.toString(param.toArray()));
31 | System.out.println(expect);
32 |
33 | Assert.assertEquals(expect, pstsSql);
34 | Assert.assertEquals(3, param.size());
35 | Assert.assertEquals(Arrays.toString(new String[]{"2" ,"3" ,"4" }), Arrays.toString(param.toArray()));
36 |
37 | }
38 | @Test
39 | public void testall() throws SqlParseException, IOException
40 | {
41 | String sql = "begin #{ m1.p3 } ${p1},@{p2},p#{p1},$[p1: midle1:${p1}],\n $[p5: midle2:${p1}],@[p2:midle3:@{p2}],@[p5:midle4:@{p2}],\\${,\\a,\\\\ end$";
42 | Map map = new HashMap();
43 | map.put("p1", "1");
44 | map.put("p3", "sdf");
45 | map.put("p2", new String[]{"2","3","4"});
46 | map.put("m1", new HashMap(map));
47 | List param = new ArrayList();
48 | String pstsSql = SqlTemplateParser.parseString(sql, map, param);
49 | String expect = "begin sdf ?,?,?,?,p1, midle1:?,\n ,midle3:?,?,?,,${,\\a,\\ end$";
50 | Assert.assertEquals(expect, pstsSql);
51 | Assert.assertEquals(8, param.size());
52 | Assert.assertEquals(Arrays.toString(new String[]{"1" ,"2" ,"3" ,"4" ,"1" ,"2" ,"3" ,"4" }), Arrays.toString(param.toArray()));
53 | }
54 |
55 | //末尾的转义异常
56 | @Test
57 | public void testlost4()
58 | {
59 | String sql = "begin end\\";
60 | Map map = new HashMap();
61 | List param = new ArrayList();
62 | try {
63 | String pstsSql = SqlTemplateParser.parseString(sql, map, param);
64 | Assert.assertTrue(false);
65 | } catch (SqlParseException e) {
66 | Assert.assertTrue(true);
67 | e.printStackTrace();
68 | } catch (IOException e) {
69 | Assert.assertTrue(false);
70 | e.printStackTrace();
71 | }
72 | }
73 |
74 | //末尾缺少符号
75 | @Test
76 | public void testlost5()
77 | {
78 | String sql = "begin $[lost5: asff end";
79 | Map map = new HashMap();
80 | List param = new ArrayList();
81 | try {
82 | String pstsSql = SqlTemplateParser.parseString(sql, map, param);
83 | Assert.assertTrue(false);
84 | } catch (SqlParseException e) {
85 | Assert.assertTrue(true);
86 | e.printStackTrace();
87 | } catch (IOException e) {
88 | Assert.assertTrue(false);
89 | e.printStackTrace();
90 | }
91 | }
92 | //参数缺少大括号
93 | @Test
94 | public void testlost1() throws SqlParseException, IOException
95 | {
96 | String sql = "begin ${p1,@{p2},p#{p1},$[p1: midle1:${p1}], $[p5: midle2:${p1}],@[p2:midle3:@{p2}],@[p5:midle4:@{p2}],\\${,\\a,\\\\ $abc #XY end";
97 | Map map = new HashMap();
98 | map.put("p1", "1");
99 | map.put("p2", new String[]{"2","3","4"});
100 | List param = new ArrayList();
101 | String pstsSql = SqlTemplateParser.parseString(sql, map, param);
102 | String expect = "begin ,p1, midle1:?, ,midle3:?,?,?,,${,\\a,\\ $abc #XY end";
103 | Assert.assertEquals(expect, pstsSql);
104 | Assert.assertEquals(4, param.size());
105 | Assert.assertEquals(Arrays.toString(new String[]{"1" ,"2" ,"3" ,"4" }),Arrays.toString( param.toArray()));
106 | }
107 |
108 | //参数缺少大括号
109 | @Test
110 | public void testlost2() throws IOException
111 | {
112 | String sql = "begin ${p1},@{p2},p#{p1},$[p1: midle1:${p1}], $[p5: midle2:${p1}],@[p5:midle3:@{p2}],@[p2:midle4:@{p2],\\${,\\a,\\\\ end";
113 | Map map = new HashMap();
114 | map.put("p1", "1");
115 | map.put("p2", new String[]{"2","3","4"});
116 | List param = new ArrayList();
117 | String pstsSql=null;
118 | try {
119 | pstsSql = SqlTemplateParser.parseString(sql, map, param);
120 | Assert.assertTrue(false);
121 | } catch (SqlParseException e) {
122 | e.printStackTrace();
123 | Assert.assertTrue(true);
124 | }
125 | Assert.assertEquals((String)null, pstsSql);
126 | }
127 |
128 | //参数名为空
129 | @Test
130 | public void testparamNameisNull() throws IOException
131 | {
132 | String sql = "begin ${#{p1}} ${#{p2}} end";
133 | Map map = new HashMap();
134 | map.put("p1", "1");
135 | map.put("p2", "");
136 | List param = new ArrayList();
137 | String pstsSql=null;
138 | try {
139 | pstsSql = SqlTemplateParser.parseString(sql, map, param);
140 | System.out.println(pstsSql);
141 | Assert.assertTrue(false);
142 | } catch (SqlParseException e) {
143 | e.printStackTrace();
144 | Assert.assertTrue(true);
145 | }
146 | Assert.assertEquals((String)null, pstsSql);
147 | }
148 |
149 | //参数缺少大括号
150 | @Test
151 | public void testlost3() throws IOException
152 | {
153 | String sql = "begin ${p1},@{p2},p#{p1},$[p1: midle1:${p1}], $[p5: midle2:${p1}],@[p5:midle3:@{p2}],@[p2:midle4:@{p2},\\${,\\a,\\\\ end";
154 | Map map = new HashMap();
155 | map.put("p1", "1");
156 | map.put("p2", new String[]{"2","3","4"});
157 | List param = new ArrayList();
158 | String pstsSql=null;
159 | try {
160 | pstsSql = SqlTemplateParser.parseString(sql, map, param);
161 | Assert.assertTrue(false);
162 | } catch (SqlParseException e) {
163 | e.printStackTrace();
164 | Assert.assertTrue(true);
165 | }
166 | Assert.assertEquals((String)null, pstsSql);
167 | }
168 | //参数缺少大括号
169 | @Test
170 | public void testparamNameContain() throws IOException
171 | {
172 | String sql = "begin ${p1\n} end";
173 | Map map = new HashMap();
174 | map.put("p1", "1");
175 | map.put("p2", new String[]{"2","3","4"});
176 | List param = new ArrayList();
177 | String pstsSql=null;
178 | try {
179 | pstsSql = SqlTemplateParser.parseString(sql, map, param);
180 | Assert.assertTrue(false);
181 | } catch (SqlParseException e) {
182 | e.printStackTrace();
183 | Assert.assertTrue(true);
184 | }
185 | Assert.assertEquals((String)null, pstsSql);
186 | }
187 | @Test
188 | public void testconcat() throws SqlParseException, IOException
189 | {
190 | String sql = "begin ${p4} ${ p1 },@{\t p2 \t },${p#{p1}\t},#{p#{p1}},$[p1: midle1:${p1},#{p#{p1}} ],\n $[p5: midle2:${p1}],@[p2:midle3:@{p2}],@[p5:midle4:@{p2}],\\${,\\a,\\\\ end#";
191 | Map map = new HashMap();
192 | map.put("p1", "3");
193 | map.put("p3", "1");
194 | map.put("p4", "");
195 | map.put("p2", new String[]{"2","3","4"});
196 | List param = new ArrayList();
197 | String pstsSql = SqlTemplateParser.parseString(sql, map, param);
198 | String expect = "begin ? ?,?,?,?,?,1, midle1:?,1 ,\n ,midle3:?,?,?,,${,\\a,\\ end#";
199 | Assert.assertEquals(expect, pstsSql);
200 | Assert.assertEquals(10, param.size());
201 | Assert.assertEquals(Arrays.toString(new String[]{"","3" ,"2" ,"3" ,"4" ,"1","3" ,"2" ,"3" ,"4" }), Arrays.toString(param.toArray()));
202 | }
203 | @Test
204 | public void testCNcode() throws SqlParseException, IOException
205 | {
206 | String sql = "开始 ${参数1},@{参数2},参数#{参数1},$[参数1: 中间1:${参数1}], $[参数5: 中间2:${参数1}],@[参数2:中间3:@{参数2}],@[参数5:midle4:@{参数2}],\\${,\\a,\\\\ 结束";
207 | Map map = new HashMap();
208 | map.put("参数1", "1");
209 | map.put("参数2", new String[]{"2","3","4"});
210 | List param = new ArrayList();
211 | String pstsSql = SqlTemplateParser.parseString(sql, map, param);
212 | String expect = "开始 ?,?,?,?,参数1, 中间1:?, ,中间3:?,?,?,,${,\\a,\\ 结束";
213 | Assert.assertEquals(expect, pstsSql);
214 | Assert.assertEquals(8, param.size());
215 | Assert.assertEquals(Arrays.toString(new String[]{"1" ,"2" ,"3" ,"4" ,"1" ,"2" ,"3" ,"4" }), Arrays.toString(param.toArray()));
216 | }
217 |
218 | //测试js执行
219 | @Test
220 | public void testJscode() throws SqlParseException, IOException
221 | {
222 | Date d = new Date();
223 | String sql = "begin ${b3|[]} @[b3|[]: abc ] ${abc|if(abc) {\nabc?DateFormat.format(abc,'yyyy-MM-dd'):'error null';\n\\}} ${abcd|abcd&&DateFormat.format(abcd,'yyyy-MM-dd')} (@{b3|['hello'].concat(b3.join('*'))}) #{abc|DateFormat.format(abc,'yyyy-MM-dd')} #{beginDate|DateFormat.format(DateUtils.addMonths(DateUtils.parseDate(beginDate, ['yyyy-MM-dd']),-1),'yyyyMM')} (${b2|b2.addAll(['5','6','7']);b2}) end ";
224 | Map map = new HashMap();
225 | map.put("beginDate","2015-03-23");
226 | map.put("abc", d);
227 | map.put("b3", new String[]{"2","3","4"});
228 | List tmp = new ArrayList();
229 | tmp.addAll(Arrays.asList(new String[]{"2","3","4"}));
230 | map.put("b2", tmp);
231 |
232 | List param = new ArrayList();
233 | String pstsSql = SqlTemplateParser.parseString(sql, map, param,"utf-8");
234 | System.out.println(pstsSql);
235 | System.out.println(Arrays.toString(param.toArray()));
236 |
237 | String str = DateFormatUtils.format(d,"yyyy-MM-dd");
238 | String expect = "begin ? (?,?) "+str+" 201502 (?,?,?,?,?,?) end ";
239 | Assert.assertEquals(expect, pstsSql);
240 | Assert.assertEquals(9, param.size());
241 | Assert.assertEquals(Arrays.toString(new String[]{str,"hello","2*3*4" ,"2","3","4","5","6","7"}), Arrays.toString(param.toArray()));
242 | }
243 |
244 | @Test
245 | public void testinnerOptionalParameter()throws SqlParseException, IOException
246 | {
247 | String sql = "begin $[p1: abc $[p3: def(${p2})]] $[p4: abc $[p3: def(${p2})]] end";
248 | Map map = new HashMap();
249 | map.put("p1", "3");
250 | map.put("p3", "1");
251 | map.put("p4", "");
252 | map.put("p2", new String[]{"2","3","4"});
253 | List param = new ArrayList();
254 | String pstsSql = SqlTemplateParser.parseString(sql, map, param);
255 | String expect = "begin abc def(?,?,?) end";
256 | Assert.assertEquals(expect, pstsSql);
257 | Assert.assertEquals(3, param.size());
258 | Assert.assertEquals(Arrays.toString(new String[]{"2" ,"3" ,"4"}), Arrays.toString(param.toArray()));
259 |
260 | }
261 |
262 | @Test
263 | public void testThreeMetaParameter()throws SqlParseException, IOException
264 | {
265 | String sql = "begin $[ p1 ? abc : def] $[ p2 ? abc : def] end";
266 | Map map = new HashMap();
267 | map.put("p1", "3");
268 | List param = new ArrayList();
269 | String pstsSql = SqlTemplateParser.parseString(sql, map, param);
270 | String expect = "begin abc def end";
271 | Assert.assertEquals(expect, pstsSql);
272 | }
273 |
274 | //测试js执行性能
275 | @Test
276 | public void testJsperf() throws SqlParseException, IOException
277 | {
278 | int i = 0;
279 | Date d = new Date();
280 | String sql = "begin ${p1,@{p2},p#{p1},$[p1: midle1:${p1}], $[p5: midle2:${p1}],@[p2:midle3:@{p2}],@[p5:midle4:@{p2}],\\${,\\a,\\\\ $abc #XY end";
281 | Map map = new HashMap();
282 | map.put("abc", d);
283 | List param = new ArrayList();
284 | int cnt = 100000;
285 | long st = System.currentTimeMillis();
286 | for(;i< cnt;i++){
287 | SqlTemplateParser.parseString(sql, map, param);
288 | };
289 | long ed = System.currentTimeMillis();
290 | System.out.println("totle:"+(double)(ed - st)+"ms ; per "+(double)(ed - st)/cnt +"ms");
291 | }
292 | }
293 |
--------------------------------------------------------------------------------