栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

一篇搞定MyBatisPlus!

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

一篇搞定MyBatisPlus!

前言:该文章是以狂神说MyBatisPlus为参考,用以复习!初学者同样可以在这篇文章学到东西!
B站:狂神说MyBatisPlus地址:https://www.bilibili.com/video/BV17E411N7KN
狂神牛逼,强烈安利狂神!

配置环境

导入依赖:


    
        org.springframework.boot
        spring-boot-starter
    
    
        org.springframework.boot
        spring-boot-starter-test
        test
    
    
    
    
        com.baomidou
        mybatis-plus-boot-starter
        Latest Version
    
    
    
    
        mysql
        mysql-connector-java
        8.0.16
    
    
    
    
        org.projectlombok
        lombok
        1.18.12
        provided
    

  1. 配置数据库等

    yaml:

#数据库配置
spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.cj.jdbc.Driver
#日志配置
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

properties:

# 数据库配置
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8

# 日志配置 (默认控制台输出)
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

★CRUD扩展 1.插入数据
@Test
public void testInsert(){
    User user = new User();
    user.setName("codeyuaiiao");
    user.setAge(3);
    user.setEmail("747557612@qq.com");
    int result = userMapper.insert(user);
    System.out.println(result);
    System.out.println(user);

}

注意:插入的Id要是全局唯一Id

2.主键自增策略

默认 ID_WORKER 全局唯一id

对应数据库中的主键(uuid.自增id.雪花算法.redis.zookeeper)

★雪花算法(Twitter的snowflake算法)

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

★主键自增

我们需要配置主键自增:

  1. 实体类字段上@TableId(type = IdType.AUTO)

  1. 数据库字段一定要是自增! 数据库和实体类一定要对应!!!

3.其余的自增方式解读:

public enum IdType {
     
    AUTO(0),//数据库ID自增  
    NONE(1),//该类型为未设置主键类型      
    INPUT(2),//用户输入ID
      		 //该类型可以通过自己注册自动填充插件进行填充  

//以下3种类型、只有当插入对象ID 为空,才自动填充。     
    ID_WORKER(3),//全局唯一ID (idWorker)      
    UUID(4),//全局唯一ID (UUID)          
    ID_WORKER_STR(5);//字符串全局唯一ID (idWorker 的字符串表示)    

2.更新数据

注意这里的update的参数都是一个实体类,并不是Id!

@Test
public void testUpdate(){
    User user = new User();
    user.setId(2L);
    user.setEmail("32134@qq.com");
    user.setName("CJ");
    int update = userMapper.updateById(user);
    System.out.println(update);
}

传入的是user,但发现它确实是按照Id来更新数据的!

★3.自动填充

创建时间 . 修改时间! 这些个操作都是自动化完成的,我们不希望手动更新!

阿里巴巴开发手册:所有的数据库表:gmt_create .gmt_modified几乎所有的表都要配置上!而且需要自动化!

方式一:数据库级别

不推荐使用!因为要修改数据库!

1.在表中新增字段 create_time , update_time

2.实体类要对应上

重新新增,时间出来了!

方式二:代码级别

1.删除数据库默认值

2.实体类增加注解

@TableField(fill = FieldFill.INSERT)   //在插入时自动执行填充创建时间
private Date createTime;

@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;

3.处理器处理注解

@Slf4j    //打印一下日志  
@Component      //注入到IOC容器中,别忘了!!!
public class MyMetaObjectHandler implements MetaObjectHandler {
    
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill...");
//        default MetaObjectHandler setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject)
        this.setFieldValByName("createTime",new Date(),metaObject);
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update fill...");
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
}

新增测试,成功!

★4.乐观锁

乐观锁就是什么时候都认为不会出问题,干啥都不加锁,等出了问题再次更新值测试

悲观锁就是认为啥时候都会出问题,无论干啥都会上锁,然后操作

MP乐观锁实现

如下:

  • 取出记录时,获取当前version
  • 更新时,带上这个version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果version不对,就更新失败

1.添加version字段

2.同步实体类

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

3.注册组件 创建config包

// 这个扫描本来是在我们MybatisPlusApplication 主启动类中,现在我们把它放在配置类中
// 扫描mapper文件夹
@MapperScan("com.chen.mapper")
@EnableTransactionManagement  // 自动开启事务管理
@Configuration // 配置类
public class MybatisPlusConfig {

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

4.测试一下单线程中的乐观锁是否生效

// 测试乐观锁单线程成功
@Test
public void testOptimisticLock(){
    // 1、查询用户信息
    User user = userMapper.selectById(1);
    // 2、修改用户信息
    user.setName("xiaoshaung");
    user.setEmail("123123132@qq.com");
    // 3、执行更新操作
    userMapper.updateById(user);
}

看一下SQL语句:

确实添加有version这个条件!

5.测试一下多线程的乐观锁

 
 // 测试乐观锁多线程失败
@Test
public void testOptimisticLock2(){
    // 线程1
    User user = userMapper.selectById(1);
    user.setName("cangjian111");
    user.setEmail("32143455@qq.com");

    // 模拟另外一个线程执行了插队操作
    // 线程2
    User user2 = userMapper.selectById(1);
    user2.setName("cagnjian222");
    user2.setEmail("32143455@qq.com");
    userMapper.updateById(user2);

    // 自旋锁来多次尝试提交
    userMapper.updateById(user);
}

111被吞掉!

5.查询数据

测试查询有如下方法:

挨个测试一把!

//test select
@Test
public void testSelect(){
    User user = userMapper.selectById(2L);
    System.out.println(user);
}

//测试批量查询
@Test
public void testSelectBatchIds(){
    List users = userMapper.selectBatchIds(Arrays.asList(1,2,3,4));
    users.forEach(System.out::println);
}


//测试按条件查询
@Test
public void testSelectMap(){
    Map map = new HashMap<>();
    map.put("name","cangbaobao");
    map.put("age",6);
    //List selectByMap(@Param(Constants.COLUMN_MAP) Map columnMap);
    List users = userMapper.selectByMap(map);
    users.forEach(System.out::println);
}

★6.逻辑删除

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

逻辑删除:实际上没有真正删除数据,数据还存在!只是用了一个字段来区分,在每次查询的时候都加上这个字段的where判断,就能达到一个逻辑删除的效果! 回收站就是用了逻辑删除实现的。

逻辑删除的步骤:

1,增加数据库字段!

2.实体类同步!

// 逻辑删除注解
@TableLogic
private Integer deleteId;

3.配置逻辑是删除组件!

// 逻辑删除组件   高版本无序写这个配置   已经自动集成!
@Bean
public ISqlInjector iSqlInjector(){
    return new LogicSqlInjector();
}

4.测试一下删除,发现有如下方法

这里直接用deleteById测试:

//test delete
@Test
public void testDelete(){
    userMapper.deleteById(6L);
}

发现:它竟然走的是update操作!

之后正常的查询将无法查询到它,这就是逻辑查询!!!

7.分页查询

Mybatis-Plus也内置了分页插件!

1.集成分页插件:

// 最新版
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
    return interceptor;
}

2.可以用了:

    @Test
    public void testPage(){
//        > E selectPage(E page, @Param(Constants.WRAPPER) Wrapper queryWrapper);
        Page page = new Page<>(1,5);
        userMapper.selectPage(page, null);

        page.getRecords().forEach(System.out::println);
        System.out.println("getCurrent()"+page.getCurrent());
        System.out.println("page.getSize()"+page.getSize());
        System.out.println("page.getTotal()"+page.getTotal());

    }

3.

实际上调用的也是limit!

性能分析插件 ★★条件构造器★★

一些重要的方法:

eq :

  • 等于 =
  • 例: eq("name", "老王")—>name = '老王'

ne :

  • 不等于 <>
  • 例: ne("name", "老王")—>name <> '老王'

gt :

  • 大于 >
  • 例: gt("age", 18)—>age > 18

ge :

  • 大于等于 >=
  • 例: ge("age", 18)—>age >= 18

lt :

  • 小于 <
  • 例: lt("age", 18)—>age < 18

le :

  • 小于等于 <=
  • 例: le("age", 18)—>age <= 18

between :

  • BETWEEN 值1 AND 值2
  • 例: between("age", 18, 30)—>age between 18 and 30

not between :

  • NOT BETWEEN 值1 AND 值2
  • 例: notBetween("age", 18, 30)—>age not between 18 and 30

like :

  • LIKE ‘%值%’
  • 例: like("name", "王")—>name like '%王%'

notLike :

  • NOT LIKE ‘%值%’
  • 例: notLike("name", "王")—>name not like '%王%'

likeLeft :

