MyBatis-Plus
MyBatis-Plus(简称 MP)是一个 MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
官方文档地址:https://mybatis.plus/guide/
环境介绍
环境要素 | 版本 |
---|---|
maven | 3.3.3 |
jdk | 1.8.0_1.81 |
编译 | idea |
springboot | 2.1.7.RELEASE |
系统 | win10 |
快速开始
添加依赖
pom.xml中引入以下的包
<!--mybatis plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.17</version>
<scope>runtime</scope>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</dependency>
<!--spring web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.1.7.RELEASE</version>
</dependency>
<!--测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.1.7.RELEASE</version>
<scope>test</scope>
</dependency>
配置
在application.properties中添加数据库配置
spring.datasource.driverClassName = com.mysql.cj.jdbc.Driver
spring.datasource.url = jdbc:mysql://localhost:3306/db_demo?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
spring.datasource.username = root
spring.datasource.password = 123456
在数据库造点东西
CREATE TABLE `tb_sys_role` (
`id` bigint(1) UNSIGNED ZEROFILL NOT NULL AUTO_INCREMENT,
`name` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`description` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `id`(`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Compact;
-- ----------------------------
-- Records of tb_sys_role
-- ----------------------------
INSERT INTO `tb_sys_role` VALUES (1, '管理员', '一切皆可管');
在springboot项目启动类DemoApplication中,添加 @MapperScan
注解,扫描 Mapper 文件夹:
@SpringBootApplication(scanBasePackages = "com.smart.demo.*")
@MapperScan("com.smart.demo.dao.mapper")
public class SmartStreetApplication {
public static void main(String[] args) {
SpringApplication.run(SmartStreetApplication.class, args);
}
}
编码
编写一个实体类TbSysRole(使用lombok简化代码)
@Data
public class TbSysRole {
private Long id;
private String name;
private String description;
}
编写一个Mapper类,在上面的com.smart.demo.dao.mapper包下
public interface SysRoleMapper extends BaseMapper<TbSysRole> {
}
开始使用
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SmartDemoApplication.class)
public class SampleTest {
@Resource
private SysRoleMapper roleMapper;
@Test
public void testRole() {
System.out.println(("----- selectAll method test ------"));
List<TbSysRole> list = roleMapper.selectList(null);
Assert.assertEquals(1, list.size());
}
}
小结
通过以上几个简单的步骤,我们就实现了 User 表的 CRUD 功能。
从以上步骤中,我们可以看到集成 MyBatis-Plus 非常的简单,只需要引入 starter 工程,并配置 mapper 扫描路径即可。
我那个擦,都不用xml 了,像JPA的调用一样丝滑。
下面介绍MP的具体使用方式
Mapper CRUD 接口
MP 封装通用的CRUD的接口BaseMapper;启动时自动解析实体表关系映射转换为 Mybatis
内部对象注入到容器
使用实例
定义Mapper接口继承BaseMapper
public interface SysRoleMapper extends BaseMapper<TbSysRole> {
}
定义实体类
@Data
public class TbSysRole {
private Long id;
private String name;
private String description;
}
测试用例
@Test
public void testMapper() {
TbSysRole r = new TbSysRole();
r.setName("aa");
roleMapper.insert(r);
QueryWrapper<TbSysRole> query = Wrappers.query();
query.eq("name","aa");
TbSysRole role= roleMapper.selectOne(query);
Map<String,Object > map=new HashMap<>();
map.put("name",role.getName());
roleMapper.deleteByMap(map);
roleMapper.insert(r);
roleMapper.delete(query);
List<Long> ids=new ArrayList<>();
ids.add(2L);
ids.add(3L);
roleMapper.deleteBatchIds(ids);
}
测试用例
@Resource
private SysRoleMapper roleMapper;
@Test
public void testRole() {
System.out.println(("----- selectAll method test ------"));
List<TbSysRole> list = roleMapper.selectList(null);
Assert.assertEquals(1, list.size());
}
庐山面目
实体类的Mapper 继承BaseMapper 。其中泛型 T 为实体类;Wrapper 条件构造器
public interface BaseMapper<T> extends Mapper<T> {
//插入一条记录
int insert(T entity);
//删除
int deleteById(Serializable id);
int deleteByMap(@Param("cm") Map<String, Object> columnMap);
int delete(@Param("ew") Wrapper<T> wrapper);
int deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList);
//更新
int updateById(@Param("et") T entity);
int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);
//查询
T selectById(Serializable id);
List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);
List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);
T selectOne(@Param("ew") Wrapper<T> queryWrapper);
Integer selectCount(@Param("ew") Wrapper<T> queryWrapper);
List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);
List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);
List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);
//分页
IPage<T> selectPage(IPage<T> page, @Param("ew") Wrapper<T> queryWrapper);
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param("ew") Wrapper<T> queryWrapper);
}
Service CRUD接口
mybatis-plus 进一步封装了CRUD方法, 封装的接口为IService,实现类为ServiceImpl,当然为了避免和Mapper层的混淆,方法的命名有些改变。
命名区别
Mapper | Service |
---|---|
insert | save/saveBatch/saveOrUpdateBatch |
delete | remove |
update | 一样/updateBatchById |
select | get |
selectPage | page |
selectList | listBy |
庐山面目
public interface IService<T> {
boolean save(T entity);
@Transactional(
rollbackFor = {Exception.class}
)
default boolean saveBatch(Collection<T> entityList) {
return this.saveBatch(entityList, 1000);
}
boolean saveBatch(Collection<T> entityList, int batchSize);
@Transactional(
rollbackFor = {Exception.class}
)
default boolean saveOrUpdateBatch(Collection<T> entityList) {
return this.saveOrUpdateBatch(entityList, 1000);
}
boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);
boolean removeById(Serializable id);
boolean removeByMap(Map<String, Object> columnMap);
boolean remove(Wrapper<T> queryWrapper);
boolean removeByIds(Collection<? extends Serializable> idList);
boolean updateById(T entity);
boolean update(T entity, Wrapper<T> updateWrapper);
default boolean update(Wrapper<T> updateWrapper) {
return this.update((Object)null, updateWrapper);
}
@Transactional(
rollbackFor = {Exception.class}
)
default boolean updateBatchById(Collection<T> entityList) {
return this.updateBatchById(entityList, 1000);
}
boolean updateBatchById(Collection<T> entityList, int batchSize);
boolean saveOrUpdate(T entity);
T getById(Serializable id);
Collection<T> listByIds(Collection<? extends Serializable> idList);
Collection<T> listByMap(Map<String, Object> columnMap);
default T getOne(Wrapper<T> queryWrapper) {
return this.getOne(queryWrapper, true);
}
T getOne(Wrapper<T> queryWrapper, boolean throwEx);
Map<String, Object> getMap(Wrapper<T> queryWrapper);
<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
int count(Wrapper<T> queryWrapper);
default int count() {
return this.count(Wrappers.emptyWrapper());
}
List<T> list(Wrapper<T> queryWrapper);
default List<T> list() {
return this.list(Wrappers.emptyWrapper());
}
IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);
default IPage<T> page(IPage<T> page) {
return this.page(page, Wrappers.emptyWrapper());
}
List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);
default List<Map<String, Object>> listMaps() {
return this.listMaps(Wrappers.emptyWrapper());
}
default List<Object> listObjs() {
return this.listObjs(Function.identity());
}
default <V> List<V> listObjs(Function<? super Object, V> mapper) {
return this.listObjs(Wrappers.emptyWrapper(), mapper);
}
default List<Object> listObjs(Wrapper<T> queryWrapper) {
return this.listObjs(queryWrapper, Function.identity());
}
<V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
IPage<Map<String, Object>> pageMaps(IPage<T> page, Wrapper<T> queryWrapper);
default IPage<Map<String, Object>> pageMaps(IPage<T> page) {
return this.pageMaps(page, Wrappers.emptyWrapper());
}
BaseMapper<T> getBaseMapper();
default QueryChainWrapper<T> query() {
return new QueryChainWrapper(this.getBaseMapper());
}
default LambdaQueryChainWrapper<T> lambdaQuery() {
return new LambdaQueryChainWrapper(this.getBaseMapper());
}
default UpdateChainWrapper<T> update() {
return new UpdateChainWrapper(this.getBaseMapper());
}
default LambdaUpdateChainWrapper<T> lambdaUpdate() {
return new LambdaUpdateChainWrapper(this.getBaseMapper());
}
default boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper) {
return this.update(entity, updateWrapper) || this.saveOrUpdate(entity);
}
}
使用实例
定义mapper
public interface SysUserMapper extends BaseMapper<TbSysUser> {
}
业务Service
public interface ISysUserService {
List<TbSysUser> queryUser();
List<TbSysUser> queryUser(Long userId);
}
业务Service实现
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, TbSysUser> implements ISysUserService {
@Resource
private SysUserMapper userMapper;
@Override
public List<TbSysUser> queryUser() {
List<TbSysUser> userList = userMapper.selectList(null);
return userList;
}
@Override
public TbSysUser queryUserById(Long userId) {
return getById(userId);
}
}
测试用例
@Autowired
private ISysUserService sysUserService;
@Test
public void test(){
TbSysUser user=sysUserService.queryUserById(1L);
System.out.println(user);
}
条件构造器
前面你肯定已经看到到一些以前没见过的东西 ,例如下面。这就是要说的条件构造器
QueryWrapper<TbSysRole> query = Wrappers.query();
条件构造器的父类是AbstractWrapper,它有两个实现类:QueryWrapper和UpdateWrapper 。它的主要作用是用于生成 sql 的 where 条件。
下面这些方法都是2个实现类公用的。
allEq 多条件
- 方法
allEq(Map<R, V> params) = allEq(true, map, true)
allEq(Map<R, V> params, boolean null2IsNull) = allEq(true,map,null2IsNull)
allEq(boolean condition, Map<R, V> params, boolean null2IsNull)
params : key为数据库字段名,value为字段值
null2IsNull :默认true,为true则在map的value为null时调用 isNull 方法,为false时则忽略value为null的条件
condition:是否执行条件,默认true
-
示例
模拟数据有:
id name description 1 管理员 一切皆可管 2 Null 测试 3 aaa AAAA /** * query.allEq(map);多参数查询 * allEq({name:null,description:"一切皆可管"})--->where name is null and description="一切皆可管" */ @Test public void testWrapper() { QueryWrapper<TbSysRole> query = Wrappers.query(); Map<String, Object> map = new HashMap<>(); map.put("name","管理员"); map.put("description","一切皆可管"); query.allEq(map); List<TbSysRole> list= roleMapper.selectList(query); Assert.assertEquals(1,list.size()); } /** * query.allEq(map,true)相当于allEq(map) ;默认值就是true * 生成的相当于 name is null,查询属性值为null的记录 * allEq({id:1,name:null})--->where id = 1 and name is null */ @Test public void testWrapper2() { QueryWrapper<TbSysRole> query = Wrappers.query(); Map<String, Object> map = new HashMap<>(); map.put("name",null); query.allEq(map,true); List<TbSysRole> list2= roleMapper.selectList(query); Assert.assertEquals(1,list2.size()); } /** * query.allEq(map,false);忽略value=null的条件 * 相当于不要这个为null的条件 * allEq({id:1,name:null})--->where id = 1 */ @Test public void testWrapper3() { QueryWrapper<TbSysRole> query = Wrappers.query(); Map<String, Object> map = new HashMap<>(); map.put("name",null); query.allEq(map,false); List<TbSysRole> list3= roleMapper.selectList(query); Assert.assertEquals(3,list3.size()); } /** * allEq(false,map,null2IsNull) * 第一个参数代表是否执行这些条件,false相当于没传条件 */ @Test public void testWrapper4() { QueryWrapper<TbSysRole> query = Wrappers.query(); Map<String, Object> map = new HashMap<>(); map.put("name","管理员"); map.put("description","一切皆可管"); query.allEq(false,map,true); List<TbSysRole> list= roleMapper.selectList(query); Assert.assertEquals(3,list.size()); }
-
方法
allEq(BiPredicate<R, V> filter, Map<R, V> params) = allEq(true, filter, params, null2IsNull); allEq(BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull) allEq(boolean condition, BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull)
-
示例
/** * allEq(filter, map); * 相当于只传入满足过滤器的条件,其他条件都跳过 */ @Test public void testWrapper4() { QueryWrapper<TbSysRole> query = Wrappers.query(); Map<String, Object> map = new HashMap<>(); map.put("name","管理员"); query.allEq((k,v) -> v.toString().indexOf("员") >= 0,map); List<TbSysRole> list3= roleMapper.selectList(query); Assert.assertEquals(1,list3.size()); }
eq 等于
- 方法
eq(R column, Object val)
eq(boolean condition, R column, Object val)
相当于“=”
column :列名
val:值
condition:是否执行条件
-
示例
/* * eq(R column, Object val); * Eq({name:"管理员"})--->where name "管理员" */ @Test public void testWrapper6() { QueryWrapper<TbSysRole> query = Wrappers.query(); query.eq("name","管理员"); List<TbSysRole> list3= roleMapper.selectList(query); Assert.assertEquals(1,list3.size()); } /* * eq(condition,column,val); * 相当于没有传递任何条件 */ @Test public void testWrapper7() { QueryWrapper<TbSysRole> query = Wrappers.query(); query.eq(false,"name","管理员"); List<TbSysRole> list3= roleMapper.selectList(query); Assert.assertEquals(3,list3.size()); }
ne 不等于
- 方法
ne(R column, Object val) = ne(true, column,val)
ne(boolean condition, R column, Object val)
相当于不等于<>
column :列名
val:值
condition:是否执行条件
-
代码
/** * ne("name","1");查询name不等于1,(mysql默认会排除name=null的数据) * 相当于where name <>'1' */ @Test public void testWrapper8() { QueryWrapper<TbSysRole> query = Wrappers.query(); query.ne("name","1"); List<TbSysRole> list3= roleMapper.selectList(query); Assert.assertEquals(2,list3.size()); } /** * ne(true,"name","1")相当于query.ne("name","1"),默认值就是true * 查询name不等于1,(mysql默认会排除name=null的数据) * 相当于where name <>'1' */ @Test public void testWrapper9() { QueryWrapper<TbSysRole> query = Wrappers.query(); query.ne(true,"name","1"); List<TbSysRole> list3= roleMapper.selectList(query); Assert.assertEquals(2,list3.size()); } /** * ne("name","1");查询name不等于1,(mysql默认会排除name=null的数据) * 相当于 没有where */ @Test public void testWrapper10() { QueryWrapper<TbSysRole> query = Wrappers.query(); query.ne(false,"name","1"); List<TbSysRole> list3= roleMapper.selectList(query); Assert.assertEquals(3,list3.size()); }
gt 大于
-
方法
gt(R column, Object val) gt(boolean condition, R column, Object val)
-
例子
ge("age", 18)
--->
age > 18
ge 大于等于
-
方法
ge(R column, Object val) ge(boolean condition, R column, Object val)
-
例子
lt("age", 18)
--->
age >= 18
lt 小于
-
方法
lt(R column, Object val) lt(boolean condition, R column, Object val)
-
例子
lt("age", 18)
--->
age < 18
le 小于等于
-
方法
le(R column, Object val) le(boolean condition, R column, Object val)
-
例子
lt("age", 18)
--->
age <= 18
between
-
方法
between(R column, Object val1, Object val2) between(boolean condition, R column, Object val1, Object val2)
-
例子
between("age", 18, 30)
--->
age between 18 and 30
notBetween
- 方法
notBetween(R column, Object val1, Object val2)
notBetween(boolean condition, R column, Object val1, Object val2)
-
例子
notBetween("age", 18, 30)
--->
age not between 18 and 30
notBetween
- 方法
notBetween(R column, Object val1, Object val2)
notBetween(boolean condition, R column, Object val1, Object val2)
-
例子
notBetween("age", 18, 30)
--->
age not between 18 and 30
like
- 方法
like(R column, Object val)
like(boolean condition, R column, Object val)
-
例子
like("name", "王")
--->
name like '%王%'
notLike
- 方法
notLike(R column, Object val)
notLike(boolean condition, R column, Object val)
-
例子
notLike("name", "王")
--->
name not like '%王%'
其他
方法名 | 方法 | 实例 |
---|---|---|
likeLeft | likeLeft(R column, Object val) likeLeft(boolean condition, R column, Object val) | likeLeft("name", "王")---> name like '%王' |
likeRight | likeRight(R column, Object val) likeRight(boolean condition, R column, Object val) | likeRight("name", "王")---> name like '王%' |
isNull | isNull(R column) isNull(boolean condition, R column) | isNull("name")---> name is null |
isNotNull | isNotNull(R column) isNotNull(boolean condition, R column) | isNotNull("name")---> name is not null |
in | in(R column, Collection<?> value) in(boolean condition, R column, Collection<?> value) | in("age",{1,2,3})---> age in (1,2,3) |
notIn | notIn(R column, Collection<?> value) notIn(boolean condition, R column, Collection<?> value) | notIn("age",{1,2,3})---> age not in (1,2,3) |
还有很多,可以去看官网
QueryWrapper
select
-
方法
select(String... sqlSelect) select(Predicate<TableFieldInfo> predicate) select(Class<T> entityClass, Predicate<TableFieldInfo> predicate)
-
代码
/** * 查询id=1, 且返回集中只有id,name **/ @Test public void testWrapper12() { QueryWrapper<TbSysRole> query = Wrappers.query(); query.select("id","name"); query.eq("id",1); List<TbSysRole> list3= roleMapper.selectList(query); Assert.assertEquals(1,list3.size()); }
UpdateWrapper
set
- 方法
set(String column, Object val)
set(boolean condition, String column, Object val)
-
代码
@Test public void testWrapper13() { UpdateWrapper<TbSysRole> updateWrapper=Wrappers.update(); updateWrapper.eq("id",3); updateWrapper.set("name","AA1A"); roleMapper.update(null,updateWrapper); }
setSql
- 方法
setSql(String sql)
-
代码
@Test public void testWrapper15() { UpdateWrapper<TbSysRole> updateWrapper=Wrappers.update(); updateWrapper.eq("id",3); updateWrapper.setSql("name='小妹妹'"); roleMapper.update(null,updateWrapper); }
自定义sql
注解方式
public interface SysRoleMapper extends BaseMapper<TbSysRole> {
/**
* 第一种方法:注解方式,不使用MP的Wrapper条件构造器
*和Mybatis使用方法一致
* @param id
* @return
*/
@Select("select * from tb_sys_role where id= #{id}")
TbSysRole findOneRole(Long id);
/**
* 第一种方法:注解方式,如果自定义的方法还希望能够使用MP提供的Wrapper条件构造器,则需要如下写法
*
* @param roleWrapper
* @return
*/
@Select("SELECT * FROM tb_sys_role ${ew.customSqlSegment}")
TbSysRole selectByMyWrapper(@Param(Constants.WRAPPER) Wrapper<TbSysRole> roleWrapper);
}
@Test
public void testWrapper16() {
TbSysRole R= roleMapper.findOneRole(1L);
System.out.println(R.getName());
}
@Test
public void testWrapper17() {
QueryWrapper<TbSysRole> query = Wrappers.query();
query.eq("id",1);
TbSysRole r=roleMapper.selectByMyWrapper(query);
System.out.println(r.getName());
}
xml 方式
Mapper接口
package com.smart.street.dao.mapper;
public interface SysUserMapper extends BaseMapper<TbSysUser> {
/**
* 和Mybatis使用方法一致
*
* @param id
* @return
*/
TbSysUser findOneUser(Long id);
/**
* 如果自定义的方法还希望能够使用MP提供的Wrapper条件构造器,则需要如下写法
*
* @param userWrapper
* @return
*/
TbSysUser selectByMyWrapper(@Param(Constants.WRAPPER) Wrapper<TbSysUser> userWrapper);
}
xml 放在resources下的com.smart.street.dao.mapper目录中,一定要和上面的Mapper接口目录结构一致且文件名和Mapper名字一致
<?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.smart.street.dao.mapper.SysUserMapper">
<select id="findOneUser" resultType="com.smart.street.dao.entity.TbSysUser">
SELECT * FROM tb_sys_user where id = #{id}
</select>
<select id="selectByMyWrapper" resultType="com.smart.street.dao.entity.TbSysUser">
SELECT * FROM tb_sys_user ${ew.customSqlSegment}
</select>
</mapper>
配置文件application.properties中添加
mybatis-plus.mapper-locations= classpath:com.smart.street.dao.mapper/*.xml
测试用例
@Test
public void testWrapper18() {
TbSysUser u= userMapper.findOneUser(1L);
System.out.println(u.getUserName());
}
@Test
public void testWrapper19() {
QueryWrapper<TbSysUser> query = Wrappers.query();
query.eq("id",1);
TbSysUser u= userMapper.selectByMyWrapper(query);
System.out.println(u.getUserName());
}