MyBatisPlus

MyBatis-Plus

默认

  • 雪花算法 – 主键
  • 开启驼峰命名 – 映射

依赖

<!--数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>

<!--mybatis_plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>




快速开始

配置连接

mapper接口

  • 继承 BaseMapper<泛型>
// 在对应的Mapper 上面继承基本的类 BaseMapper

@Repository //代表持久层
public interface UserMapper extends BaseMapper<User> {
// 所有的CRUD操作都已经编写完成了
}

使用

//查询全部用户
List<User> users = userMapper.selectList(null);




配置日志

#默认日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl


注解

@TableField(select = false)    //查询时,则不返回该字段的值
@TableField(value = "email") //通过tableField进行字段不一致的映射
@TableField(exist = false) //设置该字段在数据库表中不存在


CRUD拓展

  • T泛型

insert

int insert = userMapper.insert(user);   //自动生成id

数据库插入的id的默认值:全局的唯一id


主键生成策略

默认 ID_WORKER全局唯一id


1、方式一:默认雪花算法

snowflake是Twitter开源的分布式lD生成算i法,结果是一s个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的is(5个bit是数据中心,5个bit的机器引D),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生4096个ID),最后还有一个符号位,永远是0。可以保证几乎全球唯一


2、方式二:注解配置规则

主键自增

public enum IdType {
AUTO(0), //数据库id自增
NONE(1), //未设置主键
INPUT(2), //手动输入
ID_WORKER_STR(3), //字符串表示法
ASSIGN_UUID(4) //全局唯一id uuid
}
  • 实体类字段加注解:**@TableId(type = IdType.策略)** — 数据库对应的字段也必须要自增
@TableId(type = IdType.AUTO)	//数据库id自增,不用配置输入
private Long id;

@TableId(type = IdType.INPUT) //设置为手动输入id,需要写入


update

  • 可动态判断当前的参数是否为null,!null->update
//通过条件自动拼接动态sql
int i = userMapper.updateById(user);

自动填充

  • 创建时间、修改时间 (gmt_create , gmt_modified)

方式一:数据库级别

1、新增 create_time 、 update_time

image-20230905191245003

2、实体类同步

//plus默认开启驼峰
private Date createTime;
private Date updateTime;

3、数据库级别会对修改的数据的修改时间进行自动化更新



方式二:代码级别

1、删除数据库的字段的默认值操作

2、实体类需要自动填充的字段上添加注解:**@TableField(fill = FieldFill.何时填充)**

//添加时自动填充内容
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;

//更新时自动填充内容
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;

3、实现类

@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

//插入时的填充策略
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill......");
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());

}

//更新时的填充策略
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill ....");
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐)

}
}


乐观锁

乐观锁:故名思意十分乐观,它总是认为不会出现问题,无论干什么不去上锁!如果出现了问题,再次更新值测试

悲观锁:故名思意十分悲观,它总是认为总是出现问题,无论干什么都会上锁!再去操作!

乐观锁实现方式:

  • 取出记录时,获取当前version

  • 更新时,带上这个version

  • 执行更新时,set version=newVersion where version=oldVersion

  • 如果version不对,就更新失败

    乐观锁:
    1、先查询,获得版本号version=1
    --A
    update user set name ="kuangshen",version = version + 1
    where id = 2 and version = 1

    --B线程抢先完成,这个时候version=2,会导致A修改失败!
    update user set name ="kuangshen",version = version + 1
    where id = 2 and version =1

测试MybatisPlus乐观锁插件

1、数据库表增加字段 version

2、实体类对应的字段加注解 : @Version //乐观锁注解

@Version    //乐观锁注解
private Integer version;

3、配置插件

  • 拦截器配置类
@MapperScan("com.chen.demo.mapper")
@EnableTransactionManagement //自动管理事务
@Configuration //配置类
public class MybatisPlusConfig {

//注册乐观锁插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}

}


4、Test

//1、查询、修改
User user = userMapper.selectById(1L);
user.setAge(188888);

User user2 = userMapper.selectById(1L);
user2.setAge(28888888);
//3、执行更新
userMapper.updateById(user2);

userMapper.updateById(user); //如果没有乐观锁就会覆盖插队线程的值


select

//查询全部用户
List<User> users = userMapper.selectList(null);


//单个查询 -- selectById
User user = userMapper.selectById(1L);


//批量查询 -- selectBatchIds
List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3, 4, 5));


//按条件查询 -- selectByMap
HashMap<String, Object> map = new HashMap<>();
map.put("name","辰"); //自定义查询条件
List<User> users = userMapper.selectByMap(map);


分页查询

1、拦截器配置类

@MapperScan("com.chen.demo.mapper")
@EnableTransactionManagement //自动管理事务
@Configuration //配置类
public class MybatisPlusConfig {

@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

//注册乐观锁插件
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());

//分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));

return interceptor;
}

}

2、使用

