MyBatis实用用法与技巧总结!

张开发
2026/4/11 21:28:48 15 分钟阅读

分享文章

MyBatis实用用法与技巧总结!
MyBatis是一款非常流行的ORM框架相信很多小伙伴都在使用。我们经常会把它和MyBatis-Plus或者MBG一起使用用多了之后对于其一些常规操作就不太熟悉了。最近总结了下MyBatis的实用用法和技巧希望对大家有所帮助MyBatis简介MyBatis是一款优秀的开源持久层框架支持自定义SQL查询、存储过程和高级映射目前在Github上已有17kStar。在MyBatis中我们可以在XML中编写SQL语句然后绑定到Java方法中通过参数和结果集的自动映射来实现复杂的查询逻辑。MyBatis消除了几乎所有JDBC操作和手动绑定参数操作使用起来非常方便在SpringBoot中集成下面我们来聊聊MyBatis在SpringBoot中的使用首先我们需要集成它。在pom.xml中添加MyBatis提供的Spring Boot Starterdependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version2.2.2/version /dependency然后在application.yml中配置好编写SQL实现的xml文件路径这里我们存放在resources/dao目录下mybatis: mapper-locations: - classpath:dao/*.xml然后添加Java配置通过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模块代码具体项目结构如下。select首先是查询操作这里我们以后台用户表ums_admin为例编写一个根据ID查询用户的方法先创建实体类UmsAdminpublic 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 idselectByIdSimple resultTypecom.macro.mall.tiny.model.UmsAdmin select * from ums_admin where id #{id} /select然后编写测试类注入Dao调用Dao方法来进行测试/** * 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 idselectById resultTypecom.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: trueinsert接下来我们来编写一个插入单个用户的方法/** * 自定义UmsAdmin表查询 * Created by macro on 2022/10/20. */ Repository public interface UmsAdminDao { /** * 插入用户 */ int insert(UmsAdmin entity); }然后在xml中编写对应的SQL实现这里需要注意的是如果想返回插入后的自增ID的话需要使用selectKey标签进行配置。insert idinsert 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 keyColumnid resultTypelong keyPropertyid orderAFTER SELECT LAST_INSERT_ID() /selectKey /insertupdate接下来我们来编写一个根据ID修改用户信息的方法/** * 自定义UmsAdmin表查询 * Created by macro on 2022/10/20. */ Repository public interface UmsAdminDao { /** * 根据ID修改用户信息 */ int updateById(UmsAdmin entity); }然后在xml中编写对应的SQL实现。update idupdateById 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} /updatedelete接下来我们来编写一个根据ID删除用户的方法/** * 自定义UmsAdmin表查询 * Created by macro on 2022/10/20. */ Repository public interface UmsAdminDao { /** * 根据ID删除用户 */ int deleteById(Long id); }然后在xml中编写对应的SQL实现。delete iddeleteById delete from ums_admin where id #{id} /delete动态SQL通过MyBatis的动态SQL功能我们可以灵活地在xml中实现各种复杂的操作动态SQL功能需要依赖MyBatis的各种标签下面我们就来学习下。ifif标签可以实现判断逻辑这里我们以根据用户名和Email模糊查询用户为例来聊聊它的使用/** * 自定义UmsAdmin表查询 * Created by macro on 2022/10/20. */ Repository public interface UmsAdminDao { /** * 根据用户名和Email模糊查询用户 * 不输入查询所有 */ ListUmsAdmin selectByUsernameAndEmailLike(Param(username) String username, Param(email) String email); }xml中添加对应的SQL实现如下。select idselectByUsernameAndEmailLike resultTypecom.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 11 if testusername!null and username! and username like concat(%,#{username},%) /if if testemail!null and email! and email like concat(%,#{email},%) /if /selectchoosechoose标签也可以实现判断逻辑上面的例子中当我们不输入用户名和Email时会查询出全部用户我们如果想不查询出用户可以使用它select idselectByUsernameAndEmailLike2 resultTypecom.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 11 choose when testusername!null and username! and username like concat(%,#{username},%) /when when testemail!null and email! and email like concat(%,#{email},%) /when otherwise and 12 /otherwise /choose /selectwhere上面的例子中我们为了SQL拼接不出错添加了where 11这样的语句其实可以使用where标签来实现查询条件当标签内没有内容时会自动去除where关键字同时还会去除开头多余的and关键字。select idselectByUsernameAndEmailLike3 resultTypecom.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 testusername!null and username! and username like concat(%,#{username},%) /if if testemail!null and email! and email like concat(%,#{email},%) /if /where /selectset当我们拼接更新字段的语句时也会面临同样的问题此时可以使用set标签来解决比如我们现在想写一个根据ID选择性修改用户信息的方法/** * 自定义UmsAdmin表查询 * Created by macro on 2022/10/20. */ Repository public interface UmsAdminDao { /** * 根据ID选择性修改用户信息 */ int updateByIdSelective(UmsAdmin entity); }方法对应的SQL实现如下这里既避免了使用set关键字也会将多余的逗号去除。update idupdateByIdSelective update ums_admin set if testusername!null and username! username #{username}, /if if testpassword!null and password! password #{password}, /if if testicon!null and icon! icon #{icon}, /if if testemail!null and email! email #{email}, /if if testnickName!null and nickName! nick_name #{nickName}, /if if testnote!null and note! note #{note}, /if if testcreateTime!null create_time #{createTime}, /if if testloginTime!null login_time #{loginTime}, /if /set where id #{id} /updateforeach通过foreach我们可以实现一些循环拼接SQL的逻辑例如我们现在需要编写一个批量插入用户的方法/** * 自定义UmsAdmin表查询 * Created by macro on 2022/10/20. */ Repository public interface UmsAdminDao { /** * 批量插入用户 */ int insertBatch(Param(entityList) ListUmsAdmin adminList); }在xml中的对应SQL实现如下在foreach标签中的内容会根据传入的集合参数进行循环拼接insert idinsertBatch insert into ums_admin(username, password, icon, email, nick_name, note, create_time, login_time) values foreach collectionentityList separator, itemitem (#{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批量查询 */ ListUmsAdmin selectByIds(Param(ids) ListLong ids); }在xml中的对应SQL实现如下我们可以使用open、close属性指定拼接语句的前后缀。select idselectByIds resultTypecom.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 collectionids itemitem open( close) separator, #{item} /foreach /select高级查询介绍完MyBatis的基本操作后我们再来介绍下MyBatis的高级查询功能。一对一映射在我们平时进行SQL查询时往往会有一对一的情况比如说我们这里有资源分类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); }在xml中的具体SQL实现如下我们可以通过给ums_resource_category表中字段取以category.xxx的别名来自动进行自动映射select idselectResourceWithCategory resultTypecom.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当然除了这种方式以外我们还可以通过ResultMapassociation标签来实现不过在此之前我们在编写xml文件的时候一般习惯于先给当前文件写一个BaseResultMap用于对当前表的字段和对象属性进行直接映射例如在UmsResourceCategoryDao.xml中这样实现?xml version1.0 encodingUTF-8? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacecom.macro.mall.tiny.dao.UmsResourceCategoryDao resultMap idBaseResultMap typecom.macro.mall.tiny.model.UmsResourceCategory id propertyid columnid/ result propertycreateTime columncreate_time/ result propertyname columnname/ result propertysort columnsort/ /resultMap /mapper在UmsResourceDao.xml中我们可以这样实现?xml version1.0 encodingUTF-8? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacecom.macro.mall.tiny.dao.UmsResourceDao resultMap idBaseResultMap typecom.macro.mall.tiny.model.UmsResource id propertyid columnid/ result propertycreateTime columncreate_time/ result propertyname columnname/ result propertyurl columnurl/ result propertydescription columndescription/ result propertycategoryId columncategory_id/ /resultMap /mapper编写完成后我们的一对一ResultMap实现就很简单了我们可以使用association标签进行一对一管理配置columnPrefix属性将匹配到的字段直接映射到关联对象中去resultMap idResourceWithCategoryMap typecom.macro.mall.tiny.domain.UmsResourceExt extendsBaseResultMap association propertycategory resultMapcom.macro.mall.tiny.dao.UmsResourceCategoryDao.BaseResultMap columnPrefixcategory_/ /resultMap然后再编写下Dao中方法对应SQL实现即可这里直接使用上面的ResultMap同时给ums_resource_category表中的字段指定了category_前缀以便于映射。select idselectResourceWithCategory2 resultMapResourceWithCategoryMap 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一对多映射在编写SQL查询时一对多的情况也比较常见例如这里的分类和资源就是一对多的情况/** * UmsResourceCategory扩展类 * Created by macro on 2022/10/20. */ Data public class UmsResourceCategoryExt extends UmsResourceCategory { private ListUmsResource resourceList; }例如我们现在需要编写一个根据分类ID获取分类及对应资源的方法/** * 自定义UmsResourceCategory表查询 * Created by macro on 2022/10/20. */ Repository public interface UmsResourceCategoryDao { /** * 根据分类ID获取分类及对应资源 */ UmsResourceCategoryExt selectCategoryWithResource(Long id); }在实现具体SQL前我们需要先在xml中配置一个ResultMap通过collection标签建立一对多关系resultMap idselectCategoryWithResourceMap typecom.macro.mall.tiny.domain.UmsResourceCategoryExt extendsBaseResultMap collection propertyresourceList columnPrefixresource_ resultMapcom.macro.mall.tiny.dao.UmsResourceDao.BaseResultMap/ /resultMap然后在xml中编写具体的SQL实现使用该ResultMap。select idselectCategoryWithResource resultMapselectCategoryWithResourceMap 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!--MyBatis分页插件-- dependency groupIdcom.github.pagehelper/groupId artifactIdpagehelper-spring-boot-starter/artifactId version1.4.2/version /dependency然后在查询方法之前使用它的startPage方法传入分页参数即可分页后的得到的数据可以在PageInfo中获取到。/** * UmsResource的Service接口实现类 * Created by macro on 2022/10/20. */ Service public class UmsResourceServiceImpl implements UmsResourceService { Autowired private UmsResourceDao umsResourceDao; Override public PageInfoUmsResource page(Integer pageNum, Integer pageSize,Long categoryId) { PageHelper.startPage(pageNum,pageSize); ListUmsResource resourceList umsResourceDao.selectListByCategoryId(categoryId); PageInfoUmsResource pageInfo new PageInfo(resourceList); return pageInfo; } }总结本文主要介绍了MyBatis中一些比较常规的用法涵盖了SpringBoot集成、基本查询、动态SQL和高级查询建议大家收藏起来在对MyBatis的用法有所遗忘的时候拿出来看看。项目源码地址https://github.com/macrozheng/mall-learning/tree/master/mall-tiny-mybatis

更多文章