三、子表删除兼容问题

这个问题,使用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. JQuery延时操作

    JQuery通过setTimeout函数可以实现延时操作以完成在编程达到某些需要的效果. 使用方法如下: function doSomething() { alert("hello worl ...

  2. Xenu Link Sleuth-简单使用

    1.工具说明 xenu link sleuth,主要用于测试网站死链接.包括图片.链接. 下载地址:http://home.snafu.de/tilman/xenulink.html#Download ...

  3. 使用小技巧,让你高效使用Eclipse

    1.自动完成--Eclipse有一个自动完成代码功能,快捷键是ctrl + space.当点击时就会弹出一个对话框,上面有与前后文相关的一些建议.只要有一个可能性,Eclipse就会替你完成. 2.快 ...

  4. 初学python第二天

    今天我将用python来编写一款小游戏,用这个来总结一下自己学过的一些基础语法.没错,它就是井字游戏.想想自己第一接触这种游戏,还是小学生呢

  5. c++中的指针

    指针用起来是一把利器,但用得不好的童鞋 无异于 火上浇油 ,下面笔者将自己学习 的一点小小心得,与君共享 指针在类中 1.对象指针 初始化 Point a(4,5); Point *p1 = & ...

  6. WPF控件经验小结:(1) ToolBar去掉右边箭头(扩展图标)

    今天开发时,同事问我一个问题.怎么去除ToolBar右边扩展图标.我想了一下,说改Style.同事说太麻烦了.可不可以快速修正.我说应该动态去读取Template模板中的Style,然后隐藏.怎么实现 ...

  7. Software Testing hw3

    (a):可绘制出如下图所示的流程图 (b):对于测试用例t1=(n=3)和t2=(n=5),MAXPRIMES = 4时,t1不能检查出错误,而t2则会发生数组越界错. (c):要使测试路径不通过wh ...

  8. Android中的TabHost

    TabHost是整个Tab的容器,包含TabWidget和FrameLayout两个部分,TabWidget是每个Tab的表情,FrameLayout是Tab内容. 实现方法:继承TabActivit ...

  9. Manhattan distance(for lab)

    Input four integer x1, y1, x2, y2, which is mean that the coordinates of two points A(x1, y1), B(x2, ...

  10. StoryBoard 简单使用

    StoryBoard简单使用 故事版(storyboard)是一种简洁的图形界面,程序员可以采取拖的形式搭建一个界面,现在使用的xcode默认都会创建一个main.storyboard,作为app的入 ...