本文提供了1种自动生成sql语句的方法,它针对的对象是有主键或唯1索引的单表,提供的操作有增、删、改、查4种。理解本文和本文的提供的代码需要有java注解的知识,由于本文是基于注解生成sql的。本文适配的mybatis版本是3.2.2。
准备
为何在StatementHandler拦截
在深入浅出MyBatis-Sqlsession章节介绍了1次sqlsession的完全履行进程,从中可以知道sql的解析是在StatementHandler里完成的,所以为了自动生成sql需要拦截StatementHandler。
MetaObject简介
在我的实现里大量使用了MetaObject这个对象,因此有必要先介绍下它。MetaObject是Mybatis提供的1个的工具类,通过它包装1个对象后可以获得或设置该对象的本来不可访问的属性(比如那些私有属性)。它有个3个重要方法常常用到:
1) MetaObject
forObject(Object object,ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory)
2) Object
getValue(String name)
3) void
setValue(String name, Object value)
方法1)用于包装对象;方法2)用于获得属性的值(支持OGNL的方法);方法3)用于设置属性的值(支持OGNL的方法);
插件的原理
参见深入浅出Mybatis-插件原理。
有了上面这些基础知识的准备后,就能够我们的主题了。
拦截器签名
-
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class})})
-
public class AutoMapperInterceptor implements Interceptor {
-
...
-
}
从签名里可以看出,要拦截的目标类型是StatementHandler(注意:type只能配置成接口类型),拦截的方法是名称为prepare参数为Connection类型的方法。
intercept的实现
-
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class})})
-
public class AutoMapperInterceptor implements Interceptor {
-
private static final Log logger = LogFactory.getLog(AutoMapperInterceptor.class);
-
private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
-
private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
-
-
@Override
-
public Object intercept(Invocation invocation) throws Throwable {
-
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
-
MetaObject metaStatementHandler = MetaObject.forObject(statementHandler, DEFAULT_OBJECT_FACTORY,
-
DEFAULT_OBJECT_WRAPPER_FACTORY);
-
-
while (metaStatementHandler.hasGetter("h")) {
-
Object object = metaStatementHandler.getValue("h");
-
metaStatementHandler = MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY);
-
}
-
-
while (metaStatementHandler.hasGetter("target")) {
-
Object object = metaStatementHandler.getValue("target");
-
metaStatementHandler = MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY);
-
}
-
String originalSql = (String) metaStatementHandler.getValue("delegate.boundSql.sql");
-
Configuration configuration = (Configuration) metaStatementHandler.getValue("delegate.configuration");
-
Object parameterObject = metaStatementHandler.getValue("delegate.boundSql.parameterObject");
-
if (null == originalSql || "".equals(originalSql)) {
-
String newSql = "";
-
MappedStatement mappedStatement = (MappedStatement) metaStatementHandler
-
.getValue("delegate.mappedStatement");
-
-
String id = mappedStatement.getId();
-
id = id.substring(id.lastIndexOf(".") + 1);
-
if ("insert".equals(id)) {
-
newSql = SqlBuilder.buildInsertSql(parameterObject);
-
} else if ("update".equals(id)) {
-
newSql = SqlBuilder.buildUpdateSql(parameterObject);
-
} else if ("delete".equals(id)) {
-
newSql = SqlBuilder.buildDeleteSql(parameterObject);
-
} else if ("select".equals(id)) {
-
newSql = SqlBuilder.buildSelectSql(parameterObject);
-
}
-
logger.debug("Auto generated sql:" + newSql);
-
-
SqlSource sqlSource = buildSqlSource(configuration, newSql, parameterObject.getClass());
-
&n