MyBatis-Plus基本CRUD
- 三、基本CRUD
- 1、BaseMapper
- 2、插入
- 3、删除
- a>通过id删除记录
- b>通过id批量删除记录
- c>通过map条件删除记录
- 4、通过id修改一条记录
- 5、查询
- a>根据id查询用户信息
- b>根据多个id查询多个用户信息
- c>通过map条件查询用户信息
- d>查询所有数据
- 6、通用Service
- a>IService
- b>创建Service接口和实现类
- c>测试查询记录数
- d>测试批量插
- 四、常用注解
- 1、@TableName
- a>问题
- b>通过@TableName解决问题
- c>通过全局配置解决问题
- 2、@TableId
- a>问题
- b>通过@TableId解决问题
- c>@TableId的value属性
- d>@TableId的type属性
- 3、@TableField
- a>情况1
- b>情况2
- 4、@TableLogic
- a>逻辑删除
- b>实现逻辑删除
- 五、条件构造器和常用接口
- 1、wapper介绍
- 2、QueryWrapper
- a>例1:组装查询条件
- b>例2:组装排序条件
- c>例3:组装删除条件
- d>例4:条件的优先级
- e>例5:组装select子句
- f>例6:实现子查询
- 3、UpdateWrapper
- 4、condition
申明: 未经许可,禁止以任何形式转载,若要引用,请标注链接地址。 全文共计10418字,阅读大概需要3分钟
更多学习内容, 欢迎关注我的个人公众号:不懂开发的程序猿
相关阅读:MyBatis-Plus入门案例
三、基本CRUD
1、BaseMapper
MyBatis-Plus中的基本CRUD在内置的BaseMapper中都已得到了实现,我们可以直接使用
2、插入
//测试插入
@Test
public void testInsert() {
User user = new User();
// INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? )
user.setName("张三");
user.setAge(23);
user.setEmail("zhangsan@qq.com");
int res = userMapper.insert(user);//打印出来的是受影响的行数
System.out.println("res: " + res);//res: 1
System.out.println("id: " + user.getId());//id: 1623636806420439041
}
最终执行的结果,所获取的id为1623636806420439041
这是因为MyBatis-Plus在实现插入数据时,会默认基于雪花算法的策略生成id
3、删除
a>通过id删除记录
//通过id删除用户信息
@Test
public void testDeleteById() {
//DELETE FROM user WHERE id=?
int res = userMapper.deleteById(1623636806420439041L);//打印出来的是受影响的行数
System.out.println("受影响行数:" + res);
}
b>通过id批量删除记录
@Test
public void testDeleteBatchIds(){
List<Long> idList = Arrays.asList(104L, 105L, 106L);
//通过多个id批量删除
//DELETE FROM user WHERE id IN ( ? , ? , ? )
int i = userMapper.deleteBatchIds(idList);//打印出来的是受影响的行数
System.out.println("受影响行数:" + i);//受影响行数:3
}
c>通过map条件删除记录
//通过map条件删除记录
@Test
public void testDeleteByMap(){
//根据map集合中所设置的条件删除记录
//DELETE FROM user WHERE name = ? AND age = ?
Map<String, Object> map = new HashMap<>();
map.put("age", 18);
map.put("name", "ls4");
int i = userMapper.deleteByMap(map);//打印出来的是受影响的行数
System.out.println("受影响行数:" + i);//受影响行数:1
}
4、通过id修改一条记录
@Test
public void testUpdateById(){
User user = new User();
user.setId(6L);
user.setName("z3");
user.setAge(23);
user.setEmail("z3@qq.com");
//UPDATE user SET name=?, age=? WHERE id=?
int i = userMapper.updateById(user);//打印出来的是受影响的行数
System.out.println("受影响行数:" + i);//受影响行数:1
}
5、查询
a>根据id查询用户信息
//根据id查询用户信息
@Test
public void testSelectById(){
// SELECT id,name,age,email FROM user WHERE id=?
User user = userMapper.selectById(4L);
System.out.println(user);
}
b>根据多个id查询多个用户信息
@Test
public void testSelectBatchIds(){
List<Long> idList = Arrays.asList(1L, 2L, 3L);
//SELECT id,name,age,email FROM user WHERE id IN ( ? , ? , ? )
for (User user : userMapper.selectBatchIds(idList)) {
System.out.println(user);
}
}
c>通过map条件查询用户信息
@Test
public void testSelectByMap(){
Map<String,Object> map = new HashMap<>();
map.put("name", "jerry");
map.put("age", 21);
List<User> users = userMapper.selectByMap(map);
users.forEach(System.out::println);
}
d>查询所有数据
@Test
public void testSelectList(){
//查询所有用户信息
//SELECT id,name,age,email FROM user
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
通过观察BaseMapper中的方法,大多方法中都有Wrapper类型的形参,此为条件构造器,可针 对于SQL语句设置不同的条件,若没有条件,则可以为该形参赋值null,即查询(删除/修改)所有数据
6、通用Service
说明:
通用 Service CRUD 封装IService接口,进一步封装 CRUD 采用
get 查询单行
remove 删 除
list 查询集合
page 分页
前缀命名方式区分Mapper
层避免混淆,泛型
T
为任意实体对象建议如果存在自定义通用 Service 方法的可能,请创建自己的
IBaseService
继承Mybatis-Plus
提供的基类官网地址:https://baomidou.com/pages/49cc81/#service-crud-%E6%8E%A5%E5%8F% A3
a>IService
MyBatis-Plus中有一个接口 IService和其实现类 ServiceImpl,封装了常见的业务层逻辑
详情查看源码IService和ServiceImpl
b>创建Service接口和实现类
/**
* UserService继承IService模板提供的基础功能
*/
public interface UserService extends IService<User> {
}
/**
* ServiceImpl实现了IService,提供了IService中基础功能的实现
* 若ServiceImpl无法满足业务需求,则可以使用自定的UserService定义方法,并在实现类中实现
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService{
}
c>测试查询记录数
@Autowired
UserService userService;
//测试查询记录数
@Test
public void testGetCount() {
long count = userService.count();
//SELECT COUNT( * ) FROM user
System.out.println("总记录数:" + count);
}
d>测试批量插
//测试批量插入
@Test
public void testSaveBatch() {
ArrayList<User> users = new ArrayList<>();
for (int i = 0; i < 5; i++) {
User user = new User();
user.setName("jerry" + i);
user.setAge(18 + i);
users.add(user);
}
//INSERT INTO user ( id, name, age ) VALUES ( ?, ?, ? )
userService.saveBatch(users);
}
四、常用注解
1、@TableName
经过以上的测试,在使用MyBatis-Plus实现基本的CRUD时,我们并没有指定要操作的表,只是在 Mapper接口继承BaseMapper时,设置了泛型User,而操作的表为user表
由此得出结论,MyBatis-Plus在确定操作的表时,由BaseMapper的泛型决定,即实体类型决 定,且默认操作的表名和实体类型的类名一致
a>问题
若实体类类型的类名和要操作的表的表名不一致,会出现什么问题?
我们将表user更名为t_user,测试查询功能 程序抛出异常,Table ‘mybatis_plus.user’ doesn’t exist,因为现在的表名为t_user,而默认操作 的表名和实体类型的类名一致,即user表
b>通过@TableName解决问题
在实体类类型上添加@TableName(“t_user”),标识实体类对应的表,即可成功执行SQL语句
c>通过全局配置解决问题
在开发的过程中,我们经常遇到以上的问题,即实体类所对应的表都有固定的前缀,例如t_或tb_
此时,可以使用MyBatis-Plus提供的全局配置,为实体类所对应的表名设置默认的前缀,那么就 不需要在每个实体类上通过@TableName标识实体类对应的表
# 配置MyBatis日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
# 配置MyBatis-Plus操作表的默认前缀
table-prefix: t_
2、@TableId
经过以上的测试,MyBatis-Plus在实现CRUD时,会默认将id作为主键列,并在插入数据时,默认 基于雪花算法的策略生成id
a>问题
若实体类和表中表示主键的不是id,而是其他字段,例如uid,MyBatis-Plus会自动识别uid为主 键列吗?
我们实体类中的属性id改为uid,将表中的字段id也改为uid,测试添加功能
程序抛出异常,Field ‘uid’ doesn’t have a default value,说明MyBatis-Plus没有将uid作为主键 赋值
b>通过@TableId解决问题
在实体类中uid属性上通过@TableId将其标识为主键,即可成功执行SQL语句
c>@TableId的value属性
若实体类中主键对应的属性为id,而表中表示主键的字段为uid,此时若只在属性id上添加注解 @TableId,
则抛出异常Unknown column ‘id’ in ‘field list’,即MyBatis-Plus仍然会将id作为表的 主键操作,而表中表示主键的是字段uid
此时需要通过@TableId注解的value属性,指定表中的主键字段,@TableId(“uid”)或 @TableId(value=“uid”)
d>@TableId的type属性
type属性用来定义主键策略
常用的主键策略:
值 | 描述 |
---|---|
IdType.ASSIGN_ID(默 认) | 基于雪花算法的策略生成数据id,与数据库id是否设置自增无关 |
IdType.AUTO | 使用数据库的自增策略,注意,该类型请确保数据库设置了id自增, 否则无效 |
配置全局主键策略:
# 配置MyBatis日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
# 配置MyBatis-Plus操作表的默认前缀
table-prefix: t_
# 配置MyBatis-Plus的主键策略
id-type: auto
3、@TableField
经过以上的测试,我们可以发现,MyBatis-Plus在执行SQL语句时,要保证实体类中的属性名和 表中的字段名一致 如果实体类中的属性名和字段名不一致的情况,会出现什么问题呢?
a>情况1
若实体类中的属性使用的是驼峰命名风格,而表中的字段使用的是下划线命名风格
例如实体类属性userName,表中字段user_name
此时MyBatis-Plus会自动将下划线命名风格转化为驼峰命名风格
相当于在MyBatis中配置
b>情况2
若实体类中的属性和表中的字段不满足情况1
例如实体类属性name,表中字段username
此时需要在实体类属性上使用@TableField(“username”)设置属性所对应的字段名
4、@TableLogic
a>逻辑删除
-
物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除的数据
-
逻辑删除:假删除,将对应数据中代表是否被删除字段的状态修改为“被删除状态”,之后在数据库 中仍旧能看到此条数据记录
-
使用场景:可以进行数据恢复
b>实现逻辑删除
step1:数据库中创建逻辑删除状态列,设置默认值为0
step2:实体类中添加逻辑删除属性
step3:测试
@Test
public void test(){
//UPDATE user SET is_deleted=1 WHERE id=? AND is_deleted=0
int i = userMapper.deleteById(1623660102079778820L);
System.out.println("受影响行数:" + i);//受影响行数:1
}
五、条件构造器和常用接口
1、wapper介绍
2、QueryWrapper
a>例1:组装查询条件
查询用户名包含j,年龄在20到30之间,并且邮箱不为null的用户信息
//查询用户名包含j,年龄在20到30之间,并且邮箱不为null的用户信息
@Test
public void test01(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like("name", "j")
.between("age", 20, 30)
.isNotNull("email");
//SELECT id,name,age,email,is_deleted FROM user WHERE is_deleted=0 AND (name LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL)
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
b>例2:组装排序条件
按年龄降序查询用户,如果年龄相同则按id升序排列
//按年龄降序查询用户,如果年龄相同则按id升序排列
@Test
public void test02(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.orderByDesc("age")
.orderByAsc("id");
//SELECT id,name,age,email,is_deleted FROM user WHERE is_deleted=0 ORDER BY age DESC,id ASC
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
c>例3:组装删除条件
删除email为空的用户
@Test
public void test03(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//UPDATE user SET is_deleted=1 WHERE is_deleted=0 AND (email IS NULL)
//条件构造器也可以构建删除语句的条件
queryWrapper.isNull("email");
int delete = userMapper.delete(queryWrapper);
System.out.println(delete);
}
d>例4:条件的优先级
//将(年龄大于20并且用户名中包含有a)或邮箱为null的用户信息修改
@Test
public void test04(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.gt("age", 20)
.like("name", "a")
.or()
.isNull("email");
User user = new User();
user.setAge(20);
user.setName("Tom1");
user.setEmail("user@qq.com");
//UPDATE user SET name=?, age=?, email=? WHERE is_deleted=0 AND (age > ? AND name LIKE ? OR email IS NULL)
int i = userMapper.update(user, queryWrapper);
System.out.println("受影响行数:" + i);//受影响行数:1
}
e>例5:组装select子句
//查询用户信息的username和age字段
@Test
public void test05(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.select("name","age");
//SELECT name,age FROM user WHERE is_deleted=0
//selectMaps()返回Map集合列表,通常配合select()使用,避免User对象中没有被查询到的列值为null
List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
maps.forEach(System.out::println);
}
f>例6:实现子查询
//查询id小于等于3的用户信息
//查询id小于等于3的用户信息
@Test
public void test06(){
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//SELECT id,name,age,email,is_deleted FROM user WHERE is_deleted=0 AND (id IN (select id from user where id <= 3))
queryWrapper.inSql("id", "select id from user where id <= 3");
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
3、UpdateWrapper
//将(年龄大于20或邮箱为null)并且用户名中包含有a的用户信息修改
@Test
public void test07(){
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
//UPDATE user SET age=?,email=? WHERE is_deleted=0 AND (name LIKE ? AND (age > ?) OR email IS NULL)
updateWrapper.set("age", 18)
.set("email", "admin@qq.com")
.like("name", "a")
.and(i->i.gt("age", 18)).or().isNull("email");
int i = userMapper.update(null, updateWrapper);
System.out.println("受影响行数:" + i);//受影响行数:1
}
4、condition
在真正开发的过程中,组装条件是常见的功能,而这些条件数据来源于用户输入,是可选的,因 此我们在组装这些条件时,必须先判断用户是否选择了这些条件,若选择则需要组装该条件,若 没有选择则一定不能组装,以免影响SQL执行的结果
不使用condition的代码
@Test
public void test08(){
//定义查询条件,有可能为null(用户未输入或未选择)
String name = null;
Integer ageBegin = 10;
Integer ageEnd = 24;
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
//StringUtils.isNotBlank()判断某字符串是否不为空且长度不为0且不由空白符(whitespace)构成
if (StringUtils.isNotBlank(name)){
queryWrapper.like("name", "a");
}
if(ageBegin != null){
queryWrapper.ge("age", ageBegin);
}
if(ageEnd != null){
queryWrapper.le("age", ageEnd);
}
//SELECT id,name,age,email,is_deleted FROM user WHERE is_deleted=0 AND (age >= ? AND age <= ?)
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
使用condition
@Test
public void test08Condition() {
//定义查询条件,有可能为null(用户未输入或未选择)
String name = null;
Integer ageBegin = 10;
Integer ageEnd = 24;
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like(StringUtils.isNotBlank(name), "name", "a")
.gt(ageBegin != null, "age", ageBegin)
.lt(ageEnd != null, "age", ageEnd);
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);
}
–end–