今天来记录一下对Mybatis的扩展,版本是3.3.0,是和Spring集成使用,mybatis-spring集成包的版本是1.2.3,如果使用maven,如下配置:

<properties>元素下添加

 <mybatis.version>3.3.0</mybatis.version>
<mybatis.spring.version>1.2.3</mybatis.spring.version>

<dependencies>元素下添加

 <dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>${mybatis.version}</version>
</dependency>
<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis-spring</artifactId>
  <version>${mybatis.spring.version}</version>
</dependency>

  mybatis-spring的集成配置如下:

 <bean id="DialectDatabaseIdProvider" class="com.forms.beneform4j.core.dao.mybatis.provider.DialectDatabaseIdProvider"/>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer" p:sqlSessionFactoryBeanName="sqlSessionFactory" p:basePackage="com.forms"
p:annotationClass="org.springframework.stereotype.Repository"/>
<bean id="sqlSessionFactory" p:dataSource-ref="dataSource" class="com.forms.beneform4j.core.dao.mybatis.SqlSessionFactoryBeanForSpring"
p:configLocation="classpath:mybatis/mybatis-config.xml" p:databaseIdProvider-ref="DialectDatabaseIdProvider">
<property name="mapperLocations">
<array>
<value>classpath*:sql-mapper/ds1/*.xml</value>
<value>classpath*:com/forms/beneform4j/**/*.ds1.xml</value>
</array>
</property>
</bean>

这里的p:databaseIdProvider-ref="DialectDatabaseIdProvider"算是我们的第一个扩展:

扩展1:添加自定义的数据库ID提供者

  添加这个扩展的目的,是为了能够根据不同的数据库写不同的sql-mapper配置,比如如下的配置,就可兼容不同数据库:

 <choose>
<when test="_databaseId == 'oracle'">
</when>
<when test="_databaseId == 'db2'">
</when>
<when test="_databaseId == 'mysql'">
</when>
<when test="_databaseId == 'oracle'">
</when>
<when test="_databaseId == 'ase'">
</when>
<when test="_databaseId == 'iq'">
</when>
<when test="_databaseId == 'h2'">
</when>
</choose>

那这里的oracle、db2字符串是怎么确定的呢?这就是名称为DialectDatabaseIdProvider的bean所做的事情了,基本上和Mybatis原生提供的VendorDatabaseIdProvider类似,根据数据源对象DataSource获取DatabaseMetaData,继而调用getDatabaseProductName获取产品名称,然后根据配置好的关键字确定数据库类型。可能读者会觉得这个扩展没多大必要,直接使用VendorDatabaseIdProvider就好了,的确如此,除了自己写的类有更大的控制权之外,没有增加多少功能。但DialectDatabaseIdProvider的实现是从数据库方言角度来做的,从这里可以引出第二个扩展:

扩展2:实现物理分页

Mybatis的分页查询是逻辑分页,这对于大多数应用是不适合的,于是需要实现物理分页。

主要的实现步骤:

1、添加数据库方言接口

 public interface IDialect {

     /**
* 数据库类型
*/
enum DBType {
Oracle, DB2, H2, MySql, ASE, IQ
} /**
* 获取数据库类型
* @return 数据库类型枚举常量
*/
public DBType getType(); /**
* 获取可能的数据库驱动类名称
* @return 驱动类名数组
*/
public String[] getDriverClassNames(); /**
* 生成计算总记录数的SQL
* @param sql 原始SQL
* @return 计算总记录数的SQL
*/
public String getTotalSql(String sql); /**
* 获取查询指定范围记录的SQL
* @param sql 原始SQL
* @param offset 返回的开始记录索引
* @param limit 查询的数据大小
* @return 查询第(offset, offset + limit]条记录的SQL,索引从1开始
*/
public String getScopeSql(String sql, long offset, int limit);
}

不同的数据库具体怎么实现就不贴了;

2、添加mybatis分页和物理分页的适配类

 public class PageAdapter extends RowBounds{

 }

在调用Mybatis的分页查询时,使用该适配类参数,例如:

 public <E> List<E> selectList(String sqlId, Object parameter, IPage page) {
RowBounds adapter = new PageAdapter(page);
return sqlSession.selectList(sqlId, parameter, adapter);
}

这里IPage封装了分页对象,可以获取当前页数、分页大小等等。

3、编写Mybatis插件,拦截sql执行,如果包含PageAdapter参数,则做分页逻辑处理

(1)获取数据库方言接口的具体实现类,这里可以根据Connection对象识别、也可以使用ThreadLocal对象,还可以在适配类中添加方言对象传进来

(2)如果需要计算总记录条数(分页对象中不包含总记录数),根据数据库方言,获取计算总记录条数的sql,然后执行,并将总计录条数反写会分页对象

