Mybatis-plus
注意:@MapperScan("mappeer包全路径")mapper接口实现BaseMapper会自动写好基本的CRUD语句参数是一个wapper,条件构造器
配置日志
mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
主键生成策略(uuid,自增id,雪花算法,redis,zookeeper)
@TableId(type = IdType.选择类型)ID_WORK 默认全局唯一idAUTO 自增id,注意:数据库也为自增NONE 未设置主键UUID 全局唯一idID_WORKER_STR(5) ID_WORK字符串表示法INPUT手动输入
雪花算法
snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生4096个id),最后还有一个符号位,永远是0。
自动填充
创建时间,修改时间
方式一:数据库级别(不建议使用)
设置自动更新时间戳
方式二:代码级别
1.加注解
@TableField(fill =FieldFill.属性)
INSERT 插入时填充内容
INSERT_UPDATE更新
2.编写handler处理
@Componentpublic class Mymothedhandler implements MetaObjectHandler { //插入的填充策略 @Override public void insertFill(MetaObject metaObject) { this.setFieldValByName("create_time",new Date(),metaObject); this.setFieldValByName("upadate_time",new Date(),metaObject); } //更新的填充策略 @Override public void updateFill(MetaObject metaObject) { this.setFieldValByName("upadate_time",new Date(),metaObject); }}
@Slf4j@Componentpublic class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { log.info("start insert fill ...."); this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐使用) // 或者 this.strictUpdateFill(metaObject, "createTime", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐) // 或者 this.fillStrategy(metaObject, "createTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug) } @Override public void updateFill(MetaObject metaObject) { log.info("start update fill ...."); this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐) // 或者 this.strictUpdateFill(metaObject, "updateTime", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐) // 或者 this.fillStrategy(metaObject, "updateTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug) }}
乐观锁
乐观锁:顾名思义十分乐观,认为不会出现问题,不上锁,如果出现问题再次更新值测试
悲观锁:它认为总是会出现问题,无论如何都上锁,再操作
乐观锁实现方式
1.取出记录时,获取当前version
2.更新时,带上这个version
3.执行更新时,set version =new version where version=oldversion
4.如果version不对,就更新失败
乐观锁插件
1.数据库加字段version
2.对应实体类加字段Integer version,加注解@version
3.配置mybatis-plus配置文件
@MapperScan("com.mybatisplus.demo.mapper")@EnableTransactionManagement@Configurationpublic class Mybatisplusconfig { //注册乐观插件 @Bean public OptimisticLockerInterceptor optimisticLockerInterceptor() { return new OptimisticLockerInterceptor(); }}
// 测试乐观锁成功 @Test public void testVersionSuccess(){ // 1. 查询用户信息 User user = userMapper.selectById(1L); // 2. 修改用户信息 user.setName("fan"); user.setAge(24); // 3. 执行更新操作 userMapper.updateById(user); } // 测试乐观锁失败!多线程下 @Test public void testVersionFall(){ // 线程1 User user1 = userMapper.selectById(1L); user1.setName("fan111"); user1.setAge(14); // 线程2 User user2 = userMapper.selectById(1L); user2.setName("fan222"); user2.setAge(24); userMapper.updateById(user2); //自旋锁来多次尝试提交! userMapper.updateById(user1); //如果没有乐观锁就会覆盖插队线程的值 }
查询
// 测试查询@Testpublic void testSelectById(){ User user = userMapper.selectById(1); System.out.println(user);}// 批量查询@Testpublic void testSelectByBatchIds(){ List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3)); users.forEach(System.out::println);}// 按照条件查询之一使用 map@Testpublic void testSelectByMap(){ HashMap<String, Object> map = new HashMap<>(); // 自定义要查询 map.put("name","Dainel"); map.put("age","6"); List<User> users = userMapper.selectByMap(map); users.forEach(System.out::println);}
分页插件
@Bean public PaginationInterceptor paginationInterceptor() { return new PaginationInterceptor(); }
Page<User> userPage=new Page<>(1,3); userMapper.selectPage(userPage,null); for (User record : userPage.getRecords()) { System.out.println(record); }
逻辑删除
物理删除:从数据库直接删除
逻辑删除:数据库没有移除,总是通过一个变量让他失效,字段deleted=>1
使用方法
1.数据库加deleted int 1字段
2.实体类加deleted Interger,加注解@TableLogic
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)
性能分析插件
// SQL执行效率插件@Bean@Profile({"dev","test"})public PerformanceInterceptor performanceInterceptor(){ PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor(); performanceInterceptor.setMaxTime(100); //ms 设置sql执行的最大时间,如果超过了则不执行 performanceInterceptor.setFormat(true); // 是否格式化 return performanceInterceptor;}
配置环境为dev环境
条件构造器(wrapper)
写复杂sql可以用他来替代
创建对应wapper QueryWrapper<User> userQueryWrapper=new QueryWrapper<>();
代码自动生成器
// 演示例子,执行 main 方法控制台输入模块表名回车自动生成对应项目目录中public class CodeGenerator { /** * * 读取控制台内容 * */ public static String scanner(String tip) { Scanner scanner = new Scanner(System.in); StringBuilder help = new StringBuilder(); help.append("请输入" + tip + ":"); System.out.println(help.toString()); if (scanner.hasNext()) { String ipt = scanner.next(); if (StringUtils.isNotBlank(ipt)) { return ipt; } } throw new MybatisPlusException("请输入正确的" + tip + "!"); } public static void main(String[] args) { // 代码生成器 AutoGenerator mpg = new AutoGenerator(); // 全局配置 GlobalConfig gc = new GlobalConfig(); String projectPath = System.getProperty("user.dir"); gc.setOutputDir(projectPath + "/src/main/java"); gc.setAuthor("jobob"); gc.setOpen(false); // gc.setSwagger2(true); 实体属性 Swagger2 注解 mpg.setGlobalConfig(gc); // 数据源配置 DataSourceConfig dsc = new DataSourceConfig(); dsc.setUrl("jdbc:mysql://localhost:3306/ant?useUnicode=true&useSSL=false&characterEncoding=utf8"); // dsc.setSchemaName("public"); dsc.setDriverName("com.mysql.jdbc.Driver"); dsc.setUsername("root"); dsc.setPassword("密码"); mpg.setDataSource(dsc); // 包配置 PackageConfig pc = new PackageConfig(); pc.setModuleName(scanner("模块名")); pc.setParent("com.baomidou.ant"); mpg.setPackageInfo(pc); // 自定义配置 InjectionConfig cfg = new InjectionConfig() { @Override public void initMap() { // to do nothing } }; // 如果模板引擎是 freemarker String templatePath = "/templates/mapper.xml.ftl"; // 如果模板引擎是 velocity // String templatePath = "/templates/mapper.xml.vm"; // 自定义输出配置 List<FileOutConfig> focList = new ArrayList<>(); // 自定义配置会被优先输出 focList.add(new FileOutConfig(templatePath) { @Override public String outputFile(TableInfo tableInfo) { // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!! return projectPath + "/src/main/resources/mapper/" + pc.getModuleName() + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML; } }); /* cfg.setFileCreate(new IFileCreate() { @Override public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) { // 判断自定义文件夹是否需要创建 checkDir("调用默认方法创建的目录,自定义目录用"); if (fileType == FileType.MAPPER) { // 已经生成 mapper 文件判断存在,不想重新生成返回 false return !new File(filePath).exists(); } // 允许生成模板文件 return true; } }); */ cfg.setFileOutConfigList(focList); mpg.setCfg(cfg); // 配置模板 TemplateConfig templateConfig = new TemplateConfig(); // 配置自定义输出模板 //指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别 // templateConfig.setEntity("templates/entity2.java"); // templateConfig.setService(); // templateConfig.setController(); templateConfig.setXml(null); mpg.setTemplate(templateConfig); // 策略配置 StrategyConfig strategy = new StrategyConfig(); strategy.setNaming(NamingStrategy.underline_to_camel); strategy.setColumnNaming(NamingStrategy.underline_to_camel); strategy.setSuperEntityClass("你自己的父类实体,没有就不用设置!"); strategy.setEntityLombokModel(true); strategy.setRestControllerStyle(true); // 公共父类 strategy.setSuperControllerClass("你自己的父类控制器,没有就不用设置!"); // 写于父类中的公共字段 strategy.setSuperEntityColumns("id"); strategy.setInclude(scanner("表名,多个英文逗号分割").split(",")); strategy.setControllerMappingHyphenStyle(true); strategy.setTablePrefix(pc.getModuleName() + "_"); mpg.setStrategy(strategy); mpg.setTemplateEngine(new FreemarkerTemplateEngine()); mpg.execute(); }}