iBatis 3中新增了SelectBuilder/SqlBuilder两个工具类,用于利用类函数的方式动态生成SQL 语句,减少拼接SQL语句时候大量的显式字符串操作,减少字符串操作可能出现的错误,提高程序的易读性。
在iBatis 3的用户指南中,列举出了若干个实例,如下是个最简单的例子,生成一个静态的SQL语句:
- import static org.mybatis.jdbc.SelectBuilder.*;
- public String selectBlogsSql() {
- BEGIN(); // Clears ThreadLocal variable
- SELECT("*");
- FROM("BLOG");
- return SQL();
- }
下面几个例子生成动态的SQL语句
- private String selectPersonLike(Person p){
- BEGIN(); // Clears ThreadLocal variable
- SELECT("P.ID, P.USERNAME, P.PASSWORD, P.FIRST_NAME, P.LAST_NAME");
- FROM("PERSON P");
- if (p.id != null) {
- WHERE("P.ID like #{id}");
- } if (
- p.firstName != null) {
- WHERE("P.FIRST_NAME like #{firstName}");
- } if (
- p.lastName != null) {
- WHERE("P.LAST_NAME like #{lastName}");
- } ORDER_BY("P.LAST_NAME");
- return SQL();
- }
- public String deletePersonSql() {
- BEGIN(); // Clears ThreadLocal variable
- DELETE_FROM("PERSON");
- WHERE("ID = ${id}");
- return SQL();
- }
- public String insertPersonSql() {
- BEGIN(); // Clears ThreadLocal variable
- INSERT_INTO("PERSON");
- VALUES("ID, FIRST_NAME", "${id}, ${firstName}");
- VALUES("LAST_NAME", "${lastName}");
- return SQL();
- }
- public String updatePersonSql() {
- BEGIN(); // Clears ThreadLocal variable
- UPDATE("PERSON");
- SET("FIRST_NAME = ${firstName}");
- WHERE("ID = ${id}");
- return SQL();
- }
通过上面的实例,我们已经可以生成SQL语句了,但是如何使用这些SQL,用户指南中并没有提及。当然,对于简单的例子,如例1中生成的静态 SQL,我们完全可以以纯粹的JDBC的方式来执行。但例子2中几个方法,则必须首先将里面的变量替换掉,才能执行,因此,利用iBatis中自带的类进 行变量替换则应该是最好的办法(当然我们可以用Velocity等模板工具来做这件事情,但在iBatis环境下,不是最佳的方案)。
iBatis3的一个缺陷就是相关的开发文档太少,要想做这件事情就必须啃源码了。
首先通过观察,找到了SelectBuilder/SqlBuilder同一个package下的SqlRunner类,该类封装了针对数据库操作 的select,insert, update和delete的等方法,很显然这是一个SQL执行类,select默认的返回类型为Map。
下一步,需要寻找能替换关键字变量的相关类了,得感谢ibatis 3.0 Dynamic Sql 设计解 ...这篇文章,对Dynamic Sql相关类和类关系有了了解,才找到最终的解决方案,如下:
- private Connection conn=null;
- private SqlRunner sqlRunner;
- {
- try {
- conn = sessionFactory.getConfiguration().getEnvironment().getDataSource().getConnection();
- sqlRunner=new SqlRunner(conn);
- } catch (SQLException e) {
- logger.error(e);
- }
- }
- public void deletPerson(Map keysMap) {
- BEGIN(); // Clears ThreadLocal variable
- DELETE_FROM("PERSON");
- WHERE("ID = #{id}");
- TextSqlNode node =new TextSqlNode(SQL());
- DynamicSqlSource s=new DynamicSqlSource(sessionFactory.getConfiguration(),
- node);
- //此外对于静态SQL,ibatis还提供了StaticSqlSource
- BoundSql sql = s.getBoundSql(keysMap);
- logger.debug(sql.getSql());
- try {
- sqlRunner.delete(sql.getSql(),keysMap.get("id"));
- conn.commit();
- } catch (Exception e) {
- conn.rollback();
- throw e;
- }
- }
使用起来很简单:
- try {
- Map params= new HashMap();
- params.put("id","1");
- deletePerson();
- } catch (Exception e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
如上,使用map是为了支持任意多个参数,同时利用SelectBuilder/SqlBuilder强大的SQL构建能力,我们完全可以封装一些 很通用的数据库操作功能,比如通用删除功能,只需将上面的方法进行修改,将表名和包含主键变量的Map传入就可以实现了,而不需要再去XML文件写 SQL。