标准CRUD书写
lombok
-
Lombok,一个Java类库,提供了一组注解,简化POJO实体类开发
-
免去getter/setter/toString的书写
- 导入依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
- 在实体类前加上@Data注解
@Data
@TableName(value = "tb_user")
public class User {
private int id;
private String name;
private String password;
private int age;
private String tel;
}
标准CRUD
- 查询全部
@Test
void testGetAll() {
List<User> users = userDao.selectList(null);
users.forEach(System.out::println);
}
- 根据id查询
@Test
void testGetById() {
User user = userDao.selectById(1);
System.out.println(user);
}
- 根据id删除
@Test
void testDeleteById() {
userDao.deleteById(2);
}
- 更新
@Test
void testUpdateById() {
User user = new User();
user.setId(1);
user.setName("jihua");
userDao.updateById(user);//只修改提供的字段,不提供的不会修改为NULL
}
分页查询
- 设置分页拦截器作为Spring管理的bean(新建配置类)
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
//1.定义MybatisPlus拦截器
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
//2.添加具体拦截器
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mybatisPlusInterceptor;
}
}
- 执行分页查询
@Test
void testGetByPage() {
IPage page = new Page(1,2);
userDao.selectPage(page,null);
System.out.println("当前页码值:"+page.getCurrent());
System.out.println("每页显示数:"+page.getSize());
System.out.println("一共多少页:"+page.getPages());
System.out.println("一共多少条数据:"+page.getTotal());
System.out.println("数据:"+page.getRecords());
}
- 关于开启MybatisPlus的日志(在配置文件application.yml中)
# 开启日志,输出到控制台
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
DQL编程控制
条件查询
- MyBatisPlus将书写复杂的sQL查询条件进行了封装,使用编程的形式完成查询条件的组合
条件查询——设置查询条件
格式一:常规格式
//格式一:常规格式
@Test
void testWrapperGet1(){
QueryWrapper<User> qw = new QueryWrapper<User>();
//查询年龄大于等于18,小于60岁的用户
qw.lt("age",60);
qw.ge("age",18);
List<User> users = userDao.selectList(qw);
users.forEach(System.out::println);
}
格式二:链式编程格式
//格式二:链式编程格式
@Test
void testWrapperGet2(){
QueryWrapper<User> qw = new QueryWrapper<User>();
//查询年龄大于等于18,小于60岁的用户
qw.lt("age",60).ge("age",18);
List<User> users = userDao.selectList(qw);
users.forEach(System.out::println);
}
格式三:lambda格式(推荐)
//格式三:lambda格式(推荐)
@Test
void testWrapperGet3(){
QueryWrapper<User> qw = new QueryWrapper<User>();
//查询年龄大于等于18,小于60岁的用户
qw.lambda().lt(User::getAge,60).ge(User::getAge,18);
List<User> users = userDao.selectList(qw);
users.forEach(System.out::println);
}
格式四:lambda格式
//格式四:lambda格式
@Test
void testWrapperGet4(){
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
//查询年龄大于等于18,小于60岁的用户
lqw.lt(User::getAge,60).ge(User::getAge,18);
List<User> users = userDao.selectList(lqw);
users.forEach(System.out::println);
}
条件查询——组合条件
组合条件and
//条件查询——组合条件and
@Test
void testWrapperAnd(){
LambdaQueryWrapper<User> lqw= new LambdaQueryWrapper<User>();
//查询年龄大于等于18,小于60岁的用户
lqw.lt(User::getAge,60).ge(User::getAge,18);
List<User> users = userDao.selectList(lqw);
users.forEach(System.out::println);
}
组合条件or
//条件查询——组合条件or
@Test
void testWrapperOr(){
LambdaQueryWrapper<User> lqw= new LambdaQueryWrapper<User>();
//查询年龄小于等于18,或大于60岁的用户
lqw.gt(User::getAge,60).or().le(User::getAge,18);
List<User> users = userDao.selectList(lqw);
users.forEach(System.out::println);
}
条件查询—— null值判定
使用if语句控制条件追加
@Test
void testWrapperNull() {
UserQuery user = new UserQuery();
user.setAge(18);//下限
//user.setAge2(40);//上限
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
if(null != user.getAge()){
lqw.gt(User::getAge,user.getAge());
}
if(null!=user.getAge2()){
lqw.lt(User::getAge,user.getAge2());
}
List<User> users = userDao.selectList(lqw);
users.forEach(System.out::println);
}
条件参数控制
@Test
void testWrapperNull() {
UserQuery user = new UserQuery();
user.setAge(18);//下限
//user.setAge2(40);//上限
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
lqw.gt(null != user.getAge(),User::getAge,user.getAge())
.lt(null!=user.getAge2(),User::getAge,user.getAge2());
List<User> users = userDao.selectList(lqw);
users.forEach(System.out::println);
}
查询投影
查询投影——常规
//查询投影——常规
@Test
void testSelect() {
QueryWrapper<User> qw = new QueryWrapper<>();
qw.select("name", "age", "tel");
List<User> users = userDao.selectList(qw);
users.forEach(System.out::println);
}
查询投影——lambda
//查询投影——lambda
@Test
void testSelectLambda() {
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();
lqw.select(User::getName, User::getAge, User::getTel);
List<User> users = userDao.selectList(lqw);
users.forEach(System.out::println);
}
查询条件
eq匹配
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
lqw.eq(User::getName, userQuery.getName()).eq(User::getPassword, userQuery.getPassword());
User loginUser = userDao.selectOne(lqw);
System.out.println(loginuser);
le,ge匹配、between匹配
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
//方案一:设定上限下限
lqw.le(User::getAge, userQuery.getAge()).ge(User::getAge, userQuery.getAge2());
//方案二:设定范围
lqw.between(User::getAge, userQuery.getAge( ), userQuery.getAge2( ));
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
like匹配
LambdaQuerywrapper<User> fqw = new LambdaQuerywrapper<User>();
lqw.likeLeft(User::getTel, userQuery.getTel());
List<User> userList = userDao.selectList(lqw);
System.out.println(userList);
- like匹配
like(name, "R")
:%R%likeLeft(name, "R")
:R%likeRight(name, "R")
:%R
分组统计查询
- 使用
count(*)
进行统计查询时,查询应该使用selectMaps()
//分组统计查询
@Test
void testSelectGroup() {
QueryWrapper<User> qw = new QueryWrapper<>();
qw.select("count(*) as 人数", "age");
qw.groupBy("age");
List<Map<String, Object>> mapList = userDao.selectMaps(qw);
mapList.forEach(System.out::println);
}
字段映射与表名映射
@TableName("tbl_user")//将实体类与表名映射
public class User {
private Long id;
@TableField(value="pwd")//将实体类的属性和表的列名对应
private String name;
@TableField(select = false)//设置属性不参与查询
private string password;
private Integer age;
private String tel;
@TableField(exist = false)//设置属性在表中是否存在
private Integer online;
}
-
名称:@TableField
-
类型:属性注解
-
位置:模型类属性定义上方
-
作用:设置当前属性对应的数据库表中的字段关系
-
范例:
public class User { private Long id; @TableField(value="pwd")//将实体类的属性和表的列名对应 private String name; @TableField(select = false)//设置属性不参与查询 private string password; private Integer age; private String tel; @TableField(exist = false)//设置属性在表中是否存在 private Integer online; }
-
相关属性
- value:设置数据库表字段名称
- exist:设置属性在数据库表字段中是否存在,默认为true。此属性无法与value合并使用
- select:设置属性是否参与查询,此属性与select()映射配置不冲突
-
名称:@TableName
-
类型:类注解
-
位置:模型类定义上方
-
作用:设置当前类对应与数据库表关系
-
范例:
@TableName("tbl_user")//将实体类与表名映射 public class User { ... }
-
相关属性
- value:设置数据库表名称
DML编程控制
insert
id生成策略控制
- 不同的表应用不同的id生成策略
- 日志:自增(1,2,3,4,…)
- 购物订单:特殊规则(FQ23948AK3843)
- 外卖单:关联地区日期等信息(10 04 20200314 34 91)
- 关系表:可省略id
- …
-
名称:@TableId
-
类型:属性注解
-
位置:模型类中用于表示主键的属性定义上方
-
作用:设置当前类中主键属性的生成策略
-
范例:
public class User { @TableId(type = IdType.AUTO) private Long id; }
-
相关属性
- value:设置数据库主键名称
- type:设置主键属性的生成策略,值参照
IdType
枚举值
- AUTO(0):使用数据库id自增策略控制id生成
- NONE(1):不设置id生成策略
- INPUT(2):用户手工输入id
- ASSIGN_ID(3):雪花算法生成id(可兼容数值型与字符串型)
- ASSIGN_UUID(4):以UUID生成算法作为id生成策略
全局配置
在application.yml中
mybatis-plus:
global-config:
db-config:
#配置id生成策略
id-type: auto
#配置表名前缀(即表名在实体类名称前面加的前缀)
table-prefix: tbl_
delete
多记录操作
- 按照主键删除多条记录
List<Long> ids= Arrays.asList(new Long[ ]{
2,3});
userDao.deleteBatchIds(ids);
- 根据主键查询多条记录
List<Long> ids= Arrays.asList(new Long[]{
2,3});
List<User> userList = userDao.selectBatchIds(ids);
逻辑删除
- 逻辑删除就是在执行删除操作时不删除数据,而是将数据标记为已删除
步骤:
-
数据库表中添加逻辑删除标记字段
- 在数据库表中添加一列名为deleted的字段,设置默认值为0
-
实体类中添加对应字段,并设定当前字段为逻辑删除标记字段
public class User { private Long id; @TableLogic(value = "0", delval = "1")//配置逻辑删除,0为未删除,1为已删除 private Integer deleted; }
-
也可以在配置(application.yml)中做全局逻辑删除配置
mybatis-plus: global-config: db-config: #配置逻辑删除字段名 logic-delete-field: deleted #配置未删除时的值 logic-not-delete-value: 0 #配置已删除的值 logic-delete-value: 1
-
一旦开启逻辑删除功能后,delete语句都将变为update语句(不是delete而是updata他的deleted值为1 )
-
查询操作也会自动加上条件where deleted = 0
-
要想查询全部属性需要自己编写SQL语句进行查询
乐观锁
数据库表中添加锁标记字段version,在操作数据时先查询出当前version,执行操作时将查询到的version与当前表中的version进行对比(防止数据被其他线程修改过),在执行操作后将version+1
-
数据库表中添加锁标记字段version
-
实体类中添加对应字段,并设定当前字段为逻辑删除标记字段
public class User { private Long id; @Version private Integer version; }
-
配置乐观锁拦截器实现锁机制对应的动态SQL语句拼装
@Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { //1.定义MybatisPlus拦截器 MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); //2.添加乐观锁拦截器 mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); return mybatisPlusInterceptor; } }
-
使用乐观锁机制在修改前必须先获取到对应数据的verion方可正常进行
@Test void testUpdate(){ //先查询数据,获取到version数据 User user = userDao.selectById(1L); User user1 = userDao.selectById(1L); //执行数据修改操作 //操作一 user.setName("Tom and Jerry"); userDao.updateById(user); //操作二 user1.setName("6666"); userDao.updateById(user1); }//此时操作二将不会执行成功
-
执行修改前先执行查询语句:
SELECT id,name,age,tel,deleted,version FROM tbl_user WHERE id=?
-
执行修改时使用version字段作为乐观锁检查依据
UPDATE tbl_user SET name=?, age=?, tel=?, version=? WHERE id=? AND version=?
-