程序员人生 网站导航

深入浅出Mybatis-sql自动生成

栏目:框架设计时间:2017-03-04 08:59:00

本文提供了1种自动生成sql语句的方法,它针对的对象是有主键或唯1索引的单表,提供的操作有增、删、改、查4种。理解本文和本文的提供的代码需要有java注解的知识,由于本文是基于注解生成sql的。本文适配的mybatis版本是3.2.2

准备

为何在StatementHandler拦截

深入浅出MyBatis-Sqlsession章节介绍了1次sqlsession的完全履行进程,从中可以知道sql的解析是在StatementHandler里完成的,所以为了自动生成sql需要拦截StatementHandler

MetaObject简介

在我的实现里大量使用了MetaObject这个对象,因此有必要先介绍下它。MetaObjectMybatis提供的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-插件原理

 

有了上面这些基础知识的准备后,就能够我们的主题了。

拦截器签名

[java] view plain copy
  1. @Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class})})  
  2. public class AutoMapperInterceptor implements Interceptor {  
  3. ...  
  4. }  

从签名里可以看出,要拦截的目标类型是StatementHandler(注意:type只能配置成接口类型),拦截的方法是名称为prepare参数为Connection类型的方法。

intercept的实现

[java] view plain copy
  1. @Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class})})  
  2. public class AutoMapperInterceptor implements Interceptor {  
  3.     private static final Log logger = LogFactory.getLog(AutoMapperInterceptor.class);  
  4.     private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();  
  5.     private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();  
  6.   
  7.     @Override  
  8.     public Object intercept(Invocation invocation) throws Throwable {  
  9.         StatementHandler statementHandler = (StatementHandler) invocation.getTarget();  
  10.         MetaObject metaStatementHandler = MetaObject.forObject(statementHandler, DEFAULT_OBJECT_FACTORY,  
  11.                 DEFAULT_OBJECT_WRAPPER_FACTORY);  
  12.         // 分离代理对象链  
  13.         while (metaStatementHandler.hasGetter("h")) {  
  14.             Object object = metaStatementHandler.getValue("h");  
  15.             metaStatementHandler = MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY);  
  16.         }  
  17.         // 分离最后1个代理对象的目标类  
  18.         while (metaStatementHandler.hasGetter("target")) {  
  19.             Object object = metaStatementHandler.getValue("target");  
  20.             metaStatementHandler = MetaObject.forObject(object, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY);  
  21.         }  
  22.         String originalSql = (String) metaStatementHandler.getValue("delegate.boundSql.sql");  
  23.         Configuration configuration = (Configuration) metaStatementHandler.getValue("delegate.configuration");  
  24.         Object parameterObject = metaStatementHandler.getValue("delegate.boundSql.parameterObject");  
  25.         if (null == originalSql || "".equals(originalSql)) {  
  26.             String newSql = "";  
  27.             MappedStatement mappedStatement = (MappedStatement) metaStatementHandler  
  28.                     .getValue("delegate.mappedStatement");  
  29.             // 根据ID生成相应类型的sql语句(id需剔除namespace信息)  
  30.             String id = mappedStatement.getId();  
  31.             id = id.substring(id.lastIndexOf(".") + 1);  
  32.             if ("insert".equals(id)) {  
  33.                 newSql = SqlBuilder.buildInsertSql(parameterObject);  
  34.             } else if ("update".equals(id)) {  
  35.                 newSql = SqlBuilder.buildUpdateSql(parameterObject);  
  36.             } else if ("delete".equals(id)) {  
  37.                 newSql = SqlBuilder.buildDeleteSql(parameterObject);  
  38.             } else if ("select".equals(id)) {  
  39.                 newSql = SqlBuilder.buildSelectSql(parameterObject);  
  40.             }  
  41.             logger.debug("Auto generated sql:" + newSql);  
  42.             //  
  43.             SqlSource sqlSource = buildSqlSource(configuration, newSql, parameterObject.getClass());  
  44. &n
------分隔线----------------------------
------分隔线----------------------------

最新技术推荐