先来看一下两个mapper:
UserMapper.xml——主要完成对用户表(user)的表操作
<mapper namespace=”com.A.xsstuser.impl.dao.UserDao”>
<resultMap id=”BaseResultMap” type=”com.kainaodong.xsstuser.impl.model.User”>
<id column=”user_id” jdbcType=”INTEGER” property=”userId” />
<result column=”nickname” jdbcType=”VARCHAR” property=”nickname” />
<result column=”school_id” jdbcType=”INTEGER” property=”schoolId” />
<result column=”password” jdbcType=”VARCHAR” property=”password” />
……
</resultMap>
……
</mapper>
UserDetailMapper.xml——主要完成对用户详情表(UserDetail)的表操作
<mapper namespace=”com.A.xsstuser.impl.dao.UserDetailDao”>
<resultMap id=”UserDetailMap” type=”com.kainaodong.xsstuser.impl.model.UserDetail” >
<id column=”user_id” property=”userId” jdbcType=”INTEGER” />
<result column=”realname” property=”realname” jdbcType=”VARCHAR” />
<result column=”gender” property=”gender” jdbcType=”TINYINT” />
<result column=”birthday” property=”birthday” jdbcType=”DATE” />
……
</resultMap>
<sql id=”UserDetail_Base_Column_List” >
user_id, realname, gender, birthday
</sql>
<select id=”selectUserDetailById” resultMap=”UserDetailMap” parameterType=”java.lang.Integer” >
select
<include refid=”UserDetail_Base_Column_List” />
from user_detail
where user_id = #{userId,jdbcType=INTEGER}
</select>
</mapper>
现在有一个需求是需要将User表和UserDetail进行关联查询。我的设计是将这个操作放在UserMapper.xml里面。复杂的关联查询在网上都有很多说明了,这里就不复述了。
既然UserDetailMapper.xml中已经有了映射UserDetail表的列,因此按照编程习惯,肯定要复用一下的,所以根据网上的资料,一开始我在UserMapper.xml里面添加了如下resultMap:
<resultMap id=”UserJoinUserDetail” type=”User”>
<id column=”user_id” jdbcType=”INTEGER” property=”userId” />
<result column=”nickname” jdbcType=”VARCHAR” property=”nickname” />
<result column=”school_id” jdbcType=”INTEGER” property=”schoolId” />
<result column=”password” jdbcType=”VARCHAR” property=”password” />
……
<!– 关联userdetail表 –>
<association property=”userDetail” column=”user_detail” resultMap=”UserDetailMap” />
</resultMap>
保存,然后测试,嗯~妥妥的报错了。看了一下提示,大概就是UserDetailMap不存在的意思。那就奇怪了,明明在UserDetailMapper.xml中定义了的,为什么呢?然后就查看两个mapper,看到<mapper namespace ……>,难道由于namespace不同原因,所以果断将UserDetailMapper.xml的namespace换成和UserMapper的相同的。再测试,这次成功了,真的是namespace的原因。
那这样说,是不是应该同一个模块的mapper的namespace都设成一样呢?我测试了一下,如果改成其他名称如:User,启动的时候会报错(由于mapper是用mybatis的相关功能自动生成的,所以当时只引入了xml,而没将mapper 接口类引入,不然改了UserDetailMapper的namespace时,应该启动就报错)。原因是这个namespace有一个意义是指定相关POJO接口的路径,详情可查看以下链接。
Mybatis的namespace问题说明
那该怎么办,上网找,好像都没有很明确关于如何引用其他mapper文件中的resultMap的文章。那只能再回去看错误日志:
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException:
Error querying database. Cause: java.lang.IllegalArgumentException: Result Maps collection does not contain value for com.A.kainaodong.xsstuser.impl.dao.UserDao.UserDetailMap
The error may exist in com/A/xsstuser/impl/dao/UserMapper.xml
细心看,其实可以发现,错误中com.A.kainaodong.xsstuser.impl.dao.UserDao.UserDetailMap的UserDetailMap前面还有一串东西,刚好也就是UserMapper的namespace,在UserMapper下当然是找不到UserDetailMap的了,那如果在UserDetailMap前加上UserDetailMapper的namespace的话可能可以,即:
<association property=”userDetail” column=”user_detail” resultMap=”com.A.xsstuser.impl.dao.UserDetailDao.UserDetailMap” />
然后保存,测试,通过。确实可以这样写。
如果不引用resultmap的话,可以应用其他文件的select,如下
<association property=”userDetail” column=”user_id” select=”com.kainaodong.xsstuser.impl.dao.UserDetailDao.selectUserDetailById” /> // 当然也要加上namespace咯。
出现这种问题,也可能由于我对mybatis的运行机制还不太了解。所以写一下这篇文章,整理一下思路。