MyBatis Plus 导入IdType失败的解决
作者:青梅竹马丨两小无猜
MyBatis Plus 导入IdType失败
import com.baomidou.mybatisplus.annotation.IdType;
修正Entity模板IdType引入包名到
com.baomidou.mybatisplus.enums.IdType
所以修改为
import com.baomidou.mybatisplus.enums.IdType
既可
MybatisPlus学习笔记
一、MybatisPlus概述
1.MyBatisPlus可以节省我们大量工作时间,所有的CRUD代码它都可以自动化完成!
官网:https://mp.baomidou.com/ MyBatis Plus,简化 MyBatis
2.特性
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作, BaseMapper
- 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求, 以后简单的CRUD操作,它不用自己编写 了!
- 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
- 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 -Sequence),可自由配 置,完美解决主键问题 支持
- ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大 的 CRUD 操作
- 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
- 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用(自动帮你生成代码)
- 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
- 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、 Postgre、SQLServer 等多种数据库
- 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
- 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误 操作
二、快速入门
快速开始 | MyBatis-Plus (baomidou.com)
1.创建数据库
2.创建user表
3.创建springboot项目
4.导入相关依赖
<!--数据库驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--Lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--mybatis-plus--> <!-- mybatis-plus 是自己开发,并非官方的! --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.0.5</version> </dependency>
尽量不要同时导入mybatis和mybatis-plus,可能会出现问题
5.连接数据库
# 连接数据库(mysql 8) spring.datasource.username=root spring.datasource.password=123456 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver # useSSL:是否使用安全连接 spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
6.传统步骤:pojo–>dao(CRUD操作,配置mapper文件)–>service–>controller
6.使用mybatis-plus
pojo
package edu.ayit.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class User { private Long id; private String name; private int age; private String email; }
mapper接口
package edu.ayit.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import edu.ayit.pojo.User; import org.springframework.stereotype.Repository; //对应mapper类继承基本类 BaseMapper,泛型是对应的实体类类型 @Repository public interface UserMapper extends BaseMapper<User> { //所有的CRUD操作编写完成 }
要想主启动类扫描到mapper包下的接口,需要在主启动类上加上@MapperScan("edu.ayit.mapper")
使用
package edu.ayit; import edu.ayit.mapper.UserMapper; import edu.ayit.pojo.User; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.List; @SpringBootTest class MybatisPlusApplicationTests { @Autowired //所有方法都来自父类BaseMapper private UserMapper userMapper; @Test void contextLoads() { // 参数是一个Wrapper,条件构造器,这里先不写 List<User> users = userMapper.selectList(null); users.forEach(System.out::println); } }
三、配置日志
sql语句不可见,借助日志可见
# 配置日志 mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
四、CRUD扩展
1.Insert
@Test void testInsert(){ User user = new User(); user.setName("张三"); user.setAge(15); user.setEmail("123@qq.com"); int n = userMapper.insert(user); System.out.println(user); }
id没有设置,自动生成
ID生成
@Data @AllArgsConstructor @NoArgsConstructor public class User { /** * public enum IdType { * AUTO(0),自增,数据库也要设置自增 * NONE(1),未设置主键 * INPUT(2),手动输入 * ID_WORKER(3),默认的全局唯一id * UUID(4),全局唯一 uuid * ID_WORKER_STR(5);从ID_WORKER(3)中截取字符串作为主键 */ @TableId(type = IdType.AUTO) private Long id; private String name; private int age; private String email; }
2.Update
@Test void update(){ User user = new User(); user.setId(5L); user.setName("李四"); user.setAge(12); //根据Id更新数据库,但参数是实体类对象 userMapper.updateById(user);
根据参数自动拼接动态sql
3.自动填充
数据的创建时间和修改时间等,这些操作应该由数据库自动完成。
阿里巴巴开发手册规定:所有数据库表都要有gmt_create和gmt_modified两个字段,而且需要自动化。
方式一:数据库表级别(不推荐)
1.在表中新增字段create_time和update_time,并设置数据类型和默认值
2.修改实体类
@TableId(type = IdType.AUTO) private Long id; private String name; private int age; private String email; private Date createTime; private Date updateTime;
方式二:
1.清除数据库默认值
2.给实体类对应属性增加注解
@TableId(type = IdType.AUTO) private Long id; private String name; private int age; private String email; @TableField(fill = FieldFill.INSERT)//该字段在插入操作时填充 private Date createTime; @TableField(fill = FieldFill.INSERT_UPDATE)//该字段在插入和更新操作时填充 private Date updateTime;
3.编写处理器,处理注解
package edu.ayit.handler; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import org.apache.ibatis.reflection.MetaObject; import org.springframework.stereotype.Component; import java.util.Date; @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); } }
4.测试插入
5.测试更新
4.乐观锁
1.概念
乐观锁 :顾名思义,十分乐观,它总是认为不会出现问题,无论干什么不去上锁!如果出现了问题, 再次更新值测试
悲观锁:十分悲观,它总是认为会出现问题,无论干什么都会上锁!再去操作!
2.乐观锁实现方式
- 取出记录时,获取当前version
- 更新时,带上这个version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果version不对,就更新失败
乐观锁:先查询,获取版本号 version = 1 --线程1 update mybatis-plus set name = "zhangsan" ,version = version+1 where id = 1 and version = 1; --线程2 抢先完成,完成后version = 2,会导致线程1执行失败 update mybatis-plus set name = "zhangsan" ,version = version+1 where id = 1 and version = 1;
3.测试乐观锁
- 给数据库加上version字段
- 修改实体类代码
@TableId(type = IdType.AUTO) private Long id; private String name; private int age; private String email; @TableField(fill = FieldFill.INSERT) private Date createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime; @Version//乐观锁 private int version;
注册组件
package edu.ayit.config; import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; //可以将springboot主启动类上的@MapperScan("edu.ayit.mapper")移到这里 @Configuration public class MybatisPlusConfig { //注册乐观锁插件 @Bean public OptimisticLockerInterceptor optimisticLockerInterceptor() { return new OptimisticLockerInterceptor(); } }
5.查询操作
//查询全部 @Test void contextLoads() { // 参数是一个Wrapper,条件构造器,这里先不写 List<User> users = userMapper.selectList(null); users.forEach(System.out::println); /* for (User user : users) { System.out.println(user); }*/ } //测试查询 @Test public void testSelectById(){ User user = userMapper.selectById(2L); System.out.println(user); } //测试批量查询 @Test public void testSelectByBatchId(){ List<User> users = userMapper.selectBatchIds(Arrays.asList(1L, 2L, 3L)); users.forEach(System.out::println); } //按条件查询方法一:map操作 @Test void testSelectByCondition(){ Map map = new HashMap<String,Object>(); map.put("name","Tom"); map.put("age",28); List list = userMapper.selectByMap(map); list.forEach(System.out::println); }
6.分页查询
常见的分页方式:
- 原始的limit分页
- pageHelper第三方插件
- mybatis-plus也内置了第三方插件
内置插件如何使用?
1.配置拦截器组件(官网上有)
//注册分页插件 @Bean public PaginationInterceptor paginationInterceptor() { PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); return paginationInterceptor; }
2.直接使用page对象
//测试分页 @Test void testSelectByPage(){ //参数1:当前页 参数2:每页显示条数 Page<User> page = new Page<>(1,5); userMapper.selectPage(page, null); //获取该页所有记录 page.getRecords().forEach(System.out::println); //获取总数据条数 System.out.println(page.getTotal()); }
3.查询结果
7.删除操作
基本删除操作
//测试删除 @Test void testDelete(){ //根据id删除 userMapper.deleteById(1385852899430592517L); //根据id批次删除 userMapper.deleteBatchIds(Arrays.asList(1385852899430592518L,1385852899430592519L,1385852899430592520L)); //根据条件删除 HashMap<String, Object> map = new HashMap<>(); map.put("id",1385852899430592521L); userMapper.deleteByMap(map); }
8.逻辑删除
物理删除:从数据库中直接移除
逻辑删除:没有从数据库中移除,而是通过一个字段让它失效,如 deleted = 0 变成 deleted = 1
管理员可以查看被用户删除的记录,防止数据丢失,类似于回收站
测试
1.在数据库中增加一个deleted字段
2.增加实体类属性
@TableId(type = IdType.AUTO) private Long id; private String name; private int age; private String email; @TableField(fill = FieldFill.INSERT) private Date createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime; @Version//乐观锁 private int version; @TableLogic//逻辑删除 private int deleted;
3.配置逻辑删除组件
//逻辑删除组件 @Bean public ISqlInjector sqlInjector(){ return new LogicSqlInjector(); }
4.修改配置文件application.properties
# 配置逻辑删除 mybatis-plus.global-config.db-config.logic-delete-value=1 mybatis-plus.global-config.db-config.logic-not-delete-value=0
5.测试逻辑删除
//测试逻辑删除 @Test void testLogicDelete(){ userMapper.deleteById(1L); }
查询删除记录
查询不到,但记录没被删除,只是deleted字段的值被改变了,所以查询不到。
9.性能分析插件(新版本无)
作用
用于查找运行慢的sql。当某条sql语句超过设定时间,程序会停止运行。
测试
1.配置性能分析插件
/** * SQL执行效率插件 */ @Bean @Profile({"dev","test"})// 设置 dev test 环境开启,保证我们的效率 public PerformanceInterceptor performanceInterceptor() { PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor(); performanceInterceptor.setMaxTime(100); // ms设置sql执行的最大时间,如果超过了则不 执行 performanceInterceptor.setFormat(true); // 是否格式化代码 return performanceInterceptor; }
2.要在SpringBoot中配置环境为dev或者 test 环境!
spring.profiles.active=dev
五、条件构造器
官网资料:条件构造器 | MyBatis-Plus (baomidou.com)
测试
1.查询姓名不为空,邮箱不为空,年龄大于20岁的用户
@Autowired //所有方法都来自父类BaseMapper private UserMapper userMapper; @Test void contextLoads() { QueryWrapper<User> wrapper = new QueryWrapper<>(); //查询姓名不为空,邮箱不为空,年龄大于20岁的用户 wrapper.isNotNull("name") .isNotNull("email") .ge("age",20); List<User> users = userMapper.selectList(wrapper); System.out.println(users); }
2.查询名字等于“Tom”的用户
@Test void test2(){ //查询名字等于“Tom”的用户 /*HashMap<String, Object> map = new HashMap<>(); map.put("name","Tom"); List<User> users = userMapper.selectByMap(map);*/ QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.eq("name","Tom"); //List<User> users = userMapper.selectList(wrapper); //users.forEach(System.out::println); //查询一个用selectOne User user = userMapper.selectOne(wrapper); System.out.println(user); }
3.查询年龄在20~30岁之间的用户
@Test void test3(){ //查询年龄在20~30岁之间的用户 QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.between("age",20,30); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println); }
4.查询名字里面包含"三",且"三"在右边的用户
@Test void test4(){ //查询名字里面包含"三",且"三"在右边的用户 QueryWrapper<User> wrapper = new QueryWrapper<>(); //左:%val,右:val% wrapper.likeLeft("name","三"); //List<User> users = userMapper.selectList(wrapper); //也可以用selectMaps List<Map<String, Object>> maps = userMapper.selectMaps(wrapper); maps.forEach(System.out::println); }
5.根据id查询用户,但id不是直接赋值,而是根据查询语句(子查询)得到
@Test void test5(){ //根据id查询用户,但id不是直接赋值,而是根据查询语句(子查询)得到 QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.inSql("id","select id from user where id<4"); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println); }
6.根据id降序排序
@Test void test6(){ //根据id降序排序 QueryWrapper<User> wrapper = new QueryWrapper<>(); wrapper.orderByDesc("id"); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println); }
六、代码自动生成器
package edu.ayit.utils; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.annotation.IdType; 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.po.TableFill; import com.baomidou.mybatisplus.generator.config.rules.DateType; import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; import java.util.ArrayList; //代码自动生成器 public class MyGenerator { public static void main(String[] args) { //需要构建一个代码自动生成器对象 AutoGenerator generator = new AutoGenerator(); //配置生成策略 //1.全局配置,generator包下的GlobalConfig GlobalConfig globalConfig = new GlobalConfig();//generator包下的GlobalConfig //当前项目路径 String projectPath = System.getProperty("user.dir"); //指定自动生成文件存储的位置 globalConfig.setOutputDir(projectPath+"/src/main/java"); globalConfig.setAuthor("周");//作者 globalConfig.setOpen(false);//是否打开资源管理器 globalConfig.setFileOverride(false);//是否覆盖 globalConfig.setServiceName("%sService");//去Service层接口的"I"前缀 globalConfig.setIdType(IdType.ID_WORKER);//设置主键自动生成策略 globalConfig.setDateType(DateType.ONLY_DATE);//配置日期类型 globalConfig.setSwagger2(true);//开启Swagger generator.setGlobalConfig(globalConfig); //2.设置数据源 DataSourceConfig dataSourceConfig = new DataSourceConfig(); dataSourceConfig.setUsername("root"); dataSourceConfig.setPassword("123456"); dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver"); dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8"); dataSourceConfig.setDbType(DbType.MYSQL); generator.setDataSource(dataSourceConfig); //3.包的配置 PackageConfig packageConfig = new PackageConfig(); packageConfig.setModuleName("my");//默认是null packageConfig.setParent("edu.ayit");//默认是com.baomidou /*默认值 packageConfig.setEntity("entity"); packageConfig.setMapper("mapper"); packageConfig.setService("service"); packageConfig.setController("controller"); */ generator.setPackageInfo(packageConfig); //4.策略配置 StrategyConfig strategy = new StrategyConfig(); strategy.setInclude("user");/**设置要映射的表名,可以写多个(重要)*/ //下划线转驼峰命名 strategy.setNaming(NamingStrategy.underline_to_camel); strategy.setColumnNaming(NamingStrategy.underline_to_camel); //自动lombok strategy.setEntityLombokModel(true); //逻辑删除 strategy.setLogicDeleteFieldName("deleted"); //自动填充 TableFill createTime = new TableFill("create_time", FieldFill.INSERT); TableFill updateTime = new TableFill("update_time", FieldFill.INSERT_UPDATE); ArrayList<TableFill> tableFills = new ArrayList<>(); tableFills.add(createTime); tableFills.add(updateTime); strategy.setTableFillList(tableFills); //乐观锁 strategy.setVersionFieldName("version"); generator.setStrategy(strategy); //执行 generator.execute(); } }
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。