日期:2014-05-16 浏览次数:20723 次
??? 用hibernate用得多了,忽然怀念起自己直接写sql 的轻巧类库了。
??? 开源的类库中,需要写sql常用的有spring jdbc?,apache的dbutil?, MyBatis。看过MyBatis文档,写过demo, 相对于hibernate这个强大的ORM工具,MyBatis可控性更好,然而今天它不主角,今天的主角是spring jdbc.
???
??? spring jdbc 当我一接触到的时候,从此深深爱上了这个小巧的家伙:简单而优雅的API,配上spring本身的声名式事务!这就是一把小巧的神器!????
??? 然而随着我深入的了解,让我不爽的是SQL语句写在JAVA代码中,想要动态SQL自己拼字符串吧!
??? 但是这又有什么的?我把SQL语句放在外部文件,然后把它读出来就行了。
?? 有这想法第一步想到的是:
?? 利用Spring注入功能,把SQL注入到bean中去,但是想想又不合适,不喜欢用xml方式配置spring bean ,如果每个?? bean都注入几条SQL,不是所有要用SQL的bean都要写在xml文件吗?
?? 这个办法不是一个优雅的解决办法,那创建一个类,利用spring注入功能,将相关的值注入到map属性中,尝试了一下,所有的sql都丢到一个文件多不优雅!还是自己动手来读吧,dom4j读xml很简单,上代码:
?
?
public class SQLBuilder { private static Logger logger = LoggerFactory.getLogger(SQLBuilder.class); private Map<String, String> sqlContainer = null; private String sqlFilePath = "systemSql.xml"; public SQLBuilder() { initSqlContainer(); } public SQLBuilder(String sqlFilePath) { this.sqlFilePath = sqlFilePath; initSqlContainer(); } public String getSql(String key) { String sql = sqlContainer.get(key); if (sql == null || "".equals(sql)) logger.warn("不存在该SQL语句"); if (logger.isDebugEnabled()) { logger.debug("SQL:" + sql); } return sql; } public String getDynamicalSql(String key, Map<String, ?> param) { String sql = sqlContainer.get(key); return VelocityUtils.render(sql, param); } @SuppressWarnings("unchecked") private void initSqlContainer() { sqlContainer = new ConcurrentHashMap<String, String>(); if (sqlFilePath == null || "".equals(sqlFilePath)) { throw new NullPointerException("sql语句文件不能为空!"); } String[] files = sqlFilePath.split(";"); for (String file : files) { readSQLFromFile(file); } } private void readSQLFromFile(String fileName) { InputStream ips = Thread.currentThread().getContextClassLoader() .getResourceAsStream(fileName); Document document = null; SAXReader saxReader = new SAXReader(); try { document = saxReader.read(ips); } catch (DocumentException e) { logger.error("读取系统中用到的SQL 语句XML出错"); throw new RuntimeException("读取sql语句XML文件出错:" + e.getMessage()); } Element root = document.getRootElement(); List<Element> sqlElements = root.selectNodes("//sqlElement"); String key; for (Element sql : sqlElements) { key=sql.attribute("key").getValue(); if(sqlContainer.containsKey(key)){ logger.warn("key值:"+key+"重复"); } sqlContainer.put(key, sql.getText()); } if (ips != null) { try { ips.close(); } catch (IOException e) { logger.error("关闭输入流出错:" + e.getMessage()); } } } public void setSqlFilePath(String sqlFilePath) { this.sqlFilePath = sqlFilePath; } @Override protected void finalize() throws Throwable { super.finalize(); if (sqlContainer != null) { sqlContainer.clear(); sqlContainer = null; } } }
?
??? 模板技术用过freemarker ,velocity 我喜欢velocity多点,直接拿springside 里面工具类生成动态SQL
?
??
/** * 使用Velocity生成内容的工具类. * * @author calvin */ public class VelocityUtils { static { try { Velocity.init(); } catch (Exception e) { throw new RuntimeException("Exception occurs while initialize the velociy.", e); } } /** * 渲染内容. * * @param template 模板内容. * @param model 变量Map. */ public static String render(String template, Map<String, ?> model) { try { VelocityContext velocityContext = new VelocityContext(model); StringWriter result = new StringWriter(); Velocity.evaluate(velocityContext, result, "", template); return result.toString(); } catch (Exception e) { throw new RuntimeException("Parse template failed.", e); } } }
?
<?xml version="1.0" encoding="UTF-8"?> <sqls> <sqlElement key="queryUser"> <![CDATA[ s