
3.1 使用SQL类生成语句
使用JDBC API开发过项目的读者应该知道,当我们需要使用Statement对象执行SQL时,SQL语句会嵌入Java代码中。SQL语句比较复杂时,我们可能会在代码中对SQL语句进行拼接,查询条件不固定时,还需要根据不同条件拼接不同的SQL语句,拼接语句时不要忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。这个过程对于开发人员来说简直就是一场噩梦,而且代码可维护性级低,例如:

为了解决这个问题,MyBatis中提供了一个SQL工具类。使用这个工具类,我们可以很方便地在Java代码中动态构建SQL语句。上面的语句如果使用SQL工具类来构建,就会简单很多。下面是使用MyBatis中的SQL工具类动态构建SQL语句的案例:

如上面的代码所示,创建了一个匿名的SQL类的子类,在匿名子类的初始化代码块中,调用SELECT()、FROM()等方法构建SQL语句,这种方式能够很好地避免字符串拼接过程中缺少空格或者偶然间重复出现的AND关键字导致的SQL语句不正确。
除了SELECT语句外,SQL工具类也可以用作构建UPDATE、INSERT等语句。下面是SQL工具类的一些使用案例:

使用SQL工具类的另一个好处是可以很方便地在Java代码中根据条件动态地拼接SQL语句,例如:

关于SQL工具类的完整使用案例可参考随书源码mybatis-chapter03项目的com.blog4java.mybatis.SQLExample案例。
SQL工具类中提供的所有方法及作用可参考表3-1中的内容。
表3-1 SQL工具类的方法及作用

(续表)

在学习完SQL工具类的使用后,接下来我们简单地了解一下SQL工具类的实现源码。SQL继承至AbstractSQL类,只重写了该类的getSelf()方法,代码如下:

所有的功能由AbstractSQL类完成,AbstractSQL类中维护了一个SQLStatement内部类的实例和一系列前面提到过的构造SQL语句的方法,例如SELECT()、UPDATE()等方法。AbstractSQL类的部分代码如下:

SQLStatement内部类用于描述一个SQL语句,该类中通过StatementType确定SQL语句的类型。SQLStatement类中还维护了一系列的ArrayList属性,当调用SELECT()、UPDATE()等方法时,这些方法的参数内容会记录在这些ArrayList对象中,SQLStatement类中的属性如下:

AbstrastSQL类重写了toString()方法,该方法中会调用SQLStatement对象的sql()方法生成SQL字符串,代码如下:

SQLStatement对象的sql()方法实现代码如下:

如上面的代码所示,该方法中会判断SQL语句的类型,以UPDATE语句为例,会调用SQLStatement对象的updateSql()方法生成UPDATE语句。updateSql()方法代码如下:

如上面的代码所示,updateSql()方法中,最终会调用sqlCalause()方法完成SQL语句的拼接。sqlCalause()方法实现代码如下:

这里对SQL工具类的实现做了简单的介绍,完整代码可参考AbstractSQL类的源码。