三、子表删除兼容问题

这个问题,使用SQL配置函数不太好处理,而且就算使用SQL配置函数,也不够直观,有点自动生成SQL的意味,太Hibernate了(不过要是可以兼收Hibernate和Mybatis两家之长,那也是一个不错的主意),下面我们使用自定义命名空间的方式来解决。

1、编写sqlmapper-extend命名空间的XSD文件,引进新的<db>元素

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns="http://dysd.org/schema/sqlmapper-extend"
targetNamespace="http://dysd.org/schema/sqlmapper-extend"
xmlns:s="http://dysd.org/schema/sqlmapper"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
version="1.0"> <!-- 导入由mybatis官方DTD转换而来的XSD命名空间 -->
<xsd:import namespace="http://dysd.org/schema/sqlmapper"
schemaLocation="http://dysd.org/schema/sqlmapper.xsd"/> <xsd:element name="db">
<xsd:annotation><xsd:documentation><![CDATA[
定义一个新的db元素,有一个枚举列表的属性type,表示数据库类型,以!开头表示否定
可以配置SQL文本、statement级元素、script级元素以及其它扩展空间元素等子元素
]]></xsd:documentation></xsd:annotation>
<xsd:complexType mixed="true">
<xsd:choice maxOccurs="unbounded">
<xsd:group ref="s:statementGroup" minOccurs="0" maxOccurs="1"/>
<xsd:group ref="s:dynaScriptGroup" minOccurs="0" maxOccurs="1" />
</xsd:choice>
<xsd:attribute name="type" use="required">
<xsd:simpleType>
<xsd:list>
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="!"/>
<xsd:enumeration value="Oracle"/>
<xsd:enumeration value="MySQL"/>
<xsd:enumeration value="DB2"/>
<xsd:enumeration value="H2"/>
<xsd:enumeration value="SybaseASE"/>
<xsd:enumeration value="SybaseIQ"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:list>
</xsd:simpleType>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
</xsd:schema>

2、将扩展命名空间和XSD文件路径配置到ini文件中

# 用于配置sqlmapper的命名空间

