Java笔记:SpringBoot整合Mybatis需要注意的一些细节和ResultMap的用法
本文将讲一下SpringBoot整合Mybatis需要注意的一些细节,以及Mybatis中的resultMap结果映射集的用法。
ResultMap结果映射集可以说是mapper中最复杂的一个知识点,在此做个笔记以后可以翻阅,已经会了的朋友可以当做复习,还不会的朋友可以学习学习。
Java笔记:SpringBoot整合Mybatis需要注意的一些细节和ResultMap的用法
SpringBoot整合Mybatis
一、导入Maven依赖,配置参数
POM.xml 依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
<!-- mysql的jdbc驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- druid连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.6</version>
</dependency>
</dependencies>
application.yaml 参数配置:
spring:
#数据库连接
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/DBName?characterEncoding=utf8&useSSL=false&serverTimezone=UTC
username: root
password: root
#druid连接池
druid:
initial-size: 5 #连接池初始化大小
min-idle: 10 #最小空闲连接数
max-active: 20 #最大连接数
web-stat-filter:
exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*" #不统计这些请求数据
stat-view-servlet: #访问监控网页的登录用户名和密码
login-username: druid
login-password: druid
二、包结构和config配置
第一个细节:XXXMapper.java和XXXMapper.xml包路径要一致,即在java包结构src下和在静态资源resources文件下的路径要保持一致。
包结构:
User.java
import java.io.Serializable;
import java.util.Date;
import io.swagger.annotations.ApiModelProperty;
public class User implements Serializable {
@ApiModelProperty(value = "用户ID")
private Integer uId;
@ApiModelProperty(value = "用户名")
private String userName;
...
构造函数
getter/setter/toString...
}
第二个细节:使用Config类来进行一些必要的配置,开启自动扫描,按框架进行命名区分。
MyBatisConfig.java
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* MyBatis配置类,开启扫描
* @author HT
*/
@Configuration
@EnableTransactionManagement
@MapperScan({"com.ht.test.dao","com.ht.test.mapper"})
public class MyBatisConfig {
}
三、创建mapper.java接口,编写mapper.xml查询配置文件
UserMapper.java
import com.ht.test.pojo.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 用户信息自定义查询dao
* @author HT
*/
public interface UserMapper {
int insert(User user);
//批量新增用户
int insertUsers(List<User> users);
int deleteById(int uId);
//Param注解让mapper可以接收多个参数,打破resultType的限制
int updateById(@Param("uId") int uId, @Param("record") User user);
String selectPswByUserName(String userName);
User selectOneByUserName(String userName);
//获取所有用户信息
List<User> selectAllUser();
}
UserMapper.xml,增删改查mapper写法,Mybatis插入自增ID的两种方式
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ht.test.dao.UserMapper">
<resultMap id="users" type="com.ht.test.pojo.User">
<!-- column对应数据库字段,property对应pojo字段-->
<id column="uid" property="uId" javaType="Integer"/>
<result column="username" property="userName"/>
<result column="password" property="password"/>
</resultMap>
<!-- 查询所有用户信息 -->
<select id="selectAllUser" resultMap="users">
select * from User
</select>
<select id="selectOneByUserName" parameterType="String" resultMap="users">
select * from User where userName=#{userName}
</select>
<select id="selectPswByUserName" parameterType="String" resultType="String">
select password from User where userName=#{userName}
</select>
<!-- 新增插入用户信息,自增ID方式一: selectKey-->
<insert id="insert" parameterType="com.ht.test.pojo.User" >
<selectKey keyProperty="uId" order="AFTER" resultType="Integer">
select LAST_INSERT_ID()
</selectKey>
insert into user(uid,username,password)
values(#{uId,jdbcType=INTEGER},
#{userName,jdbcType=VARCHAR},
#{password,jdbcType=VARCHAR},
</insert>
<!-- 批量新增插入用户信息,自增ID方式二:useGeneratedKeys="true" -->
<insert id="insertUsers" parameterType="java.util.List" useGeneratedKeys="true" keyProperty="uId" >
insert into user(uid,username,password)
values
<foreach collection="list" item="item" index="index" separator=",">
(#{item.uId,jdbcType=INTEGER},
#{item.userName,jdbcType=VARCHAR},
#{item.password,jdbcType=VARCHAR},
</foreach>
</insert>
<!-- 根据uid删除用户 -->
<delete id="deleteById" parameterType="Integer" >
delete from user
where uid = #{uId,jdbcType=INTEGER}
</delete>
<!-- 根据uid更新用户信息,判断传入的字段不为null则更新 -->
<update id="updateById">
update user
<set>
<if test="record.userName != null">
username = #{record.userName,jdbcType=VARCHAR},
</if>
<if test="record.password != null">
password = #{record.password,jdbcType=VARCHAR},
</if>
</set>
<if test="uId != null">
where uid = #{uId,jdbcType=INTEGER}
</if>
</update>
</mapper>
~~ ~~
ResultMap的用法
Resultmap可以说是Mybatis中最复杂的元素之一,它描述如何从结果集中加载对象,主要作用是定义映射规则、关联查询、级联的更新、定制类型转化器等。
ResultMap中个参数属性说明
属性 | 说明 |
---|---|
id | 结果集的唯一标识,当需要使用此结果集时根据ID进行使用 |
result | 配置Pojo中字段和数据库字段的映射关系 |
constructor | 子元素(idArg 、arg)。可指定使用具体的某个Pojo实体类的构造函数;若Pojo没有无参构造时,也可以用此方法和其他构造函数关联注入字段值。 |
association | 可表示一对一关联关系 |
collection | 可表示一对多关联关系 |
discriminator | 鉴别器,根据指定条件匹配关联指定的Pojo实体类 |
用上面UserMapper.xml中的配置为例:
<mapper namespace="com.ht.test.dao.UserMapper">
<resultMap id="users" type="com.ht.test.pojo.User">
<id property="uId" column="uid" javaType="Integer" jdbcType="INTEGER"/>
<result column="username" property="userName" javaType="String" jdbcType="VARCHAR"/>
<result column="password" property="password" javaType="String" jdbcType="VARCHAR"/>
</resultMap>
ResultMap中子元素id、result中的各个配置参数说明:
属性 | 说明 |
---|---|
column | 关联的数据库字段 |
property | 关联的Pojo实体类字段 |
javaType | 数据类型、对应类型的Java完整类名;如果你匹配的是一个JavaBean,那MyBatis 通常会自行检测到。但是如果你想要映射到一个HashMap,需要指定javaType 来达到的目的。 |
jdbcType | 数据库中支持的字段类型 |
typeHandler | 使用这个属性可以覆写类型处理器。这项值可以是一个完整的类名,也可以是一个类型别名。 |
常见用法
一般返回受影响的条数(基本数据类型),或者某个对象,可以直接使用参数resultType=“Integer”、Pojo类,一般我们都使用Pojo实体类储存查询结果,Mybatis可以自动关联指定的java类。
若这个类没有涉及关联关系,也可以定义resultMap用来明确字段的关系,也建议每个mapper.xml中应当统一去定义结果集,当其他类需要关联查询时才能有结果集可关联。
一对一关联
我们继续使用User类,然后增加一个People类,人员信息和用户名就行成了一对一的关系。使用 association 进行一对一关联的配置。
public class People implements Serializable {
@ApiModelProperty(value = "人员ID")
private Integer pId;
@ApiModelProperty(value = "人员姓名")
private String pName;
@ApiModelProperty(value = "身份证号")
private String idCard;
@ApiModelProperty(value = "人员的用户信息")
private User user;
...
构造函数
getter/setter/toString...
}
PeopleMapper.xml
<mapper namespace="com.ht.test.dao.PeopleMapper">
<resultMap id="peopleMap" type="com.ht.test.pojo.People">
<id property="pId" column="pid"></id>
<result property="pName" column="pName"/>
<result property="idCard" column="idCard"/>
<result property="address" column="address"/>
<association property="users" column="username" select="com.ht.test.dao.UserMapper.selectOneByUserName"/>
</resultMap>
<select id="selectOnePeopleById" parameterType="Integer" resultMap="People">
SELECT * FROM People WHERE pid = #{pId}
</select>
</mapper>
通过关联处理,其中select元素指定的sql查询,而column则是指定传递给select的参数,是user对象的用户名。当取出User的时候,MyBatis就知道下面的sql取出我们需要的级联信息,对应到我们指定的查询方法中去级联查询。
实际上最终执行了两次Sql,一次是People的查询,一次是User的查询。
一对多关联
使用collection进行一对多的关联。对于多对多关联,为了将实现难度降低,一般分解为双方的一对多关系进行配置。
每个用户会存在多个订单的情况,用户和订单就是一对多的关系。新增一个订单实体类。
public class Order implements Serializable {
@ApiModelProperty(value = "订单id")
private Integer oId;
@ApiModelProperty(value = "订单编号")
private String orderSn;
@ApiModelProperty(value = "订单总金额")
private BigDecimal totalAmount;
...
构造函数
getter/setter/toString...
此处用户Pojo中订单list仅作为进行关联的展示,实际情况中一般是在订单中存用户名或者用户ID,再使用用户信息即可查到对应的多张订单。
public class User implements Serializable {
@ApiModelProperty(value = "用户ID")
private Integer uId;
@ApiModelProperty(value = "用户名")
private String userName;
@ApiModelProperty(value = "用户的订单")
priavte List<Order> orders;
...
构造函数
getter/setter/toString...
}
<mapper namespace="com.ht.test.dao.UserMapper">
<resultMap id="users" type="com.ht.test.pojo.User">
<id property="uId" column="uid" javaType="Integer"/>
<result column="username" property="userName"/>
<result column="password" property="password"/>
<collection property="users" column="oId" select="com.ht.test.dao.OrderMapper.selectOneOrderById"/>
</resultMap>
<select id="selectOneByUserName" parameterType="String" resultMap="users">
SELECT * FROM User WHERE username = #{userName}
</select>
</mapper>
经过collection 的关联,当需要查询订单信息时,Mybatis就会根据关联到订单OrserMapper中拿到关联的指定方法查询订单信息。依然是会发出两条sql语句。
collection 也可以直接作为多对多的表示,例如订单和商品,他们是多对多的关系,因此他们会存在中间表(订单详情表),则多对多可以在详情表中进行表示,如下所示。
<mapper namespace="com.ht.test.dao.OrderDetailDao">
<resultMap id="orderDetailResultMap" type="com.ht.test.dao.OrderDetail">
<collection property="orderItemList" resultMap="com.ht.test.dao.ItemMapper.ItemMap" columnPrefix="item_"/>
<collection property="historyList" resultMap="com.ht.test.dao.OrderMapper.OrderMap" columnPrefix="order_"/>
</resultMap>
</mapper>
鉴别器级联
鉴别器,根据指定条件可以匹配关联指定不同的Pojo实体类。
<resultMap id="orderDetailMapper" type="com.ht.test.dao.OrderDetailDao">
<discriminator javaType="int" column="types">
<case value="1" resultMap="ItemMap"></case>
<case value="2" resultMap="OrderMap"></case>
</discriminator>
</resultMap>
SpringBoot整合Mybatis难度并不大,跟着以上步骤很快就能整合完成,不过只有学会并且用好了 resultMap 结果集才是用好Mybatis的必经之路,多用多练必不可少。