前面了解了springboot + mybatis的单数据源和多数据源的集成已经使用,本篇文章来聊聊mybatis的高端用法吧
1.环境搭配
1.1 pom依赖
- 基于springboot 2.5.6,也可以参看mybatis的第一篇文章
<!--Mysql依赖包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
1.2 yml配置
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.0.100:3306/demo_test?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false
username: root
password: 123456
#mybatis资源文件扫描和其他相关配置
mybatis:
mapperLocations: classpath:mapper/*/*.xml
executorType: SIMPLE
configuration:
# 驼峰式 测试用先关闭
# map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
1.3 数据库表
user_info 用户的信息表
user_card 用户身份证表 一个用户一个身份证 一对一
user_mobile 用户手机号表 一个用户有多个手机号
-- 导出 表 demo_test.user_card 结构
CREATE TABLE IF NOT EXISTS `user_card` (
`user_id` bigint(20) NOT NULL COMMENT '用户ID',
`card` varchar(50) DEFAULT NULL COMMENT '身份证',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='身份证表';
-- 正在导出表 demo_test.user_card 的数据:~3 rows (大约)
DELETE FROM `user_card`;
/*!40000 ALTER TABLE `user_card` DISABLE KEYS */;
INSERT INTO `user_card` (`user_id`, `card`, `create_time`, `update_time`) VALUES
(1, '111111', '2022-02-17 16:45:28', '2022-02-17 16:45:28');
/*!40000 ALTER TABLE `user_card` ENABLE KEYS */;
-- 导出 表 demo_test.user_info 结构
CREATE TABLE IF NOT EXISTS `user_info` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL COMMENT '名称',
`age` int(11) DEFAULT NULL COMMENT '年龄',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
-- 正在导出表 demo_test.user_info 的数据:~3 rows (大约)
DELETE FROM `user_info`;
/*!40000 ALTER TABLE `user_info` DISABLE KEYS */;
INSERT INTO `user_info` (`id`, `name`, `age`, `create_time`, `update_time`) VALUES
(1, '张三', 22, '2022-02-17 16:45:01', '2022-02-17 16:47:21');
/*!40000 ALTER TABLE `user_info` ENABLE KEYS */;
-- 导出 表 demo_test.user_mobile 结构
CREATE TABLE IF NOT EXISTS `user_mobile` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`userId` bigint(20) DEFAULT NULL COMMENT '用户id',
`mobile` varchar(50) NOT NULL COMMENT '手机号',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `userId` (`userId`,`mobile`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='用户手机表';
-- 正在导出表 demo_test.user_mobile 的数据:~2 rows (大约)
DELETE FROM `user_mobile`;
/*!40000 ALTER TABLE `user_mobile` DISABLE KEYS */;
INSERT INTO `user_mobile` (`id`, `userId`, `mobile`, `create_time`, `update_time`) VALUES
(1, 1, '13011112222', '2022-02-17 16:45:51', '2022-02-17 16:45:51'),
(2, 1, '13011112223', '2022-02-17 16:45:51', '2022-02-17 16:47:02'),
(3, 1, '13011112224', '2022-02-17 16:45:51', '2022-02-17 16:47:02');
1.4 测试代码
@Resource
TestMapper testMapper;
@GetMapping("/data/selectBean")
public Object selectBean(@RequestParam(required = false) Long id) {
UserInfo userInfo = new UserInfo();
userInfo.setId(id);
List<UserInfo> userInfos = testMapper.selectBean(userInfo);
return userInfos;
}
1.5 java bean
分别对user_info、user_card、user_mobile生成实体bean,并添加getter、setter方法
只贴下user_info的bean,后面一对一,一对多查询用
@Data
public class UserInfo {
Long id;
String name;
Integer age;
//个人的身份证,一对一关系
UserCard userCard;
//个人的手机号 一对多关系
Set<UserMobile> userMobiles;
String createTime;
String updateTime;
}
2. resultMap 映射
2.1 直接映射
- xml文件,注意传参的
parameterType
和出参的resultType
<select id="selectBean" parameterType="com.example.demo.entity.UserInfo"
resultType="com.example.demo.entity.UserInfo">
select * from user_info where id = #{id}
</select>
- 测试结果输出
[{
"id": 1,
"name": "张三",
"age": 22,
"userCard": null,
"userMobileList": null,
"createTime": null,
"updateTime": null
}]
结果可以看到,原本表中的createTime和updateTime有值的,但也输出是空。
解决方法:
- 打开yml里面的驼峰式配置
map-underscore-to-camel-case: true
- 使用自定义的映射resultMap
接下来方便测试,从这里打开驼峰式的配置
2.2 自定义映射map
- xml代码做如下修改
//例如这个xml下有很多个查询都需要用到userInfo,就可以抽离出来使用
//id 别名的意思 需保持唯一 type:映射到javabean中的实体类
<resultMap id="userInfoMap" type="com.example.demo.entity.UserInfo">
//id 主键 column/数据库中的列名 property/对应实体类中的列名
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
</resultMap>
//这里的出参就要使用resultMap了 指向上面的id
<select id="selectBean" parameterType="com.example.demo.entity.UserInfo"
resultMap="userInfoMap">
select * from user_info where id = #{id}
</select>
- 测试结果输出
[{
"id": 1,
"name": "张三",
"age": 22,
"userCard": null,
"userMobileList": null,
"createTime": "2022-02-17 16:45:01",
"updateTime": "2022-02-17 16:47:21"
}]
user_Info表中的数据都能看到了,接下来看看userCard一对一的扩展该怎么实现
3. 一对一数据查询
3.1 关联实现
<resultMap id="userInfoMap" type="com.example.demo.entity.UserInfo">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
<association property="userCard" javaType="com.example.demo.entity.UserCard">
<id property="userId" column="user_id"/>
<result property="card" column="card"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
</association>
</resultMap>
<select id="selectBean" parameterType="com.example.demo.entity.UserInfo"
resultMap="userInfoMap">
select * from user_info u
left join user_card uc on u.id=uc.user_id
where u.id = #{id}
</select>
- 测试结果输出
[{
"id": 1,
"name": "张三",
"age": 22,
"userCard": {
"userId": 1,
"card": "111111",
"createTime": "2022-02-17 16:45:01",
"updateTime": "2022-02-17 16:47:21"
},
"userMobileList": null,
"createTime": "2022-02-17 16:45:01",
"updateTime": "2022-02-17 16:47:21"
}]
有个很明显的问题,如果两张表存在相同的字段,mysql查询会自动去掉后者。这种情况需要建立很多的别名来使用
如果这种满足不了需求,还可以用下面这种方法实现
3.2 主键查询实现
通过执行另外一个SQL映射语句来返回预期的复杂类型
- xml代码修改
<resultMap id="userInfoMap" type="com.example.demo.entity.UserInfo">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
//关联查询 property对应实体类中的userCard列
//使用当前id列的值在进行查询 对应的sql查询id selectUserCard
<association property="userCard" column="id" select="selectUserCard">
//下面的映射大同小异
<id property="userId" column="user_id"/>
<result property="card" column="card"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
</association>
</resultMap>
<select id="selectBean" parameterType="com.example.demo.entity.UserInfo"
resultMap="userInfoMap">
select * from user_info where id = #{id}
</select>
//单独的查询,其他业务可以用
<select id="selectUserCard" parameterType="Long" resultType="com.example.demo.entity.UserCard">
select * from user_card where user_id=#{id}
</select>
- 测试结果输出
[{
"id": 1,
"name": "张三",
"age": 22,
"userCard": {
"userId": 1,
"card": "111111",
"createTime": "2022-02-17 16:45:28",
"updateTime": "2022-02-17 16:45:28"
},
"userMobileList": null,
"createTime": "2022-02-17 16:45:01",
"updateTime": "2022-02-17 16:47:21"
}]
结果可以看出,一对一的需求实现了,接下来分析一对多的
3. 一对多数据查询
- xml代码修改
<resultMap id="userInfoMap" type="com.example.demo.entity.UserInfo">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="age" column="age"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
//以id列的值再进行一次查询 sql id为selectUserMobile
<collection property="userMobiles" column="id" select="selectUserMobile">
<id property="userId" column="user_id"/>
<result property="mobile" column="mobile"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
</collection>
</resultMap>
<!--left join user_card uc on u.id=uc.user_id-->
<select id="selectBean" parameterType="com.example.demo.entity.UserInfo"
resultMap="userInfoMap">
select * from user_info u where u.id = #{id}
</select>
<select id="selectUserMobile" parameterType="Long" resultType="com.example.demo.entity.UserMobile">
select * from user_mobile where user_id=#{id}
</select>
- 测试结果输出
[{
"id": 1,
"name": "张三",
"age": 22,
"userCard": null,
"userMobiles": [{
"userId": 1,
"mobile": "13011112223",
"createTime": "2022-02-17 16:45:51",
"updateTime": "2022-02-17 16:47:02"
}, {
"userId": 1,
"mobile": "13011112224",
"createTime": "2022-02-17 16:45:51",
"updateTime": "2022-02-17 16:47:02"
}, {
"userId": 1,
"mobile": "13011112222",
"createTime": "2022-02-17 16:45:51",
"updateTime": "2022-02-17 16:45:51"
}],
"createTime": "2022-02-17 16:45:01",
"updateTime": "2022-02-17 16:47:21"
}]
以上均为作者在项目中所用过的,还想了解其他的用法的自行了解哦
以上就是本章的全部内容了。
上一篇:mybatis第二话 - mybatis,多数据源的快乐你懂吗?
下一篇:mybatis第四话 - 让我们一层一层来剥开mybatis的心,源码分析
及时当勉励,岁月不待人