学习内容:学习Mybatis-Plus(Day71)
1、Mybatis-Plus的注解
2、条件构造器
3、分页查询
4、动态sql
5、代码自动生成
1、Mybatis-Plus的注解
(1)@TableId,设置主键映射,value 映射主键字段名,type 设置主键类型,主键的生成策略。
public class User {
@TableId(value = "id",type = IdType.AUTO) //设置id自增(默认)
private Long id;
private String name;
private Integer age;
}
NONE,无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)。
INPUT 如果开发者没有手动赋值,则数据库通过自增的方式给主键赋值,如果开发者手动赋值,则存入该值。
ASSIGN_ID MP 自动赋值,雪花算法。
ASSIGN_UUID 主键的数据类型必须是 String,自动生成 UUID 进行赋值。
(2)@TableField,映射非主键字段
1.value 映射字段名
2.exist 表示是否为数据库表字段,默认true,如果实体类中的成员变量在数据库中没有对应的字段,则可以使用 exist=false,VO、DTO
3.select 表示是否查询该字段,默认true
4.fill 表示是否自动填充,默认FieldFill.DEFAULT将对象存入数据库的时候,由 MyBatis Plus 自动给某些字段赋值,如create_time、update_time
编写实体类,数据库添加createTime和updateTime字段
@Data
@ToString
@TableName(value = "user") //设置表名,如果表名和实体类名相同可省略
public class User {
@TableId(value = "id", type = IdType.AUTO) //设置id自增
private Long id;
private String name;
private Integer age;
@TableField(value = "email",select = false) //映射字段名为email,不查询该字段
private String email;
@TableField(exist = false) //表中不存在此字段
private String gender;
@TableField(fill = FieldFill.INSERT)//插入字段的值时自动填充
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)//插入或修改时自动填充
private Date updateTime;
}
创建自动填充处理器
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
在添加和修改数据后会自动填充添加时间和修改时间。
(3)@Version,OptimisticLockerInnerInterceptor乐观锁
当要更新一条记录的时候,希望这条记录没有被别人更新。
乐观锁实现方式:取出记录时,获取当前version。更新时,带上这个version。执行更新时, set version = newVersion where version = oldVersion。如果version不对,就更新失败。
数据库表添加 version 字段,默认值为 1,实体类添加 version 成员变量,并且添加 @Version
@Data
@ToString
@TableName(value = "user") //设置表名,如果表名和实体类名相同可省略
public class User {
...
@Version
private Integer version;
}
注册配置类
@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
测试,先查再改才能对比version值
@Test
public void testVersion() {
User user = userMapper.selectById(5);
user.setName("黄蓉");
int result = userMapper.updateById(user);
System.out.println(user);
}
查看sql语句:
UPDATE user SET name=?, age=?, update_time=?, version=? WHERE id=? AND version=?
修改后数据库version字段加1
(4)@EnumValue,通用枚举类注解,将数据库字段映射成实体类的枚举类型成员变量。
声明通用枚举属性
方式一: 使用 @EnumValue 注解枚举属性 完整示例
public enum GradeEnum {
PRIMARY(1, "小学"), SECONDORY(2, "中学"), HIGH(3, "高中");
GradeEnum(int code, String descp) {
this.code = code;
this.descp = descp;
}
//方式一: 使用 @EnumValue 注解枚举属性 完整示例
@EnumValue//标记数据库存的值是code
private final int code;
private final String descp;
}
//方式二: 枚举属性,实现 IEnum 接口
public enum AgeEnum implements IEnum<Integer> {
ONE(1, "一岁"),
TWO(2, "二岁"),
THREE(3, "三岁");
private int value;
private String desc;
AgeEnum(int i, String desc) {
this.value = i;
this.desc = desc;
}
@Override
public Integer getValue() {
return this.value;
}
}
实体属性使用枚举类型
@Data
@ToString
@TableName(value = "user") //设置表名,如果表名和实体类名相同可省略
public class User {
...
/**
* 年龄,IEnum接口的枚举处理
* 数据库字段:age INT(3)
*/
private AgeEnum age1;
/**
* 年级,原生枚举(带{@link com.baomidou.mybatisplus.annotation.EnumValue}):
* 数据库字段:grade INT(2)
*/
private GradeEnum grade;
}
配置扫描通用枚举
mybatis-plus:
type-enums-package: com.hisoft.enums #扫描枚举包
测试
@Test
public void testEnum() {
User user = new User();
user.setName("杨过");
user.setAge(16);
user.setEmail("333@qq.com");
user.setGrade(GradeEnum.HIGH);
user.setAge1(AgeEnum.THREE);
int result = userMapper.insert(user); //成功返回1
System.out.println(user);
System.out.println("result = " + result);
}
(5)@TableLogic,映射逻辑删除
只对自动注入的sql起效:
插入: 不作限制
查找: 追加where条件过滤掉已删除数据,且使用 wrapper.entity 生成的where条件会忽略该字段
更新: 追加where条件防止更新到已删除数据,且使用 wrapper.entity 生成的where条件会忽略该字段
删除: 转变为更新
配置com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig
mybatis-plus:
global-config:
db-config:
logic-delete-field: flag # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
实体类字段上加上@TableLogic注解
@TableLogic
private Integer deleted;
测试
@Test
public void testLogicDelete() {
int result = userMapper.deleteById(1458703975678332931L);
Assertions.assertEquals(result,1);//检查结果是否为1,不为1则报错
}
查看sql语句
删除:
update user set deleted=1 where id = 1458703975678332931L and deleted=0
查找:
select id,name,deleted from user where deleted=0
2、条件构造器
(1)AbstractWrapper
QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper) 的父类用于生成 sql 的 where 条件, entity 属性也用于生成 sql 的 where 条件。
注意: entity 生成的 where 条件与 使用各个 api 生成的 where 条件没有任何关联行为。
(2)allEq,全部eq(或个别isNull)
params : key为数据库字段名,value为字段值
null2IsNull : 为true则在map的value为null时调用 isNull 方法,为false时则忽略value为null的。
@Test
public void testWrapper() {
QueryWrapper wrapper = new QueryWrapper<>();
Map<String,Object> map = new HashMap<>();
map.put("id",1458703975678332932L);
map.put("name","郭靖");
wrapper.allEq(map,false);//为false时则忽略value为null的
userMapper.selectList(wrapper);
}
查看sql
SELECT id,name,age FROM user WHERE name = "郭靖" AND id = 1458703975678332932
(3)eq,等于 = ;ne,不等于 <> ;gt,大于 > ;ge,大于等于 >= ; lt,小于 < ;le,小于等于 <= ;between,BETWEEN 值1 AND 值2 ;like,LIKE ‘%值%’ ;
or,拼接 OR
@Test
public void testWrapper() {
QueryWrapper wrapper = new QueryWrapper<>();
wrapper.eq("name","郭靖");
wrapper.or();
wrapper.ge("age",21);
userMapper.selectList(wrapper).forEach(System.out::println);
/*wrapper.like("name","a");
wrapper.or();
wrapper.likeRight("name",'杨');
userMapper.selectList(wrapper).forEach(System.out::println);*/
查看sql
SELECT id,name,age FROM user WHERE name = "郭靖" OR age >= 21
SELECT id,name,age FROM user WHERE name LIKE "a" OR name LIKE '杨'
(4)in
wrapper.in("id", 1,2,3,4);//条件之间会自动加上and
wrapper.in("id", Arrays.asList(1,2,3,4));
wrapper.inSql("id","1,2,3,4");
wrapper.inSql("id","select id from user where id < 4");
userMapper.selectList(wrapper).forEach(System.out::println);
查看sql
SELECT id,name,age FROM user WHERE
id IN (1,2,3,4) AND id IN (1,2,3,4) AND id IN (1,2,3,4)
AND id IN (select id from user where id < 4)
3、分页查询
(1)注册配置类
@Configuration
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
测试
@Test
public void testPage() {
Page page = new Page(3,3); //查询第3页,每页3条
Page result = userMapper.selectPage(page, null);//条件构造器为null
System.out.println("当前页:" + result.getCurrent());
System.out.println("总条数:" + result.getTotal());
System.out.println("总页数:" + result.getPages());
System.out.println("页面大小:" + result.getSize());
result.getRecords().forEach(System.out::println);//具体信息
}
4、动态sql
(1)mybatis-plus无法单独实现动态sql,需要创建mapper.xml映射文件来实现动态sql。
在yml配置文件设置驼峰匹配
mybatis-plus:
type-aliases-package: com.hisoft.entity #别名,驼峰匹配
mapper接口
@Repository
public interface UserMapper extends BaseMapper<User> {
List<User> queryUserByNameAndEmail(@Param("name")String name,@Param("email")String email);
}
mapper.xml映射文件
<?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.hisoft.mapper.UserMapper">
<select id="queryUserByNameAndEmail" resultType="user">
select * from user
<where>
<if test="name != null and name != ''">
and name like concat('%',#{name},'%')
</if>
<if test="email != null and email != ''">
and name like concat('%',#{email},'%')
</if>
</where>
</select>
</mapper>
测试
@Test
public void testSql() {
List<User> users = userMapper.queryUserByNameAndEmail("郭", null);
users.forEach(System.out::println);
}
(2)若果不创建mapper.xml映射文件,也可以通过注解来实现动态sql
@Repository
public interface UserMapper extends BaseMapper<User> {
@Select("<script>"+
"select * from user\n" +
"<where>" +
" <if test=\"name != null and name != ''\">" +
" and name like concat('%',#{name},'%')" +
" </if>" +
" <if test=\"email != null and email != ''\">" +
" and name like concat('%',#{email},'%')" +
" </if>" +
"</where>"+
"</script>")
List<User> queryUserByNameAndEmail(@Param("name")String name,@Param("email")String email);
}
5、代码自动生成
(1)添加依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-velocity</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
(2)测试
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
@Test
public void testGenerator() {
//创建generator对象
AutoGenerator autoGenerator = new AutoGenerator();
//数据源
DataSourceConfig dataSourceConfig = new DataSourceConfig();
dataSourceConfig.setDbType(DbType.MYSQL);
dataSourceConfig.setUrl("jdbc:mysql:///exam?useUnicode=true&characterEncoding=UTF-8");
dataSourceConfig.setUsername("root");
dataSourceConfig.setPassword("root");
dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver");
autoGenerator.setDataSource(dataSourceConfig);
//全局配置
GlobalConfig globalConfig = new GlobalConfig();
globalConfig.setOutputDir("E:\\IntelliJ IDEA\\WorkSpace\\Project01\\Mybatis-plusDemo\\src\\main\\java");
globalConfig.setOpen(false);
globalConfig.setAuthor("huzige");
globalConfig.setServiceName("%sService");
autoGenerator.setGlobalConfig(globalConfig);
//包信息
PackageConfig packageConfig = new PackageConfig();
packageConfig.setParent("com.hisoft2");
packageConfig.setModuleName("user");
packageConfig.setController("controller");
packageConfig.setService("service");
packageConfig.setServiceImpl("service.impl");
packageConfig.setMapper("mapper");
packageConfig.setEntity("entity");
autoGenerator.setPackageInfo(packageConfig);
//配置策略
StrategyConfig strategyConfig = new StrategyConfig();
strategyConfig.setEntityLombokModel(true);
strategyConfig.setNaming(NamingStrategy.underline_to_camel);
strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);
autoGenerator.setStrategy(strategyConfig);
autoGenerator.execute();
}