MyBatis-Plus为我们提供了BaseMapper,我们只需要继承BaseMapper就可以直接使用简单的增删改查功能。
一:Create(Insert)
int insert(T entity);
@Test
void testMyBatisPlus() {
// INSERT INTO tbl_user ( username, name ) VALUES ( ?, ? )
User user = new User();
user.setUsername("gaozhanlong");
user.setName("高占龙");
// 返回受影响的行数
// 插入时如果属性值为null则不加入到SQL中。
// INSERT INTO tbl_user ( id, username, password, name ) VALUES ( ?, ?, ?, ? )
int affectRows = userMapper.insert(user);
// 插入后主键id会赋值给实体
Long userId = user.getId();
System.out.println("affectRows=" + affectRows + ", userId=" + userId);
}
public class User implements Serializable {
/**
* 主键
*/
@TableId(type = IdType.AUTO)
private Long id;
}
数据库的主键对应实体中属性需要使用@TableId
注解标注,并指明主键id的生成策略,常用的有AUTO(数据库自增)、ASSIGN_ID(雪花算法),当插入成功后会将主键id值回显给实体对象,一般情况下id生成策略都使用ATUO,只有在有分表需求的时候才使用ASSIGN_ID(雪花算法)。
注意
:最新版本的mybatis-plus中的雪花算法好像不需要配置数据中心ID和机器ID,它们都是自动计算出来的:
- mybatis-plus.global-config.datacenter-id 根据服务器的Mac地址来计算
- mybatis-plus.global-config.worker-id 根据datacenter-id和java虚拟中的bean数量来计算。
使用@TableId(type = IdType.AUTO)这种将注解标注在主键id属性上属于局部主键策略,我们也可以在application.yml中配置全局主键策略,当配置了全局id生成策略并且主键为“id”此时不用显式的使用@TableId注解,如果同时配置了全局策略和局部策略,那么局部策略优于全局策略。
# 配置mybatis plus 全局的id生成策略
mybatis-plus.global-config.db-config.id-type=auto
二:Delete
// 根据 entity 条件,删除记录
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);
// 删除(根据ID 批量删除)
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根据 ID 删除
int deleteById(Serializable id);
// 根据 columnMap 条件,删除记录
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
@Test
public void testDelete() {
// DELETE FROM tbl_user WHERE id=?
int affectRows = userMapper.deleteById(100L);
// DELETE FROM tbl_user WHERE id IN ( ? , ? , ? )
int num = userMapper.deleteBatchIds(Arrays.asList(1L, 2L, 3L));
// 多条件删除,逻辑运算符使用and连接,关系运算符使用=连接,如果值为null表示 is null
// DELETE FROM tbl_user WHERE username = ? AND status IS NULL
Map<String, Object> whereMap = new HashMap<>();
whereMap.put("username", "gaozhanlong");
whereMap.put("status", null);
int rows = userMapper.deleteByMap(whereMap);
// 使用QueryWrapper构造where条件(这种方式最灵活,可以构造任意关系运算符和逻辑运算符)
// DELETE FROM tbl_user WHERE (age > ? AND username LIKE ?)
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.gt("age", 30).likeRight("username", "xiao");
int count = userMapper.delete(wrapper);
}
三:Update
// 根据 whereEntity 条件,更新记录
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);
// 根据 ID 修改
int updateById(@Param(Constants.ENTITY) T entity);
@Test
void testMyBatisPlus() {
// UPDATE tbl_user SET age=?, status=? WHERE id=?
User user = new User();
user.setId(1L);
user.setAge(50);
user.setStatus(2);
int affectRows = userMapper.updateById(user);
System.out.println(affectRows);
}
注意:修改时如果属性为null也是不会加入到SQL语句中来的。
@Test
public void testUpdate(){
User user = new User();
user.setAge(35);
user.setRemark("重庆军统王牌特工,表面残酷狠辣的军统特务“鬼子六”");
QueryWrapper<User> queryWrapper = new QueryWrapper();
queryWrapper.eq("username", "sixbrother").gt("age", 20);
// UPDATE tbl_user SET age=?, remark=? WHERE (username = ? AND age > ?)
int affectRows = userMapper.update(user, queryWrapper);
System.out.println(affectRows);
}
@Test
void testMyBatisPlus() {
// UPDATE tbl_user SET age=?, status=? WHERE (id = ?)
User user = new User();
user.setId(1L);
user.setAge(50);
user.setStatus(2);
QueryWrapper<User> queryWrapper = new QueryWrapper<User>().eq("id", 100L);
int affectRows = userMapper.update(user, queryWrapper);
System.out.println(affectRows);
}
UpdateWrapper可以通过set方法来设置字段的值。
@Test
void testMyBatisPlus() {
// UPDATE tbl_user SET age=?,status=? WHERE (id = ?)
UpdateWrapper<User> updateWrapper = new UpdateWrapper<User>()
.set("age", 30)
.set("status", 2)
.eq("id", 100L);
int affectRows = userMapper.update(null, updateWrapper);
System.out.println(affectRows);
}
UpdateWrapper可以通过setSql() 采用SQL语法来设置值。
@Test
void testMyBatisPlus() {
// UPDATE tbl_user SET age=?,status = 2 WHERE (id = ?)
LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<User>()
.set(User::getAge, 30)
.setSql("status = 2")
.eq(User::getId, 100L);
int affectRows = userMapper.update(null, updateWrapper);
System.out.println(affectRows);
}
注意:
- QueryWrapper:用于构造where条件的,SQL中的条件在QueryWrapper中都有对应的方法。
- QueryWrapper默认是使用and 并且来连接各个条件的。
- UpdateWrapper:用于构造update语句,比QueryWrapper多了一个set()方法用于修改值,也可以使用QueryWrapper中的方法来构造where条件。
四:Retrieve(Select)
// 根据 ID 查询
T selectById(Serializable id);
// 根据 entity 条件,查询一条记录
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 查询(根据ID 批量查询)
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根据 entity 条件,查询全部记录
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 查询(根据 columnMap 条件)
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
// 根据 Wrapper 条件,查询全部记录
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录。注意: 只返回第一个字段的值
List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 entity 条件,查询全部记录(并翻页)
IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录(并翻页)
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询总记录数
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
@Test
public void testSelect() {
// SELECT * FROM tbl_user WHERE id=?
User user = userMapper.selectById(1L);
System.out.println(user);
// SELECT * FROM tbl_user WHERE id IN ( ? , ? )
List<User> users = userMapper.selectBatchIds(Arrays.asList(1L, 2L));
System.out.println(users);
// 查询一条,如果有多条满足条件的数据会报错
// SELECT * FROM tbl_user WHERE (username = ?)
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username", "sixbrother");
User user1 = userMapper.selectOne(queryWrapper);
// 查询满足条件的条数
// SELECT COUNT( 1 ) FROM tbl_user WHERE (username LIKE ?)
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.like("username", "xiao");
Integer count = userMapper.selectCount(wrapper);
// SELECT * FROM tbl_user WHERE (username LIKE ?)
List<User> userList = userMapper.selectList(wrapper);
}
selectMaps()通常用于统计查询,因为一般统计的结果字段都不在实体类中。
@Test
void testMyBatisPlus() {
// SELECT gender,count(*) as count,avg(age) as avg_age FROM tbl_user GROUP BY gender
QueryWrapper<User> queryWrapper = Wrappers.<User>query()
.select("gender", "count(*) as count", "avg(age) as avg_age").groupBy("gender");
List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
System.out.println(maps);
}
五:自定义SQL
自定义SQL就是又想自己写SQL语句又想使用MyBatis-Plus中的条件构造器Wrapper,MyBatis-Plus中可以支持此方式,通过使用@Param注解即可引用条件构造器。
BaseMapper中的很多方法参数都使用了@Param注解进行标注了,这就意味着我们可以在原生的MyBatis中使用这个参数(可以在MyBatis注解中也可以在xml文件中),例如使用@Param(Constants.WRAPPER)
定义参数名,在MyBatis中使用固定的写法${ew.customSqlSegment}
来引用MyBatis-Plus中的条件构造器。
@Test
void testMyBatisPlus() {
// delete from tbl_user WHERE (id = ? OR age > ?)
QueryWrapper<User> wrapper = new QueryWrapper<User>().eq("id", 100).or().gt("age", 30);
userMapper.myDelete(wrapper);
}
public interface UserMapper extends BaseMapper<User> {
// 注意SQL语句不需要加where关键字
@Delete("delete from tbl_user ${ew.customSqlSegment}")
void myDelete(@Param(Constants.WRAPPER) QueryWrapper<User> wrapper);
}
六:@TableField
@TableField用于指定字段的一些属性,常用的场景有:
- 对象中的属性名和字段名不一致的问题,如表中使用user_id作为主键,而实体中使用id作为属性名,此时需要配置两者的映射关系。
@TableName("tbl_user")
public class User implements Serializable {
/**
* 主键
*/
@TableId(type = IdType.AUTO)
@TableField(value = "user_id")
private Long id;
}
- 对象中的属性字段在表中不存在的问题。
@TableName("tbl_user")
public class User implements Serializable {
/** 数据库中不存在的字段 */
@TableField(exist = false)
private String mock;
}
- 查询时不查询指定的字段,如有些字段只是服务器在使用,没必要暴露出去
@TableName("tbl_user")
public class User implements Serializable {
/**
* 版本号
*/
@TableField(select = false)
private String version;
/**
* 是否删除(0: 未删除,1:已删除)
*/
@TableField(select = false)
private Integer deleted;
}