//pageNo , pageSize
Page<User> page = new Page<>(2,2);
userMapper.selectPage(page,null);

page.getPages(); //一共多少页
page.getTotal();//一共多少条数据
page.getCurrent(); //当前第几页
page.getRecords();//获取分页后的数据


删除

//单个删除  -- deleteById
userMapper.deleteById(1L);


//批量删除 -- deleteBatchIds
userMapper.deleteBatchIds(Arrays.asList(1,2,3));


//指定删除(动态) -- deleteByMap
HashMap<String, Object> map = new HashMap<>();
map.put("email","99999999999999@qq/com");
userMapper.deleteByMap(map);


逻辑删除

物理删除:从数据库中直接移除

逻辑删除:再数据库中没有被移除,而是通过一个变量来让他失效!deleted = 0 => deleted = 1

1、数据库表增加删除字段:deleted

2、实体类字段增加注解:**@TableLogic**

@TableLogic  //逻辑删除
private Integer deleted;

3、配置插件

  • 配置文件
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)

4、使用

userMapper.deleteById(1);

本质上执行更新操作,把标记为删除的字段更改而已

查询的时候,会增加判断是否删除条件





条件构造器【*】

  • QueryWrapper

  • 编写查询条件

//查询name不为空,且邮箱不为空,	 --  isNotNull
//年龄大于等于18的用户 -- ge
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper
.isNotNull("name")
.isNotNull("email")
.ge("age",12);
userMapper.selectList(wrapper);//列表

//字符判断  -- eq  
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name","辰");
userMapper.selectOne(wrapper);//单一

//查询指定年龄 区间  -- between
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.between("age",1,7);
Integer integer = userMapper.selectCount(wrapper);//总数

//模糊查询  -- notLike不包含  -- likeLeft包含字符&通配符位置
QueryWrapper<User> wrapper = new QueryWrapper<>();
// 左/右 --> 通配符的位置 %c%
wrapper
.notLike("name","c")
.likeLeft("name","辰");

List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
maps.forEach(System.out::println);

//通过id进行排序  -- orderByDesc
QueryWrapper<User> wrapper = new QueryWrapper<>();

wrapper.orderByDesc("id");

List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);

//连接查询
QueryWrapper<User> wrapper = new QueryWrapper<>();

//id 在子查询中查询出来的
wrapper.inSql("id","select id from user where id < 3");

List<Object> objects = userMapper.selectObjs(wrapper);
objects.forEach(System.out::println);

  • lambdaQuery

通过方法引用的方式来使用实体字段名的操作,不需要手动写字段名防止写错

//  Wrappers.<实体>lambdaQuery()
LambdaQueryWrapper<User> lambda3 = Wrappers.<User>lambdaQuery();
lambda3.like(User::getName, "雨").lt(User::getAge, 40);
List<User> users = userMapper.selectList(lambda3);



代码生成器

  • 依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.0</version>
</dependency>


  • 只需要改实体类名字 和包名 还有 数据库配置即可
// 代码自动生成器
public class CCode {
public static void main(String[] args) {
// 需要构建一个 代码自动生成器 对象
AutoGenerator mpg = new AutoGenerator();

// 配置策略
// 1、全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath+"/src/main/java");
gc.setAuthor("ccc"); gc.setOpen(false);
gc.setFileOverride(false);

// 是否覆盖
gc.setServiceName("%sService");

// 去Service的I前缀
gc.setIdType(IdType.ID_WORKER);
gc.setDateType(DateType.ONLY_DATE);
gc.setSwagger2(true);
mpg.setGlobalConfig(gc);

//2、设置数据源
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/kuang_community? useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("123456");
dsc.setDbType(DbType.MYSQL); mpg.setDataSource(dsc);

//3、包的配置
PackageConfig pc = new PackageConfig();
//只需要改实体类名字 和包名 还有 数据库配置即可
pc.setModuleName("blog"); pc.setParent("com.kuang");
pc.setEntity("entity"); pc.setMapper("mapper");
pc.setService("service"); pc.setController("controller");
mpg.setPackageInfo(pc);

//4、策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setInclude("blog_tags","course","links","sys_settings","user_record"," user_say");

// 设置要映射的表名
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setEntityLombokModel(true);

// 自动lombok;
strategy.setLogicDeleteFieldName("deleted");

// 自动填充配置
TableFill gmtCreate = new TableFill("gmt_create", FieldFill.INSERT);
TableFill gmtModified = new TableFill("gmt_modified", FieldFill.INSERT_UPDATE);
ArrayList<TableFill> tableFills = new ArrayList<>();
tableFills.add(gmtCreate); tableFills.add(gmtModified);
strategy.setTableFillList(tableFills);

// 乐观锁
strategy.setVersionFieldName("version");
strategy.setRestControllerStyle(true);
strategy.setControllerMappingHyphenStyle(true);

// localhost:8080/hello_id_2
mpg.setStrategy(strategy);
mpg.execute(); //执行
}
}