持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第22天,点击查看活动详情
1. 关联查询
MyBatis 作为 ORM 框架为项目中的对象模型和关系数据库之间建立联系,并提供机制实现程序对数据库中数据的操作。
对于简单的单表查询,MyBatis 提供了 JavaBean 和数据库 Table 的直接映射关系,可以很方便通过 bean 操作数据。
在实际业务中,关联数据查询也是比较常见的需求,如用户账户与详细信息关系、订单与明细的关系等,MyBatis 中同样提供了关联查询的能力。
2. 一对一关联
常见的系统中,用户登录账户仅作为登录的身份识别使用,登录后的用户信息存储在另外一个地方,两者建立一定的关联关系,且这种关系是唯一的,就是一对一关联关系。
2.1 定义关联表
自定义创建用户账户表和详细信息表,并使用 user_id 进行关联
CREATE TABLE `user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`username` varchar(100) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL,
`password` varchar(100) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
insert into `user`(`id`,`username`,`password`) values (1,'tom','abc123'),(2,'lily','123456');
CREATE TABLE `user_info` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) DEFAULT NULL,
`age` int(11) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL,
`address` varchar(100) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
insert into `user`(`id`,`user_id`,`age`,`address`) values (1,'1','18','上海市'),(2,2,17,'北京市');
2.2 定义 JavaBean
分别为两个表定义对应的对象模型类
- 对应 user 表
@Data
@Table("user")
public class User {
private long id;
private String username;
private String password;
}
- 对应 user_info 表
@Data
@Table("user_info")
public class Userinfo {
private long id;
private long userId;
private Integer age;
private String mobile;
}
3. 关联查询
使用 MyBaits 为数据模型和数据库表建立一个 Mapper 接口类,以此实现两者的关联,并提供操作数据库表中数据的能力。
3.1 业务代码关联
一对一关联查询,最常使用的方法是在业务代码中通过属性进行关联匹配 此种方法不需要使用 MyBatis 的关联支持,只需要分别对两个数据库进行单表查询,并使用查询结果中的关联字段进行匹配,最终得到关联合并的结果数据。
@Service
public class UserServiceImpl{
@Override
private Usermapper userMapper;
@Override
private UserInfomapper userInfoMapper;
public UserModelDto getUserInfoByUserId(){
User user = userMapper.queryUserById(userId);
UserInfo userInfo = userInfoMapper.queryUserInfoByUserId(userId);
UserModelDto userModelDto = new UserModelDto();
userModelDto.setUserId(userId);
userModelDto.setUserName(user.getUserName());
userModelDto.setUserAge(user.getAge());
userModelDto.setMobile(user.getMobile());
return userModelDto;
}
}
- 在业务代码中对多个表的数据进行处理是可行的,但是对于比较简单的表数据的整合,MyBatis 或 MySQL 的 SQL 语句完全可以胜任,并且可以使得业务代码逻辑更简洁。
3.2 MyBatis 实现一对一关联
MyBatis 进行一对一表关联时可以使用动态 SQL 语句中提供的 association 标签,并通过其中的相关属性来将多个分别定义的 SQL 语句产生关联,最终得到整合的数据。
- UserMapper.xml
<!-- 省略了 UserMapper.java 文件的定义-->
<mapper namespace="com.shone.manage.mapper.UserMapper">
<select id="queryUserById" resultType="com.shone.manage.Entity.User">
SELECT * FROM user WHERE id = #{id}
</select>
</mapper>
- UserInfoMapper.xml
<!-- 省略了 UserInfoMapper.java 文件的定义-->
<mapper namespace="com.shone.manage.mapper.UserInfoMapper">
<resultMap type="com.shone.manage.dto.userModelDto" id="userInfoMap">
<id property="id" column="id" />
<result property="userId" column="user_id" />
<result property="age" column="age" />
<result property="mobile" column="mobile" />
<!-- association 关联其他 SQL 实现一对一级联查询 -->
<association property="userName" column="username"
javaType="com.shone.manage.mapper.UserMapper"
select="com.shone.manage.mapper.UserMapper.queryUserById" />
</resultMap>
<select id="queryUserInfoByUserId" resultMap="userInfoMap">
SELECT * FROM user_info WHERE user_id = #{userId}
</select>
</mapper>
- 这样在执行外层 queryUserInfoByUserId 查询方法时,会根据对应的字段自动执行内部的 queryUserById 方法获取 username 字段内容
此时业务代码逻辑可以写成
@Service
public class UserServiceImpl{
@Override
private UserInfomapper userInfoMapper;
public UserModelDto getUserInfoByUserId(){
return userInfoMapper.queryUserInfoByUserId(userId);
}
}
3.3 MySQL 关联表实现一对一关联
除了业务逻辑代码整合数据、MyBatis 动态 SQL 关联,还可以根据 MySQL 自带的表关联语法实现一对一关联,在少表小表关联上更加适用
- 定义一个联合两张表的 UserJoinMapper.xml
<!-- 省略了 UserJoinMapper.java 文件的定义-->
<mapper namespace="com.shone.manage.mapper.UserJoinMapper">
<!--定义查询语句使用 inner join on 关联两张表的数据-->
<select id="queryUserModelDtoByUserId" resultType="com.shone.manage.dto.userModelDto">
SELECT user.username, user_info.user_id, user_info.age, user_info.mobile
FROM user
INNER JOIN user_info ON user.id = user_info.user_id
WHERE user.id = #{id}
</select>
</mapper>
- 业务代码逻辑书写
@Service
public class UserServiceImpl{
@Override
private UserJoinMapper userJoinMapper;
public UserModelDto getUserInfoByUserId(){
return userJoinMapper.queryUserModelDtoByUserId(userId);
}
}