我们在查询业务数据的时候经常会遇到关联查询的情况。
比如查询用户会关联设备(1对多),查询设备会关联用户(1对1)。
一个设备属于一个用户,这是一对一的关系:如下内容:
#设备表
CREATE TABLE `t_device` (
`id` int NOT NULL,
`sn` varchar(45) DEFAULT NULL,
`u_id` int DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
#用户表
CREATE TABLE `t_user` (
`uid` int NOT NULL,
`name` varchar(45) DEFAULT NULL,
PRIMARY KEY (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
<select id="queryUserNested" resultMap="nestedMap">
select
t1.id,
t1.sn,
t2.uid,
t2.name
from
t_device t1
left join t_user t2 on t1.u_id = t2.uid
</select>
<resultMap id="nestedMap" type="com.lk.tool.bean.Device">
<id property="id" column="id" jdbcType="INTEGER"/>
<result property="sn" column="sn" jdbcType="VARCHAR"/>
<association property="user" javaType="com.lk.tool.bean.User">
<id column="uid" property="uid"/>
<result column="name" property="name"/>
</association>
</resultMap>
实体类
@Data
@Builder
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Device {
private int id;
private String sn;
private User user;
}
@Data
@NoArgsConstructor
public class User {
private int uid;
private String name;
}
测试类:
@Test
void testAssociateQuery() throws IOException {
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
SqlSession sqlSession = sqlSessionFactory.openSession();
DeviceMapper deviceMapper = sqlSession.getMapper(DeviceMapper.class);
List<Device> list = deviceMapper.queryUserNested();
sqlSession.commit();
sqlSession.close();
list.forEach(entity->{
System.out.println(entity);
});
}
测试类执行结果:
Device(id=1, sn=CHYLL00001, user=User(uid=1, name=Emily))
Device(id=2, sn=CHYLL00002, user=User(uid=2, name=Chris))
Device(id=3, sn=CHYLL00003, user=User(uid=3, name=Eva))
Device(id=4, sn=CHYLL00004, user=User(uid=4, name=Spring))
一个用户可以拥有多个设备,这是一对多的关系,如下所示:
<resultMap id="NestedDevice" type="user">
<id property="uid" column="uid"/>
<result property="name" column="name"/>
<collection property="devices" ofType="device">
<id property="id" column="id"/>
<result property="sn" column="sn"/>
</collection>
</resultMap>
<select id="queryUserNested" resultMap="NestedDevice">
select
t1.uid,
t1.name,
t2.id,
t2.sn
from t_user t1
left join t_device t2 on t1.uid = t2.u_id
</select>
执行结果:
User(uid=1, name=Emily, devices=[Device(id=5, sn=CHYLL00005, user=null), Device(id=1, sn=CHYLL00001, user=null)])
User(uid=2, name=Chris, devices=[Device(id=2, sn=CHYLL00002, user=null)])
User(uid=3, name=Eva, devices=[Device(id=3, sn=CHYLL00003, user=null)])
User(uid=4, name=Spring, devices=[Device(id=4, sn=CHYLL00004, user=null)])
关联(association)元素处理“有一个”类型的关系。 比如,在我们的示例中,一个博客有一个用户。关联结果映射和其它类型的映射工作方式差不多。 你需要指定目标属性名以及属性的javaType(很多时候 MyBatis 可以自己推断出来),在必要的情况下你还可以设置 JDBC 类型,如果你想覆盖获取结果值的过程,还可以设置类型处理器。
关联的不同之处是,你需要告诉 MyBatis 如何加载关联。MyBatis 有两种不同的方式加载关联:
嵌套结果映射:使用嵌套的结果映射来处理连接结果的重复子集。
嵌套 Select 查询:通过执行另外一个 SQL 映射语句来加载期望的复杂类型。
延迟加载
在settings标签里设置:
<!--延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。默认false -->
<setting name="lazyLoadingEnabled" value="true"/>
<!--当开启时,任何方法的调用都会加载该对象的所有属性。默认false,可通过select标签的
fetchType来覆盖-->
<setting name="aggressiveLazyLoading" value="false"/>
lazyLoadingEnabled 决定来是否延迟加载(默认false)
aggressiveLazyLoading决定了是不是对象的所有方法都会触发查询。
启用延迟加载后,当使用到被关联的属性时才会执行查询,否则不会执行子查询。