  • LIKE ‘%值’
  • 例: likeLeft("name", "王")—>name like '%王'

likeRight :

  • LIKE ‘值%’
  • 例: likeRight("name", "王")—>name like '王%'

isNull :

  • 字段 IS NULL
  • 例: isNull("name")—>name is null

isNotNull :

  • 字段 IS NOT NULL
  • 例: isNotNull("name")—>name is not null

还有好多,可以在官网上找到,写得都很详细!!!

一些测试:

@Test
public void test1(){
    // 查询 name 不为空的用户,并且邮箱不为空的用户,年龄大于等于20
    //控制台查询的语句:SELECT id,age,email,name,version,delete_id,create_time,update_time FROM user WHERe delete_id=0 AND (name IS NOT NULL AND email IS NOT NULL AND age >= ?)
    QueryWrapper queryWrapper = new QueryWrapper<>();
    queryWrapper.isNotNull("name")
                .isNotNull("email")
                .ge("age",20);
    userMapper.selectList(queryWrapper).forEach(System.out::println);
}
    @Test
    public void test2(){
        // 查询名字 CJ
//生成的SQL:SELECT id,age,email,name,version,delete_id,create_time,update_time FROM user WHERe delete_id=0 AND (name = ?)
        QueryWrapper queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name","CJ");
        User user = userMapper.selectOne(queryWrapper);
        System.out.println(user);
    }
    @Test
    public void test3(){
        //查询年龄在21到30的
//        sql : SELECT id,age,email,name,version,delete_id,create_time,update_time FROM user WHERe delete_id=0 AND (age BETWEEN ? AND ?)
        QueryWrapper queryWrapper = new QueryWrapper<>();
        queryWrapper.between("age",21,30);
        userMapper.selectList(queryWrapper).forEach(System.out::println);
    }
    @Test
    public void test4(){
        //模糊查询  查询名字中含有i的和email以3开头的
//        sql :SELECT id,age,email,name,version,delete_id,create_time,update_time FROM user WHERe delete_id=0 AND (name LIKE %i% AND email LIKE 3%)
        QueryWrapper queryWrapper = new QueryWrapper<>();
        queryWrapper.like("name","i")
                    .likeRight("email","3");
        userMapper.selectMaps(queryWrapper).forEach(System.out::println);
    }
// userMapper.selectList(queryWrapper).forEach(System.out::println);  selectList和selectMap的区别就是返回值形式的不同,一个是按照user表中属性顺序来,一个是安照map形式显示

    @Test
    public void test5(){
        //连接查询(内查询)  查找id<6的
//        sql :SELECT id,age,email,name,version,delete_id,create_time,update_time FROM user WHERe delete_id=0 AND (id IN (select id from user where id < 6))
        QueryWrapper queryWrapper = new QueryWrapper<>();
        queryWrapper.inSql("id","select id from user where id < 6");
        userMapper.selectList(queryWrapper).forEach(System.out::println);
    }
@Test
public void test6(){
    //根据id倒叙排列
    QueryWrapper queryWrapper = new QueryWrapper<>();
    queryWrapper.orderByDesc("id");
    userMapper.selectList(queryWrapper).forEach(System.out::println);
}
代码生成器

AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。

有两个版本:3.5.1以下和以上

我用的MP是3.4.2的,所以采用历史版本:

1.导入依赖:

        
        
            com.baomidou
            mybatis-plus-generator
            3.4.1
        
        
            org.apache.velocity
            velocity-engine-core
            2.3
        
        

2.编写一个自动生成类:注意包不要导错了 基本都是generator下的包

// 代码自动生成器
public class AutoGeneratorTest {
    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("CJ");
        gc.setOpen(false);
        gc.setFileOverride(false);  // 是否覆盖
        gc.setServiceName("%Service"); // 服务接口,去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/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2b8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("root");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);

        // 3、包的配置

        PackageConfig pc = new PackageConfig();
        pc.setModuleName("blog");
        pc.setParent("com.chen");
        pc.setEntity("entity");
        pc.setMapper("mapper");
        pc.setService("service");
        pc.setController("controller");

        mpg.setPackageInfo(pc);

        // 4、策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setInclude("user"); // 设置要映射的表名
        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);

        ArrayList 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();
    }
}

3.执行!

大功告成!!!

MP完结!!!!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1041259.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号