如下教程学习自尚硅谷杨博超老师的MyBatis-Plus教程
增删改查
1.BaseMapper<T>
说明:
- 通用 CRUD 封装BaseMapper 接口,为
Mybatis-Plus
启动时自动解析实体表关系映射转换为 Mybatis
内部对象注入容器 - 泛型
T
为任意实体对象 - 参数
Serializable
为任意类型主键 Mybatis-Plus
不推荐使用复合主键约定每一张表都有自己的唯一 id
主键 - 对象
Wrapper
为条件构造器
MyBatis-Plus中的基本CRUD在内置的BaseMapper中都已得到了实现,因此我们继承该接口以后可以直接使用。
本次演示的CRUD操作不包含参数带有条件构造器的方法,关于条件构造器将单独在一个章节进行演示。
BaseMapper中提供的CRUD方法:
增加:Insert
删除:Delete
1 2 3 4 5 6 7 8
| int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
int deleteById(Serializable id);
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
|
修改:Update
1 2 3 4
| int update(@Param(Constants.ENTITY) T updateEntity, @Param(Constants.WRAPPER) Wrapper<T> whereWrapper);
int updateById(@Param(Constants.ENTITY) T entity);
|
查询:Selete
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| T selectById(Serializable id);
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
|
2.调用Mapper层实现CRUD
2.1 插入
最终执行的结果,所获取的id为1527206783590903810
这是因为MyBatis-Plus在实现插入数据时,会默认基于雪花算法的策略生成id
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
@Test public void testInsert(){ User user = new User(); user.setName("Vz"); user.setAge(21); user.setEmail("vz@oz6.cn"); int result = userMapper.insert(user); System.out.println(result > 0 ? "添加成功!" : "添加失败!"); System.out.println("受影响的行数为:" + result); System.out.println("id自动获取" + user.getId()); }
|
2.2 删除
a、根据ID删除数据
调用方法:int deleteById(Serializable id);
1 2 3 4 5 6 7 8 9
|
@Test public void testDeleteById(){ int result = userMapper.deleteById(1527206783590903810L); System.out.println(result > 0 ? "删除成功!" : "删除失败!"); System.out.println("受影响的行数为:" + result); }
|
b、根据ID批量删除数据
调用方法:int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
1 2 3 4 5 6 7 8 9 10
|
@Test public void testDeleteBatchIds(){ List<Long> ids = Arrays.asList(6L,7L,8L); int result = userMapper.deleteBatchIds(ids); System.out.println(result > 0 ? "删除成功!" : "删除失败!"); System.out.println("受影响的行数为:" + result); }
|
c、根据Map条件删除数据
调用方法:int deleteByMap(@Param(Constants.COLUMN_MAP) Map columnMap);
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
@Test public void testDeleteByMap(){ Map<String,Object> map = new HashMap<>(); map.put("name","Vz"); map.put("age",21); int result = userMapper.deleteByMap(map); System.out.println(result > 0 ? "删除成功!" : "删除失败!"); System.out.println("受影响的行数为:" + result); }
|
2.3 修改
调用方法:int updateById(@Param(Constants.ENTITY) T entity);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
@Test public void testUpdateById(){ User user = new User(); user.setId(6L); user.setName("VzUpdate"); user.setAge(18); user.setEmail("Vz@sina.com"); int result = userMapper.updateById(user); System.out.println(result > 0 ? "修改成功!" : "修改失败!"); System.out.println("受影响的行数为:" + result); }
|
2.4 查询
a、根据ID查询用户信息
调用方法:T selectById(Serializable id);
1 2 3 4 5 6 7 8
|
@Test public void testSelectById(){ User user = userMapper.selectById(1L); System.out.println(user); }
|
b、根据多个ID查询多个用户信息
调用方法:List selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
1 2 3 4 5 6 7 8 9 10
|
@Test public void testSelectBatchIds(){ List<Long> ids = Arrays.asList(1L,2L,3L); List<User> users = userMapper.selectBatchIds(ids); users.forEach(System.out::println); }
|
c、根据Map条件查询用户信息
调用方法:List selectByMap(@Param(Constants.COLUMN_MAP) Map columnMap);
1 2 3 4 5 6 7 8 9 10 11
|
@Test public void testSelectByMap(){ Map<String,Object> map = new HashMap<>(); map.put("age",18); List<User> users = userMapper.selectByMap(map); users.forEach(System.out::println); }
|
d、查询所有用户信息
调用方法:List selectList(@Param(Constants.WRAPPER) Wrapper queryWrapper);
1 2 3 4 5 6 7 8
|
@Test void testSelectList(){ List<User> users = userMapper.selectList(null); users.forEach(System.out::println); }
|
3.通用Service
说明:
- 通用 Service CRUD 封装
IService
接口,进一步封装 CRUD 采用 get 查询单行
remove 删除
list 查询集合
page 分页
前缀命名方式区分 Mapper
层避免混淆, - 泛型
T
为任意实体对象 - 建议如果存在自定义通用 Service 方法的可能,请创建自己的
IBaseService
继承 Mybatis-Plus
提供的基类 - 对象
Wrapper
为 条件构造器
MyBatis-Plus中有一个接口 IService
和其实现类 ServiceImpl
,封装了常见的业务层逻辑,详情查看源码IService和ServiceImpl
因此我们在使用的时候仅需在自己定义的Service
接口中继承IService
接口,在自己的实现类中实现自己的Service并继承ServiceImpl
即可
IService中的CRUD方法
增加:Save、SaveOrUpdate
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| boolean save(T entity);
boolean saveBatch(Collection<T> entityList);
boolean saveBatch(Collection<T> entityList, int batchSize);
boolean saveOrUpdate(T entity);
boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper);
boolean saveOrUpdateBatch(Collection<T> entityList);
boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);
|
删除:Remove
1 2 3 4 5 6 7 8
| boolean remove(Wrapper<T> queryWrapper);
boolean removeById(Serializable id);
boolean removeByMap(Map<String, Object> columnMap);
boolean removeByIds(Collection<? extends Serializable> idList);
|
修改:Update
1 2 3 4 5 6 7 8 9 10
| boolean update(Wrapper<T> updateWrapper);
boolean update(T updateEntity, Wrapper<T> whereWrapper);
boolean updateById(T entity);
boolean updateBatchById(Collection<T> entityList);
boolean updateBatchById(Collection<T> entityList, int batchSize);
|
查询:Get、List、Count
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| T getById(Serializable id);
T getOne(Wrapper<T> queryWrapper);
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);
List<T> list();
List<T> list(Wrapper<T> queryWrapper);
Collection<T> listByIds(Collection<? extends Serializable> idList);
Collection<T> listByMap(Map<String, Object> columnMap);
List<Map<String, Object>> listMaps();
List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);
List<Object> listObjs();
<V> List<V> listObjs(Function<? super Object, V> mapper);
List<Object> listObjs(Wrapper<T> queryWrapper);
<V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
int count();
int count(Wrapper<T> queryWrapper);
|
分页:Page
1 2 3 4 5 6 7 8 9 10
| T getById(Serializable id);
T getOne(Wrapper<T> queryWrapper);
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);
|
4.调用Service层操作数据
我们在自己的Service接口中通过继承MyBatis-Plus提供的IService接口,不仅可以获得其提供的CRUD方法,而且还可以使用自身定义的方法。
常用注解
MyBatis-Plus提供的注解可以帮我们解决一些数据库与实体之间相互映射的问题。
1.@TableName
经过以上的测试,在使用MyBatis-Plus实现基本的CRUD时,我们并没有指定要操作的表,只是在Mapper接口继承BaseMapper时,设置了泛型User,而操作的表为user表,由此得出结论,MyBatis-Plus在确定操作的表时,由BaseMapper的泛型决定,即实体类型决定,且默认操作的表名和实体类型的类名一致。
1.1 引出问题
若实体类类型的类名和要操作的表的表名不一致,会出现什么问题?
1.2 解决问题
a、使用注解解决问题
在实体类类型上添加@TableName("t_user")
,标识实体类对应的表,即可成功执行SQL语句
1 2 3 4 5 6 7 8
| @Data @TableName("t_user") public class User { private Long id; private String name; private Integer age; private String email; }
|
b、使用全局配置解决问题
在开发的过程中,我们经常遇到以上的问题,即实体类所对应的表都有固定的前缀,例如 t_
或 tbl_
此时,可以使用MyBatis-Plus提供的全局配置,为实体类所对应的表名设置默认的前缀,那么就不需要在每个实体类上通过@TableName标识实体类对应的表
1 2 3 4 5
| mybatis-plus: global-config: db-config: table-prefix: t_
|
2.@TableId
经过以上的测试,MyBatis-Plus在实现CRUD时,会默认将id作为主键列,并在插入数据时,默认基于雪花算法的策略生成id
2.1 引出问题
若实体类和表中表示主键的不是id,而是其他字段,例如uid,MyBatis-Plus会自动识别uid为主键列吗?
2.2 解决问题
在实体类中uid属性上通过@TableId
将其标识为主键,即可成功执行SQL语句
1 2 3 4 5 6 7 8
| @Date public class User { @TableId private Long uid; private String name; private Integer age; private String email; }
|
2.3 @TableId的value属性
若实体类中主键对应的属性为id,而表中表示主键的字段为uid,此时若只在属性id上添加注解@TableId,则抛出异常Unknown column ‘id’ in ‘field list’,即MyBatis-Plus仍然会将id作为表的主键操作,而表中表示主键的是字段uid此时需要通过@TableId注解的value属性,指定表中的主键字段,@TableId("uid")
或@TableId(value="uid")
2.4 @TableId的type属性
type属性用来定义主键策略:默认雪花算法
常用的主键策略:
值 | 描述 |
---|
IdType.ASSIGN_ID(默认) | 基于雪花算法的策略生成数据id,与数据库id是否设置自增无关 |
IdType.AUTO | 使用数据库的自增策略,注意,该类型请确保数据库设置了id自增, |
配置全局主键策略:
1 2 3 4 5 6 7 8 9 10 11
| mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: id-type: auto table-prefix: t_
|
3.@TbaleField
经过以上的测试,我们可以发现,MyBatis-Plus在执行SQL语句时,要保证实体类中的属性名和表中的字段名一致
如果实体类中的属性名和字段名不一致的情况,会出现什么问题呢?
3.1 情况一
若实体类中的属性使用的是驼峰命名风格,而表中的字段使用的是下划线命名风格
例如实体类属性userName
,表中字段user_name
此时MyBatis-Plus会自动将下划线命名风格转化为驼峰命名风格
相当于在MyBatis中配置
3.2 情况二
若实体类中的属性和表中的字段不满足情况1
例如实体类属性name
,表中字段username
此时需要在实体类属性上使用@TableField("username")
设置属性所对应的字段名
1 2 3 4 5 6 7 8
| public class User { @TableId("uid") private Long id; @TableField("username") private String name; private Integer age; private String email; }
|
4.@TableLogic
4.1 逻辑删除
物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除的数据
逻辑删除:假删除,将对应数据中代表是否被删除字段的状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录
使用场景:可以进行数据恢复
4.2 实现逻辑删除