(3)根据数据库方言和分页对象,获取需要从数据库查询的当前页数据的sql,然后调用拦截器的执行方法继续之前执行

4、将mybatis插件配置到spring配置文件或mybatis配置文件中,启用该插件即可。

  说到Mybatis插件,实际上并不只是做了分页处理一件事,还可以格式化sql、进行sql拦截处理等等,这里就包括我们的第三个扩展:

扩展3:SQL拦截1——语句拦截

主要的实现步骤:

1、添加SQL字符串拦截接口

 public interface ISqlInterceptor {

     /**
* 执行SQL拦截
* @param jndi 数据源
* @param src 原SQL
* @param context 上下文环境
* @param root 根对象
* @return 拦截后的SQL
*/
public String intercept(IJndi jndi, String src, Map<String, Object> context, Object root);
}

这里的IJndi对象是数据源对象的一个抽象,可以获取相应的数据库方言对象、和数据源对应的特定属性等

 public interface IJndi{

     /**
* 获取数据源名称
* <p>
* 默认为spring配置中的beanId
* </p>
* @return 数据源名称
*/
public String getName(); /**
* 是否默认数据源
* <p>
* 默认情况下,如果spring配置中的beanId等于dataSource(不区分大小写)则设置为默认数据源,如果不存在dataSource,则设置第一个数据源为默认数据源
* </p>
* @return 是否默认数据源
*/
public boolean isDefault(); /**
* 获取数据库方言
* <p>
* 根据数据库产品名称自动判断哪个数据库方言
* </p>
* @return 和数据源对应的数据库方言
*/
public IDialect getDialect(); /**
* 获取数据源
* @return 对应的数据源
*/
public DataSource getDataSource(); /**
* 获取属性
* @return
*/
public Properties getProperties();
}

2、在平台配置中,添加sql拦截的配置,可以配置一系列的拦截

3、在Mybatis插件中,根据Mybatis执行上下文找到IJndi对象、参数对象、拦截前的sql,调用平台配置中的sql拦截,并将返回值反写会mybatis上下文中

  可能有人会问,这种语句拦截有什么作用呢?

  其实我们就是利用这种机制,来实现不同应用系统使用不同的表前缀,比如平台中有一个BF_USER表,A系统建表的时候统一添加A_前缀,B系统建表的时候统一添加前缀B_,那么,在平台中怎么知道访问的具体表呢?我们的做法是,在平台中添加一个平台表前缀的配置,然后实现一个SQL拦截,将符合特别语法{{BF}}的替换为Beneform4jConfig.getBeneform4jTablePrefix() + "BF",这种SQL语句的拦截,有点类似于使用${}语法。

扩展4:SQL拦截2——参数拦截

  如果说SQL语句拦截是使用${}语法,那么参数拦截则是#{}语法了。

主要实现步骤:

1、添加参数拦截接口

 public interface IStatementParameterResolver {

     /**
* 是否可以解析表达式
* @param jndi 数据源对象
* @param expression 表达式
* @return 如果可以解析,返回true,否则返回false
*/
public boolean isSupport(IJndi jndi, String expression); /**
* 执行参数解析
* @param jndi 数据源对象
* @param parameterObject 参数对象
* @param expression 表达式
* @return 解析后的值
*/
public Object resolver(IJndi jndi, Object parameterObject, String expression);
}

这里有两个方法,第一个方法判断当前的拦截器实现类是否支持#{}内部的表达式,如果支持,就调用第二个方法处理参数。这种先判断是否支持,然后在支持的情况下再继续处理的类责任链模式在Spring MVC中用的也相当普通。

2、编写Mybatis原生接口ParameterHandler的实现类,在其中调用参数拦截接口来实现不同参数的解析

3、在Mybatis插件中,替换ParameterHandler接口的实现类。

  在新平台中,利用参数拦截主要实现了一种效果,就是在mybatis的sql-mapper文件中直接执行SpEL表达式或OGNL表达式。例如:

 <select id="selectList">
SELECT * FROM BF_PARAM_ENUM_DEF
<where>
<if test="null != paramCode and '' != paramCode">
and PARAM_CODE = #{@bean.getName(), jdbctType=VARCHAR}
</if>
</where>
</select>

这里的bean是Spring容器管理的bean,getBean就是调用其getBean方法了。

  今天记录到这里,下周继续。

