MyBatis是一款非常流行的ORM框架,相信很多小伙伴都在使用。我们经常会把它和MyBatis-Plus或者MBG一起使用,用多了之后对于其一些常规操作就不太熟悉了。最近总结了下MyBatis的实用用法和技巧,希望对大家有所帮助!
SpringBoot实战电商项目mall(50k+star)地址:https://github.com/macrozheng/mall
MyBatis是一款优秀的开源持久层框架,支持自定义SQL查询、存储过程和高级映射,目前在Github上已有17k+Star
。在MyBatis中,我们可以在XML中编写SQL语句,然后绑定到Java方法中,通过参数和结果集的自动映射来实现复杂的查询逻辑。MyBatis消除了几乎所有JDBC操作和手动绑定参数操作,使用起来非常方便!
下面我们来聊聊MyBatis在SpringBoot中的使用,首先我们需要集成它。
pom.xml
中添加MyBatis提供的Spring Boot Starter;<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.2.2version>
dependency>
application.yml
中配置好编写SQL实现的xml
文件路径,这里我们存放在resources/dao
目录下;mybatis:
mapper-locations:
- classpath:dao/*.xml
@MapperScan
配置好Dao接口路径,这样就可以开始使用了。/**
* MyBatis配置类
* Created by macro on 2019/4/8.
*/
@Configuration
@MapperScan("com.macro.mall.tiny.dao")
public class MyBatisConfig {
}
下面我们来聊聊MyBatis的基本使用方法,涵盖了基本的增删改查操作。
这里将以mall项目中权限管理模块相关表为例进行介绍,具体表结构如下。
本文示例使用了mall-learning
项目中的mall-tiny-mybatis
模块代码,具体项目结构如下。
ums_admin
为例,编写一个根据ID查询用户
的方法,先创建实体类UmsAdmin
;public class UmsAdmin implements Serializable {
private Long id;
private String username;
private String password;
@ApiModelProperty(value = "头像")
private String icon;
@ApiModelProperty(value = "邮箱")
private String email;
@ApiModelProperty(value = "昵称")
private String nickName;
@ApiModelProperty(value = "备注信息")
private String note;
@ApiModelProperty(value = "创建时间")
private Date createTime;
@ApiModelProperty(value = "最后登录时间")
private Date loginTime;
@ApiModelProperty(value = "帐号启用状态:0->禁用;1->启用")
private Integer status;
}
UmsAdminDao
,再添加对应的方法;/**
* 自定义UmsAdmin表查询
* Created by macro on 2022/10/20.
*/
@Repository
public interface UmsAdminDao {
/**
* 根据ID查询用户
*/
UmsAdmin selectByIdSimple(Long id);
}
xml
文件UmsAdminDao.xml
,添加查询方法的SQL实现;<select id="selectByIdSimple" resultType="com.macro.mall.tiny.model.UmsAdmin">
select * from ums_admin where id = #{id}
select>
/**
* MyBatis基本操作测试
* Created by macro on 2022/10/20.
*/
@SpringBootTest
public class MyBatisBaseTest {
private static final Logger LOGGER = LoggerFactory.getLogger(MyBatisBaseTest.class);
@Autowired
private UmsAdminDao umsAdminDao;
@Test
void testSelectByIdSimple(){
UmsAdmin umsAdmin = umsAdminDao.selectByIdSimple(1L);
LOGGER.info("testSelectByIdSimple result={}",umsAdmin);
}
}
下划线
分割的返回字段无法自动映射,可以通过对字段取别名的方式来进行映射;<select id="selectById" resultType="com.macro.mall.tiny.model.UmsAdmin">
select username,
password,
icon,
email,
nick_name as nickName,
note,
create_time as createTime,
login_time as loginTime,
status
from ums_admin
where id = #{id}
select>
application.yml
中开启全局下划线自动转驼峰功能来解决,个人习惯使用第一种。mybatis:
configuration:
# 下划线自动转驼峰
map-underscore-to-camel-case: true
插入单个用户
的方法;/**
* 自定义UmsAdmin表查询
* Created by macro on 2022/10/20.
*/
@Repository
public interface UmsAdminDao {
/**
* 插入用户
*/
int insert(UmsAdmin entity);
}
selectKey
标签进行配置。<insert id="insert">
insert into ums_admin(username, password, icon, email, nick_name, note, create_time, login_time)
values (#{username}, #{password}, #{icon}, #{email}, #{nickName}, #{note}, #{createTime}, #{loginTime})
<selectKey keyColumn="id" resultType="long" keyProperty="id" order="AFTER">
SELECT LAST_INSERT_ID()
selectKey>
insert>
根据ID修改用户信息
的方法;/**
* 自定义UmsAdmin表查询
* Created by macro on 2022/10/20.
*/
@Repository
public interface UmsAdminDao {
/**
* 根据ID修改用户信息
*/
int updateById(UmsAdmin entity);
}
<update id="updateById">
update ums_admin
set username = #{username},
password = #{password},
icon = #{icon},
email = #{email},
nick_name = #{nickName},
note = #{note},
create_time = #{createTime},
login_time = #{loginTime}
where id = #{id}
update>
根据ID删除用户
的方法;/**
* 自定义UmsAdmin表查询
* Created by macro on 2022/10/20.
*/
@Repository
public interface UmsAdminDao {
/**
* 根据ID删除用户
*/
int deleteById(Long id);
}
<delete id="deleteById">
delete from ums_admin where id = #{id}
delete>
通过MyBatis的动态SQL功能,我们可以灵活地在xml中实现各种复杂的操作,动态SQL功能需要依赖MyBatis的各种标签,下面我们就来学习下。
if
标签可以实现判断逻辑,这里我们以根据用户名和Email模糊查询用户
为例,来聊聊它的使用;/**
* 自定义UmsAdmin表查询
* Created by macro on 2022/10/20.
*/
@Repository
public interface UmsAdminDao {
/**
* 根据用户名和Email模糊查询用户
* 不输入查询所有
*/
List<UmsAdmin> selectByUsernameAndEmailLike(@Param("username") String username, @Param("email") String email);
}
<select id="selectByUsernameAndEmailLike" resultType="com.macro.mall.tiny.model.UmsAdmin">
select username,
password,
icon,
email,
nick_name as nickName,
note,
create_time as createTime,
login_time as loginTime,
status
from ums_admin
where 1=1
<if test="username!=null and username!=''">
and username like concat('%',#{username},'%')
if>
<if test="email!=null and email!=''">
and email like concat('%',#{email},'%')
if>
select>
choose
标签也可以实现判断逻辑,上面的例子中当我们不输入用户名和Email时,会查询出全部用户,我们如果想不查询出用户,可以使用它;<select id="selectByUsernameAndEmailLike2" resultType="com.macro.mall.tiny.model.UmsAdmin">
select username,
password,
icon,
email,
nick_name as nickName,
note,
create_time as createTime,
login_time as loginTime,
status
from ums_admin
where 1=1
<choose>
<when test="username!=null and username!=''">
and username like concat('%',#{username},'%')
when>
<when test="email!=null and email!=''">
and email like concat('%',#{email},'%')
when>
<otherwise>
and 1=2
otherwise>
choose>
select>
where 1=1
这样的语句,其实可以使用where
标签来实现查询条件,当标签内没有内容时会自动去除where
关键字,同时还会去除开头多余的and
关键字。<select id="selectByUsernameAndEmailLike3" resultType="com.macro.mall.tiny.model.UmsAdmin">
select username,
password,
icon,
email,
nick_name as nickName,
note,
create_time as createTime,
login_time as loginTime,
status
from ums_admin
<where>
<if test="username!=null and username!=''">
and username like concat('%',#{username},'%')
if>
<if test="email!=null and email!=''">
and email like concat('%',#{email},'%')
if>
where>
select>
set
标签来解决,比如我们现在想写一个根据ID选择性修改用户信息
的方法;/**
* 自定义UmsAdmin表查询
* Created by macro on 2022/10/20.
*/
@Repository
public interface UmsAdminDao {
/**
* 根据ID选择性修改用户信息
*/
int updateByIdSelective(UmsAdmin entity);
}
set
关键字,也会将多余的逗号去除。<update id="updateByIdSelective">
update ums_admin
<set>
<if test="username!=null and username!=''">
username = #{username},
if>
<if test="password!=null and password!=''">
password = #{password},
if>
<if test="icon!=null and icon!=''">
icon = #{icon},
if>
<if test="email!=null and email!=''">
email = #{email},
if>
<if test="nickName!=null and nickName!=''">
nick_name = #{nickName},
if>
<if test="note!=null and note!=''">
note = #{note},
if>
<if test="createTime!=null">
create_time = #{createTime},
if>
<if test="loginTime!=null">
login_time = #{loginTime},
if>
set>
where id = #{id}
update>
foreach
我们可以实现一些循环拼接SQL的逻辑,例如我们现在需要编写一个批量插入用户
的方法;/**
* 自定义UmsAdmin表查询
* Created by macro on 2022/10/20.
*/
@Repository
public interface UmsAdminDao {
/**
* 批量插入用户
*/
int insertBatch(@Param("entityList") List<UmsAdmin> adminList);
}
foreach
标签中的内容会根据传入的集合参数进行循环拼接;<insert id="insertBatch">
insert into ums_admin(username, password, icon, email, nick_name, note, create_time, login_time) values
<foreach collection="entityList" separator="," item="item">
(#{item.username}, #{item.password}, #{item.icon}, #{item.email}, #{item.nickName}, #{item.note}, #{item.createTime}, #{item.loginTime})
foreach>
insert>
根据用户ID批量查询
的方法;/**
* 自定义UmsAdmin表查询
* Created by macro on 2022/10/20.
*/
@Repository
public interface UmsAdminDao {
/**
* 根据用户ID批量查询
*/
List<UmsAdmin> selectByIds(@Param("ids") List<Long> ids);
}
open
、close
属性指定拼接语句的前后缀。<select id="selectByIds" resultType="com.macro.mall.tiny.model.UmsAdmin">
select username,
password,
icon,
email,
nick_name as nickName,
note,
create_time as createTime,
login_time as loginTime,
status
from ums_admin
where id in
<foreach collection="ids" item="item" open="(" close=")" separator=",">
#{item}
foreach>
select>
介绍完MyBatis的基本操作后,我们再来介绍下MyBatis的高级查询功能。
一对一
的情况,比如说我们这里有资源分类ums_resource_category
和资源ums_resource
两张表,资源和分类就是一对一的关系,如果你不想改动原实体类的话,可以编写一个扩展类继承UmsResource
,并包含UmsResourceCategory
属性;/**
* UmsResource扩展类
* Created by macro on 2022/10/20.
*/
@Data
public class UmsResourceExt extends UmsResource {
private UmsResourceCategory category;
}
根据资源ID获取资源及分类信息
的方法;/**
* 自定义UmsResource表查询
* Created by macro on 2022/10/20.
*/
@Repository
public interface UmsResourceDao {
/**
* 根据资源ID获取资源及分类信息
*/
UmsResourceExt selectResourceWithCategory(Long id);
}
ums_resource_category
表中字段取以category.xxx
的别名来自动进行自动映射;<select id="selectResourceWithCategory" resultType="com.macro.mall.tiny.domain.UmsResourceExt">
select ur.id,
ur.create_time as createTime,
ur.name,
ur.url,
ur.description,
ur.category_id as categoryId,
urc.id as "category.id",
urc.name as "category.name",
urc.sort as "category.sort",
urc.create_time as "category.createTime"
from ums_resource ur
left join ums_resource_category urc on ur.category_id = urc.id
where ur.id = #{id}
select>
ResultMap
+association
标签来实现,不过在此之前我们在编写xml文件的时候,一般习惯于先给当前文件写一个BaseResultMap
,用于对当前表的字段和对象属性进行直接映射,例如在UmsResourceCategoryDao.xml
中这样实现;
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.macro.mall.tiny.dao.UmsResourceCategoryDao">
<resultMap id="BaseResultMap" type="com.macro.mall.tiny.model.UmsResourceCategory">
<id property="id" column="id"/>
<result property="createTime" column="create_time"/>
<result property="name" column="name"/>
<result property="sort" column="sort"/>
resultMap>
mapper>
UmsResourceDao.xml
中我们可以这样实现;
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.macro.mall.tiny.dao.UmsResourceDao">
<resultMap id="BaseResultMap" type="com.macro.mall.tiny.model.UmsResource">
<id property="id" column="id"/>
<result property="createTime" column="create_time"/>
<result property="name" column="name"/>
<result property="url" column="url"/>
<result property="description" column="description"/>
<result property="categoryId" column="category_id"/>
resultMap>
mapper>
ResultMap
实现就很简单了,我们可以使用association
标签进行一对一管理,配置columnPrefix
属性将匹配到的字段直接映射到关联对象中去;<resultMap id="ResourceWithCategoryMap" type="com.macro.mall.tiny.domain.UmsResourceExt" extends="BaseResultMap">
<association property="category" resultMap="com.macro.mall.tiny.dao.UmsResourceCategoryDao.BaseResultMap" columnPrefix="category_"/>
resultMap>
ums_resource_category
表中的字段指定了category_
前缀以便于映射。<select id="selectResourceWithCategory2" resultMap="ResourceWithCategoryMap">
select ur.id,
ur.create_time,
ur.name,
ur.url,
ur.description,
ur.category_id,
urc.id as category_id,
urc.name as category_name,
urc.sort as category_sort,
urc.create_time as category_create_time
from ums_resource ur
left join ums_resource_category urc on ur.category_id = urc.id
where ur.id = #{id}
select>
/**
* UmsResourceCategory扩展类
* Created by macro on 2022/10/20.
*/
@Data
public class UmsResourceCategoryExt extends UmsResourceCategory {
private List<UmsResource> resourceList;
}
根据分类ID获取分类及对应资源
的方法;/**
* 自定义UmsResourceCategory表查询
* Created by macro on 2022/10/20.
*/
@Repository
public interface UmsResourceCategoryDao {
/**
* 根据分类ID获取分类及对应资源
*/
UmsResourceCategoryExt selectCategoryWithResource(Long id);
}
collection
标签建立一对多关系;<resultMap id="selectCategoryWithResourceMap" type="com.macro.mall.tiny.domain.UmsResourceCategoryExt" extends="BaseResultMap">
<collection property="resourceList" columnPrefix="resource_" resultMap="com.macro.mall.tiny.dao.UmsResourceDao.BaseResultMap"/>
resultMap>
<select id="selectCategoryWithResource" resultMap="selectCategoryWithResourceMap">
select urc.id,
urc.create_time,
urc.name,
urc.sort,
ur.id resource_id,
ur.create_time resource_create_time,
ur.name resource_name,
ur.url resource_url,
ur.description resource_description,
ur.category_id resource_category_id
from ums_resource_category urc
left join ums_resource ur on urc.id = ur.category_id
where urc.id = #{id}
select>
PageHelper
插件即可,首先在pom.xml
中添加它的Starter;
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelper-spring-boot-starterartifactId>
<version>1.4.2version>
dependency>
startPage
方法传入分页参数即可,分页后的得到的数据可以在PageInfo
中获取到。/**
* UmsResource的Service接口实现类
* Created by macro on 2022/10/20.
*/
@Service
public class UmsResourceServiceImpl implements UmsResourceService {
@Autowired
private UmsResourceDao umsResourceDao;
@Override
public PageInfo<UmsResource> page(Integer pageNum, Integer pageSize,Long categoryId) {
PageHelper.startPage(pageNum,pageSize);
List<UmsResource> resourceList = umsResourceDao.selectListByCategoryId(categoryId);
PageInfo<UmsResource> pageInfo = new PageInfo<>(resourceList);
return pageInfo;
}
}
本文主要介绍了MyBatis中一些比较常规的用法,涵盖了SpringBoot集成、基本查询、动态SQL和高级查询,建议大家收藏起来,在对MyBatis的用法有所遗忘的时候拿出来看看。
https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-mybatis