在Mybatis中使用接口继承实现通用性crud

2013/04/24 17:13:37 3 Comments

在最新的mybatis中,我们通过定义一个接口,然后通过mybatis-spring插件来调用相应的接口xml实现spring代理bean。那么考虑这样一种场景,我们定义了一个通用性的操作,如getByKey方法,即通过一个主键查找所对应的对象。这个在hibernate中可以这样来描述,即

//Hibernate
get(Serializable id,Class clazz)

//我们要实现的Mybatis版本
getByKey(Key key)

由上的调用相对比一下,会发现下面的方法缺少一个clazz,即实际要返回哪个对象。这也是在mybatis中所必须的参数信息,即在mapper.xml中,我们必须定义一个resultType,即标明要返回哪个对象。当然,可以使用通用的map,或者object对象,但是这样的实现就相比hibernate来说,弱很多了。

本文描述了一种,通过接口继承来实现统一的SQL方法,便根据不同的调用者来返回不同的数据对象的一个方法。通过这个方法,可以实现如hibernate中一样的通用性get操作,而不需要每一个数据对象写一个获取方法。

在前文所说的getByKey中,我们的sql可以描述为以下的伪代码:

		select * from ${key.schema}.${key.name}
		where
		1 = 1 and
		<foreach collection="key.vsList" separator="and" item="vs">//数据参数集
			${vs.jdbcField} = #{vs.v,jdbcType=${vs.jdbcType}}
		</foreach>
		and rownum &lt;= 2

上述中的代码表示,key中封装了大量的信息,但实际上,可以通过简化的其它手段动态的组装入这些信息。在实际调用中,我们只需要传入主键信息即可,如Key.of(1L),即表示主键值为1的数据。由于这不是本文的重点,简单略过。

在上述的代码中,并没有说明将返回哪个resultType,但根据业务上的通用处理,每一个数据表均会对应一个数据对象,即domain,而每一个domain,一般都会有一个相对应的mapper对象。那么我们可以这样来认为,如果我们调用StudentMapper.getByKey(key)方法,我们将会返回一个student对象,如果是ClassMaper.getByKey,将会返回一个class对象。
而实际上,这个getByKey是在BaseMapper中定义的,StudentMapper和ClassMapper只不过是继承而已。

这里消除一个误解,并不是说继承了baseMapper,然后再把上面的sql代码再复制一遍,而是我们使用一种手段自动地将其注入到相应的子mapper中即可。
这里要说一个限制,在mybatis-spring中,我们我们调用studentMapper.getByKey方法时,mybatis将自动查找一个叫studentMapper.getByKey的一个statement。如果找到,则调用此方法,否则则报错误信息。那么我们将使用手段注入这些statement到mybatis即可。

实际上的实现也很简单,即首先查找到baseMapper中的getByKey定义,然后将其重新与子mapper进行重新组合,并改变相应的resultType即可。简单的代码如下所示:

//查找到baseMapper定义
MappedStatement getByKey = configuration.getMappedStatement(BaseMapper.class.getName() + ".getByKey");
//定义子mapper的statement1
String getByKeyId = clazz.getName() + ".getByKey";
			if(!configuration.hasStatement(getByKeyId)) {
//创建新的statement,并封装相应的resultType
				MappedStatement getByKeyMappedStatement = buildNewStatement(getByKey, getByKeyId,
						子mapper所对应的domain类型);
//添加进configuration即可
				configuration.addMappedStatement(getByKeyMappedStatement);
			}

1    在上面的实现当中,我们需要先找到哪些类继承了BaseMapper,这个简单。使用classFinder即可。
2    其次,需要创建新的buildNewStatement,这个也不难,使用MappedStatement.Builder简单复制一个即可,当然在复制过程中我们需要加入自己的东西,如id,resultType等。
3    还有一个问题,我们需要找到这个mapper对应的domain,这个可以通过一个映射来完成。

转载请标明出处:i flym
本文地址:https://www.iflym.com/index.php/code/201304240001.html

相关文章:

已有3 个评论

  1. wxl Says:

    求解 在哪里注入的?

  2. flym Says:

    这边没有使用注入,是直接改写MapperProxy的实现来完成的.如果发现调用的方法声明类为顶层接口,则跳转到自定义实现

  3. ssss379 Says:

    有点看不懂,能否提供给例子,或者再多点讲解,谢谢

留下足迹