Java EE开发平台随手记2——Mybatis扩展1的更多相关文章

  1. Java EE开发平台随手记4——Mybatis扩展3

    接着昨天的Mybatis扩展——IDaoTemplate接口. 扩展9:批量执行 1.明确什么是批量执行 首先说明一下,这里的批量执行不是利用<foreach>标签生成一长串的sql字符串 ...

  2. Java EE开发平台随手记3——Mybatis扩展2

    忙里偷闲,继续上周的话题,记录Mybatis的扩展. 扩展5:设置默认的返回结果类型 大家知道,在Mybatis的sql-mapper配置文件中,我们需要给<select>元素添加resu ...

  3. Java EE开发平台随手记6——Mybatis扩展4

    这篇博客中来说一下对Mybatis动态代理接口方式的扩展,对于Mybatis动态代理接口不熟悉的朋友,可以参考前一篇博客,或者研读Mybatis源码. 扩展11:动态代理接口扩展 我们知道,真正在My ...

  4. Java EE开发平台随手记5——Mybatis动态代理接口方式的原生用法

    为了说明后续的Mybatis扩展,插播一篇广告,先来简要说明一下Mybatis的一种原生用法,不过先声明:下面说的只是Mybatis的其中一种用法,如需要更深入了解Mybatis,请参考官方文档,或者 ...

  5. Java EE开发平台随手记1

    过完春节以来,一直在负责搭建公司的新Java EE开发平台,所谓新平台,其实并不是什么新技术,不过是将目前业界较为流行的框架整合在一起,做一些简单的封装和扩展,让开发人员更加易用. 和之前负责具体的项 ...

  6. Java EE开发课外事务管理平台

    Java EE开发课外事务管理平台 演示地址:https://ganquanzhong.top/edu 说明文档 一.系统需求 目前课外兴趣培训学校众多,完善,但是针对课外兴趣培训学校教务和人事管理信 ...

  7. Java EE开发环境——MyEclipse2017破解 和 Tomcat服务器配置

    Java EE开发,我们可以搭建如下开发环境: 底层运行环境:jdk 和 jre. Web服务器:Tomcat 后台数据库:SQL Server 可视化集成开发环境:MyEclipse Java EE ...

  8. JEECG 3.7.1 版本发布,企业级JAVA快速开发平台

    JEECG 3.7.1 版本发布,企业级JAVA快速开发平台 ---------------------------------------- Version:  Jeecg_3.7.1项 目:   ...

  9. JEECG 4.0 版本发布,JAVA快速开发平台

    JEECG 4.0 版本发布,系统全面优化升级,更快,更稳定!         导读                               ⊙平台性能优化,系统更稳定,速度闪电般提升      ...

随机推荐

  1. 在Xcode 6 beta里编译Cocos2d-x iOS项目时失败

    转载 在Xcode 6 beta里编译Cocos2d-x iOS项目时可能会失败,提示如下错误: Undefined symbols for architecture i386: "_fwr ...

  2. 使用git svn clone迁移svn仓库

    使用git svn clone迁移svn仓库 clone命令可以指定很多参数,主要用到这些,你也可以使用git svn help查看完整的参数列表. git svn clone https://172 ...

  3. 使用Maven自动部署Tomcat 6和Tomcat 7下Web应用

    使用Maven自动部署Tomcat 6和Tomcat 7下Web应用 开启Tomcat远程管理权限 在tomcat的config目录下的tomcat-users.xml文件, <role rol ...

  4. 编译系统中的 NFA/DFA算法理解

    1.问题概述 NFA 和 DFA浅析---要深入了解正则表达式,必须首先理解有穷自动机. 有穷自动机(Finite Automate)是用来模拟实物系统的数学模型,它包括如下五个部分: 有穷状态集St ...

  5. HDU-4869 Turn the pokers

    原题:  Turn the pokers       思路:假设正面为0,反面为1.牌就像这样 000000....... .考虑到假如可以实现最终反面个数为m, 牌共n张, 则这n张排任取m个为反面 ...

  6. Largest Rectangle in a Histogram(DP)

    Largest Rectangle in a Histogram Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/32768K ...

  7. Win10 设置外网多用户远程桌面连接

    主要原理:利用路由器的虚拟服务器功能,将内网的Ip地址通过端口映射提供给外网,使得外网能够访问到目的主机. 1. 配置路由器上的虚拟服务器,假设目的主机内网的ip为192.168.1.100,则配置如 ...

  8. (转)linux服务器安全配置攻略

    引言: 最小的权限+最少的服务=最大的安全 所以,无论是配置任何服务器,我们都必须把不用的服务关闭.把系统权限设置到最小话,这样才能保证服务器最大的安全.下面是CentOS服务器安全设置,供大家参考. ...

  9. asp.net WebApi and protobuff

    protobuff 是谷歌开发的,在性能上要比Json xml好很多,对性能要求比较高的时候这个是一个不错的选择,但是这个目前只是一个序列化反序列化的东西,以前原生的只有几种语言的现在在github ...

  10. 【腾讯Bugly干货分享】深度学习在OCR中的应用

    本文来自于腾讯bugly开发者社区,未经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/5809bb47cc5e52161640c5c8 Dev Club 是一个交流移动 ...