# SqlMapper命名空间
[http://dysd.org/schema/sqlmapper]
schema = namespace/dysd-sqlmapper.xsd
parser = org.dysd.dao.mybatis.schema.SchemaSqlMapperNamespaceParser # 扩展命名空间,因为不是根元素,所以不需要配置命名空间解析器
[http://dysd.org/schema/sqlmapper-extend]
schema = namespace/dysd-sqlmapper-extend.xsd

3、编写db元素的解析处理器,因为db元素即可作为一级子元素(statement),也可作为脚本级元素(script),因此我们实现这两种处理器:

//Statement级处理器实现类
public class DbStatementHandler extends StatementHandlerSupport{ @Override
public void handleStatementNode(Configuration configuration, SchemaSqlMapperParserDelegate delegate, XNode node) {
if(SchemaHandlers.isMatch(configuration.getDatabaseId(), node.getStringAttribute("type"))){
delegate.doParseStatements(node.getNode());
}
}
} //Script级处理器实现类
public class DbScriptHandler extends ScriptHandlerSupport { @Override
public void handleScriptNode(Configuration configuration, XNode node, List<SqlNode> targetContents) {
if(!SchemaHandlers.isMatch(configuration.getDatabaseId(), node.getStringAttribute("type"))){
List<SqlNode> contents = parseDynamicTags(configuration, node);
final MixedSqlNode mixedSqlNode = new MixedSqlNode(contents);
targetContents.add(new SqlNode(){
@Override
public boolean apply(DynamicContext context) {
mixedSqlNode.apply(context);
return true;
}
});
}
}
} //SchemaHandlers中的帮助方法
public static boolean isMatch(String databaseId, String allowDatabaseIds){
if(!Tool.CHECK.isBlank(databaseId) && !Tool.CHECK.isBlank(allowDatabaseIds)){
String[] allows = allowDatabaseIds.split("\\s+");//使用空白字符分隔
boolean mode = !"!".equals(allows[0]);//是否肯定模式
if(mode){//肯定模式
for(int i = 0, l = allows.length; i < l; i++){
if(databaseId.equalsIgnoreCase(allows[i])){
return true;
}
}
}else{// 否定模式,从第1项开始匹配
for(int i = 1, l = allows.length; i < l; i++){
if(databaseId.equalsIgnoreCase(allows[i])){
return false;
}
}
return true;
}
}
return false;
}

4、在SchemaHandlers中注册实现类

// 注册自定义命名空间的处理器
registerExtend("db", new DbStatementHandler(), new DbScriptHandler());

5、修改SqlMapper中配置,为了不实际执行数据库操作,这里只以脚本级的查询语句为例

<?xml version="1.0" encoding="UTF-8" ?>
<mapper xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://dysd.org/schema/sqlmapper"
xmlns:e="http://dysd.org/schema/sqlmapper-extend"
xsi:schemaLocation="http://dysd.org/schema/sqlmapper http://dysd.org/schema/sqlmapper.xsd
http://dysd.org/schema/sqlmapper-extend http://dysd.org/schema/sqlmapper-extend.xsd"
namespace="org.dysd.dao.mybatis.schema.IExampleDao"> <select id="selectString" resultType="string">
select PARAM_NAME
from BF_PARAM_ENUM_DEF
<e:db type="MySQL">
<if test="null != paramName and '' != paramName">
where PARAM_NAME $like{#{paramName, jdbcType=VARCHAR}}
</if>
</e:db>
<e:db type="! MySQL">
<if test="null != paramName and '' != paramName">
where PARAM_CODE = 'DISPLAY_AREA'
</if>
</e:db>
</select>
</mapper>

需要注意,这里引入了两个命名空间。

6、执行测试

(1)H2

20161108 09:48:37,738 [main]-[DEBUG] ==>  Preparing: select PARAM_NAME from BF_PARAM_ENUM_DEF where PARAM_NAME LIKE '%'||?||'%'

(2)MySQL

20161108 09:50:36,453 [main]-[DEBUG] ==>  Preparing: select PARAM_NAME from BF_PARAM_ENUM_DEF where PARAM_CODE = 'DISPLAY_AREA' 

从where条件可知已经实现预期的效果。

可能有人会说,其实根本不用麻烦,直接使用mybatis的<if>或<choose>,在其中判断_databaseId参数的值就可以。虽然mybatis可以实现这种情况,但需要开发人员记住_databaseId这个参数名,并且<if>或<choose>只能用作脚本级Script的元素使用,不能作为语句级Statement的元素使用;而且更重要的是,扩展提供了一种机制,上面的例子只是演示怎么引入自定义命名空间的元素,仅仅只是其中一个例子而已,开发人员尽可以发挥自己的聪明才智,自行扩展出更多实用的元素。

Mybatis中SqlMapper配置的扩展与应用(2)的更多相关文章

  1. Mybatis中SqlMapper配置的扩展与应用(3)

    隔了两周,首先回顾一下,在Mybatis中的SqlMapper配置文件中引入的几个扩展机制: 1.引入SQL配置函数,简化配置.屏蔽DB底层差异性 2.引入自定义命名空间,允许自定义语句级元素.脚本级 ...

  2. Mybatis中SqlMapper配置的扩展与应用(1)

    奋斗了好几个晚上调试程序,写了好几篇博客,终于建立起了Mybatis配置的扩展机制.虽然扩展机制是重要的,然而如果没有真正实用的扩展功能,那也至少是不那么鼓舞人心的,这篇博客就来举几个扩展的例子. 这 ...

  3. mybatis中resultMap配置细则

    resultMap算是mybatis映射器中最复杂的一个节点了,能够配置的属性较多,我们在mybatis映射器配置细则这篇博客中已经简单介绍过resultMap的配置了,当时我们介绍了resultMa ...

  4. MyBatis中---数据库配置的属性名冲突问题

    一.db.properties 属性文件中 最好加特殊的标志前缀  jdbc.username ,如果单纯的username有可能影响到 mapper.xml中的 ${username}; 举例   ...

  5. mybatis中namespace配置方式

    namespace有三种全路径的配置方式: namespace绑定实体类的全路径;绑定dao接口的全路径绑定;mapper的sql.xml文件第一种:namespace绑定实体类的全路径: 当name ...

  6. MyBatis中的配置错误creating bean with name 'sqlSessionFactory'

    错误信息如下: 警告: Exception encountered during context initialization - cancelling refresh attempt: org.sp ...

  7. Springboot中以配置类方式自定义Mybatis的配置规则(如开启驼峰映射等)

    什么是自定义Mybatis的配置规则? 答:即原来在mybatis配置文件中中我们配置到<settings>标签中的内容,如下第6-10行内容: 1 <?xml version=&q ...

  8. 优化与扩展Mybatis的SqlMapper解析

    接上一篇博文,这一篇来讲述怎么实现SchemaSqlMapperParserDelegate——解析SqlMapper配置文件. 要想实现SqlMapper文件的解析,还需要仔细分析一下mybatis ...

  9. Mybatis中配置Mapper的方法

    在这篇文章中我主要想讲一下Mybatis配置文件中mappers元素的配置.关于基础部分的内容可以参考http://haohaoxuexi.iteye.com/blog/1333271. 我们知道在M ...

随机推荐

  1. c#编程指南(十) 平台调用P-INVOKE完全掌握, 字符串和指针

    可以说新手使用P-INVOKE最开始的头疼就是C#和C++的字符串传递,因为这里涉及到两个问题. 第一:C#的string和C++的字符串首指针如何对应. 第二:字符串还有ANSI和UNICODE(宽 ...

  2. WideCharToMultiByte和MultiByteToWideChar函数的用法

    为了支持Unicode编码,需要多字节与宽字节之间的相互转换.这两个系统函数在使用时需要指定代码页,在实际应用过程中遇到乱码问题,然后重新阅读<Windows核心编程>,总结出正确的用法. ...

  3. 在android 6.0(API 23)中,Google已经移除了移除了Apache HttpClient相关的类

    推荐使用HttpUrlConnection,如果要继续使用需要Apache HttpClient,需要在eclipse下libs里添加org.apache.http.legacy.jar,androi ...

  4. 基于Linux的WebSphere性能调优与故障诊断

    一.关于was数据源等问题的配置 (1)关于was数据源连接池的最大.最小配置多大合适?怎样去计算? (2)关于JVM的配置,64位系统,64位WAS,最值小和最大配置多大最优?怎样去计算? (3)应 ...

  5. Java学习笔记(六)

    期末课程选题:QQ登录界面.好友列表界面及聊天框界面. 功能实现:简单的功能可实现,如:点击登录进入好友列表界面:点击好友可进入聊天框:可实现简单聊天功能:聊天可输入及输出,可选择私聊或群聊,可获得当 ...

  6. kali基本设置

    一.更换比较快的软件源 修改sources.list文件(su): leafpad /etc/apt/sources.list #debain源 deb http://mirrors.163.com/ ...

  7. stanford-parser使用说明

    主意:本说明文档针对stanford-parser-full-2014-06-16.不同版本的parser,其功能和表示形式可能会略有不同.但总体不会有太大差异 Stanford parser是一款较 ...

  8. 在docker里部署网络服务

    之前试着玩玩docker有一阵子了,今天算是头一回正式在docker里部署网络服务. 本来想和lxc差不多的东西那自然是手到擒来,没想到还是改了很多. 第一个遇到的问题是,远程连到docker宿主机干 ...

  9. oracle 11g install linux

    #!/bin/bash#Purpose:Create and config oracle install.#Usage:Log on as the superuser('root') #1.creat ...

  10. 【重磅推荐】腾讯Bugly2015年移动应用质量大数据报告

    2015年,随着移动智能设备的普及,移动端用户的增速明显放缓:相比之下,由于云服务.众筹平台.推广平台等基础设施和服务的不断改善,极大降低了创业的门槛,越来越多人投身于移动应用的创新创业中. 想让用户 ...