association关联元素处理“有一个”类型的关系,即一对一关联。
它有两种关联方式
嵌套查询:通过执行另外一个SQL映射语句来返回预期的复杂类型。
嵌套结果:使用嵌套结果映射来处理重复的联合结果的子集。
嵌套查询
Xml代码
<resultMap id="userResultMap" type="User">
<id property="id" column="ID" jdbcType="NUMERIC" javaType="java.lang.Long"/>
<result property="loginName" column="LOGIN_NAME" jdbcType="VARCHAR" javaType="java.lang.String"/>
<result property="password" column="password" jdbcType="VARCHAR" javaType="java.lang.String"/>
<result property="roleId" column="role_id" jdbcType="NUMERIC" javaType="java.lang.Long"/>
<association property="role" column="role_id" javaType="Role" select="selectRole"/>
</resultMap>
<select id="selectUser" parameterType="java.lang.Long" resultMap="userResultMap" >
select * from User where id =#{id}
</select>
<select id="selectRole" parameterType="java.lang.Long" resultType="Role" >
select * from Role where id =#{id}
</select>
这里有两个查询,一个查询加载User,一个查询加载Role.
这里select为另外一个映射语句的ID,可以加载这个属性映射需要的复杂类型。获取的在列属性中指定的列的值将被传递给目标select语句作为参数。
注意:要保证第二个查询查出来的结果只有一条记录。
要处理复合主键,你可以指定多个列名通过column="{prop1=col1,prop2=col2}"这种语法来传递给嵌套查询语句。这会引起prop1和prop2以参数对象形式来设置给目标嵌套查询语句。
Xml代码
<resultMap id="userResultMap" type="User">
<id property="id" column="ID" jdbcType="NUMERIC" javaType="java.lang.Long"/>
<result property="loginName" column="LOGIN_NAME" jdbcType="VARCHAR" javaType="java.lang.String"/>
<result property="password" column="password" jdbcType="VARCHAR" javaType="java.lang.String"/>
<result property="roleId" column="role_id" jdbcType="NUMERIC" javaType="java.lang.Long"/>
<association property="role" column="{id=role_id,name=role_name}" javaType="Role" select="selectRole"/>
</resultMap>
<select id="selectRole" parameterType="HashMap" resultType="Role" >
select * from Role where id =#{id} and name= #{name}
</select>
这种方式很简单,但是对于大型数据集合和列表将不会表现很好。问题就是我们熟知的“N+1查询问题”。概括地讲,N+1查询问题可以是这样引起的:
你执行了一个单独的SQL语句来获取结果列表(就是“+1”)。
对返回的每条记录,你执行了一个查询语句来为每个加载细节(就是“N”)。
这个问题会导致很多的SQL语句被执行。这通常不是期望的。
比如一个查询用户列表的SQL,假如有2000个用户,那么就是一个查询用户的SQL和2000个查询角色的SQL,一共有2001个SQL被运行。
MyBatis能延迟加载这样的查询就是一个好处,因此你可以分散这些语句同时运行的消耗。然而,如果你加载一个列表,之后迅速迭代来访问嵌套的数据,你会调用所有的延迟加载,这样的行为可能是很糟糕的。
所以还有另外一种方法。
关联的嵌套结果
嵌套结果
Xml代码
<resultMap id="userResultMap" type="User">
<id property="id" column="ID" jdbcType="NUMERIC" javaType="java.lang.Long"/>
<result property="loginName" column="LOGIN_NAME" jdbcType="VARCHAR" javaType="java.lang.String"/>
<result property="password" column="password" jdbcType="VARCHAR" javaType="java.lang.String"/>
<result property="roleId" column="role_id" jdbcType="NUMERIC" javaType="java.lang.Long"/>
<association property="role" column="role_id" javaType="Role" resultMap="roleResultMap"/>
<id property="id" column="role_id"/>
<result property="name" column="role_name"/>
</association>
</resultMap>
<resultMap id="roleResultMap" type="Role">
<id property="id" column="role_id"/>
<result property="name" column="role_name"/>
</resultMap>
也可以这样配置
Xml代码
<resultMap id="userResultMap" type="User">
<id property="id" column="ID" jdbcType="NUMERIC" javaType="java.lang.Long"/>
<result property="loginName" column="LOGIN_NAME" jdbcType="VARCHAR" javaType="java.lang.String"/>
<result property="password" column="password" jdbcType="VARCHAR" javaType="java.lang.String"/>
<result property="roleId" column="role_id" jdbcType="NUMERIC" javaType="java.lang.Long"/>
<association property="role" column="role_id" javaType="Role" resultMap="roleResultMap"/>
</resultMap>
<resultMap id="roleResultMap" type="Role">
<id property="id" column="role_id"/>
<result property="name" column="role_name"/>
</resultMap>
resultMap这是结果映射的ID,可以映射关联的嵌套结果到一个合适的对象图中。这是一种替代方法来调用另外一个查询语句。这允许你联合多个表来合成到一个单独的结果集。这样的结果集可能包含重复,数据的重复组需要被分解,合理映射到一个嵌套的对象图。为了使它变得容易,MyBatis让你“链接”结果映射,来处理嵌套结果。一个例子会很容易来仿照,这个表格后面也有一个示例。
注意这个联合查询,以及采取保护来确保所有结果被唯一而且清晰的名字来重命名。
columnPrefix 属性
Xml代码
<association property="role" column="role_id" javaType="Role" resultMap="roleResultMap" columnPrefix="role_"/>
<id property="id" column="id"/>
<result property="name" column="name"/>
</association>
非常重要:在嵌套据诶过映射中id元素扮演了非常重要的角色。应应该通常指定一个或多个属性,它们可以用来唯一标识结果。实际上就是如果你离开她了,但是有一个严重的性能问题时MyBatis仍然可以工作。选择的属性越少越好,它们可以唯一地标识结果。主键就是一个明显的选择(尽管是联合主键)。
上面你已经看到了如何处理“有一个”类型关联。但是“有很多个”是怎样的?下面这个部分就是来讨论这个主题的。
collection
collection关联元素处理一对多关联。
Xml代码
<resultMap id="roleResultMap" type="Role">
<id property="id" column="ID" jdbcType="NUMERIC" javaType="java.lang.Long"/>
<result property="name" column="NAME" jdbcType="VARCHAR" javaType="java.lang.String"/>
<result property="userId" column="user_id" jdbcType="NUMERIC" javaType="java.lang.Long"/>
<collection property="user" column="user_id" javaType="ArrayList" ofType="Post" select="selectUser"/>
</resultMap>
<select id="selectUser" parameterType="java.lang.Long" resultType="User" >
select * from uer where id =#{id}
</select>
同样,可以这样配置
Xml代码
<resultMap id="roleResultMap" type="Role">
<id property="id" column="ID" jdbcType="NUMERIC" javaType="java.lang.Long"/>
<result property="name" column="NAME" jdbcType="VARCHAR" javaType="java.lang.String"/>
<result property="userId" column="user_id" jdbcType="NUMERIC" javaType="java.lang.Long"/>
<collection property="user" column="user_id" javaType="ArrayList" ofType="Post">
<id property="id" column="user_id"/>
<result property="name" column="user_name"/>
</collection>
</resultMap>
<resultMap id="userResultMap" type="User">
<id property="id" column="user_id"/>
<result property="name" column="user_name"/>
</resultMap>