狂神MyBatisPlus学习笔记

MyBatisPlus概述

简化Mybatis MyBatisPlus官网

本笔记是基于【狂神说Java】MyBatisPlus最新完整教程通俗易懂

MySQL版本 5.7(5.7以下的更新一下,不然后续学习自动填充会卡壳) 添加createTime和updateTime导致导入 SQL 时出现 Invalid default value for ‘create_time’ 报错解决方法

MyBatis-Plus版本 3.0.5

QuickStart

  1. 根据官网提供的数据导入mybatisplus数据库
  2. 创建mybatis_plus,springboot项目
  3. 导入依赖
<dependencies>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
    dependency>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-testartifactId>
        <scope>testscope>
    dependency>
    
    <dependency>
        <groupId>mysqlgroupId>
        <artifactId>mysql-connector-javaartifactId>
    dependency>
    
    <dependency>
        <groupId>org.projectlombokgroupId>
        <artifactId>lombokartifactId>
    dependency>
    
    <dependency>
        <groupId>com.baomidougroupId>
        <artifactId>mybatis-plus-boot-starterartifactId>
        <version>3.0.5version>
    dependency>
dependencies>
  1. 配置application.properties文件
# mysql 5 驱动不同 com.mysql.jdbc.Driver
# mysql 8 com.mysql.cj.jdbc.Driver 需要增加时区配置
spring.datasource.username=root
spring.datasource.password=250259
spring.datasource.url=jdbc:mysql://localhost:3306/mybatisplus?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
  1. 根据数据库设置pojo类
  2. 在mapper包下创建持久层接口UserMapper
@Repository // 代表持久层
public interface UserMapper extends BaseMapper<User> {
    // 所有CRUD文件已经生成
}
  1. 启动类
// 扫描mapper文件夹
@MapperScan("com.example.mapper")
@SpringBootApplication
public class MybatisPlusApplication {
    public static void main(String[] args) {
        SpringApplication.run(MybatisPlusApplication.class, args);
    }
}
  1. 测试类

System.out::println是什么?

@SpringBootTest
class MybatisPlusApplicationTests {
    @Autowired
    private UserMapper userMapper;

    @Test
    void contextLoads() {
//        参数是一个mapper,条件构造器
//        查询全部用户
        List<User> users = userMapper.selectList(null);
        users.forEach(System.out::println);
    }
}

图1 执行结果

狂神MyBatisPlus学习笔记_第1张图片

配置日志

我们所有的sql现在都是不可见的,我们希望知道它是怎么执行的,所以我们必须要看日志

  1. 添加application.properties配置信息
# 配置日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
  1. 运行测试类

图2 日志输出SQL语句

狂神MyBatisPlus学习笔记_第2张图片

CRUD扩展

Insert插入

@Test
public void testInsert() {
    User user = new User();
    user.setName("ccy");
    user.setAge(20);
    user.setEmail("[email protected]");
    int result = userMapper.insert(user); // 帮我们自动生成ID
    System.out.println(result); // 受影响的行数
    System.out.println(user); // ID会自动回填
}

图3 Insert自动生成ID并且回显在数据库中

狂神MyBatisPlus学习笔记_第3张图片

不难发现,我们在没有设置ID的情况下,自动生成了ID并且回显在了数据库里,这是基于mybatis-plus中基于主键ID的主键生成

主键生成策略

分布式唯一ID生成

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

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
//    对应数据库中的主键(uuid,自增id,雪花算法)
//    AUTO(0), 数据库ID自增,切记要设计数据库主键ID自增
//    NONE(1), 未设置主键
//    INPUT(2), 手动输入
//    ID_WORKER(3),	默认为全局唯一ID
//    UUID(4), 全局唯一ID
//    ID_WORKER_STR(5); ID_WORKER字符串表示法
    @TableId(type = IdType.ID_WORKER)
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

update更新

只改变ID为5L的姓名

@Test
    public void testUpdate() {
        User user = new User();
        user.setId(5L);
        user.setName("ccy");
        int result = userMapper.updateById(user);
        System.out.println(result);
    }

图4 Update操作

狂神MyBatisPlus学习笔记_第4张图片

增加改变年龄

@Test    public void testUpdate() {        User user = new User();        user.setId(5L);//      根据条件自动生成动态sql        user.setName("ccy");        user.setAge(21);        int result = userMapper.updateById(user);        System.out.println(result);    }

图5 与图4做对比动态生成SQL

狂神MyBatisPlus学习笔记_第5张图片

我们会发现,mybatis-plus会帮我们自动生成动态sql

自动填充

方式一:数据库级别(工作中不允许修改数据库)

  1. 在表中新增两个字段

图6 修改数据库

狂神MyBatisPlus学习笔记_第6张图片

  1. 更新pojo类
@Data@NoArgsConstructor@AllArgsConstructorpublic class User {    @TableId(type = IdType.ID_WORKER)    private Long id;    private String name;    private Integer age;    private String email;    private Date createTime;    private Date updateTime;}
  1. 再次执行测试类更新操作,结果update_time自动填充

图7 更新时间变化

狂神MyBatisPlus学习笔记_第7张图片

方式二:代码级别

  1. 删除数据库的默认值,更新操作

图8 修改数据库

狂神MyBatisPlus学习笔记_第8张图片

  1. pojo字段上添加注解
//    字段添加填充内容    @TableField(fill = FieldFill.INSERT)    private Date createTime;    @TableField(fill = FieldFill.INSERT_UPDATE)    private Date updateTime;
  1. 添加处理器MyMetaObjectHandler
@Component // 将注解处理器加入到IOC容器中
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {
    //    插入时的填充策略
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill");
//      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);
    }
}
  1. 测试插入,观察时间

图9 执行Insert操作后数据库变化

狂神MyBatisPlus学习笔记_第9张图片

  1. 测试更新,观察更新时间

图10 执行Update操作更新时间变化

狂神MyBatisPlus学习笔记_第10张图片

乐观锁

乐观锁和悲观锁

MyBatis-Plus——乐观锁

乐观锁实现方式:

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

图11 修改数据库

狂神MyBatisPlus学习笔记_第11张图片

  1. pojo类中添加字段和注解
@Version // 乐观锁version注解private Integer version;
  1. 在config包下添加配置类
// 扫描mapper文件夹,有了配置类以后就可以将启动类中的扫描移动到这里@MapperScan("com.example.mapper")@EnableTransactionManagement@Configurationpublic class MyBatisPlusConfig {    @Bean    public OptimisticLockerInterceptor optimisticLockerInterceptor() {        return new OptimisticLockerInterceptor();    }}
  1. 测试单一线程的乐观锁,查看version变化
    //    测试乐观锁    @Test    public void testOptimisticLocker() {//        查询用户信息        User user = userMapper.selectById(4L);//        修改用户信息        user.setName("shuang");        user.setEmail("[email protected]");//        执行更新操作        userMapper.updateById(user);    }

图12 SQL语句中判断条件新增version

狂神MyBatisPlus学习笔记_第12张图片

  1. 测试多线程乐观锁
    //    测试多线程乐观锁
    @Test
    public void testOptimisticLocker2() {
//        线程1
        User user = userMapper.selectById(3L);
        user.setName("fs");
        user.setEmail("[email protected]");
//        模拟另外一个线程执行了插队操作
        User user2 = userMapper.selectById(3L);
        user2.setName("ccy丶ccy");
        user.setEmail("[email protected]");
        userMapper.updateById(user2);

//        自旋锁来多次尝试操作!
        userMapper.updateById(user); // 如果没有乐观锁就会覆盖插队线程的值
    }

图13 乐观锁加持下version变化

狂神MyBatisPlus学习笔记_第13张图片

由于乐观锁的机制,version并没有变成3

查询操作

单一查询

//    测试单一查询
@Test
public void testSelectById() {
    System.out.println(userMapper.selectById(1L));
}

图14 单一查询

狂神MyBatisPlus学习笔记_第14张图片

批量查询

//    测试批量查询@Testpublic void testSelectBatchIds(){    ArrayList list = new ArrayList<>();    list.add(1L);    list.add(2L);    list.add(3L);    List users = userMapper.selectBatchIds(list);    users.forEach(System.out::println);}

图15 批量查询

狂神MyBatisPlus学习笔记_第15张图片

条件查询

图16 条件查询

//    条件查询@Testpublic void test() {    HashMap map = new HashMap<>();    map.put("name", "ccy");    map.put("age", 21);    List users = userMapper.selectByMap(map);    users.forEach(System.out::println);}

狂神MyBatisPlus学习笔记_第16张图片

分页查询

  1. 添加分页插件
//    分页插件@Beanpublic PaginationInterceptor paginationInterceptor() {    return new PaginationInterceptor();}
  1. 执行测试类
    //    分页查询    @Test    public void testPage() {//        参数一:当前页//        参数二:页面大小        Page page = new Page<>(1, 3);        userMapper.selectPage(page, null);        page.getRecords().forEach(System.out::println);//        获得分页总数        System.out.println(page.getTotal());    }

图17 分页查询

狂神MyBatisPlus学习笔记_第17张图片

删除操作

单一删除

批量删除

@Testpublic void testDelete() {    userMapper.deleteBatchIds(Arrays.asList(5L,6L));}

图18 其他的一些方法就不再赘述了基本同查询操作类似

狂神MyBatisPlus学习笔记_第18张图片

逻辑删除

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

逻辑删除:从数据库中没有被移除,而是通过一个变量deleted让它失效

  1. 修改数据库,添加deleted字段并且设置初始值为0

图19 修改数据库

狂神MyBatisPlus学习笔记_第19张图片

  1. pojo类中添加字段和注解
@TableLogicprivate Integer deleted;
  1. application.properties配置逻辑删除信息
#配置逻辑删除mybatis-plus.global-config.db-config.logic-delete-value=1mybatis-plus.global-config.db-config.logic-not-delete-value=0
  1. config包下的配置类中添加逻辑删除组件
//    逻辑删除组件@Beanpublic ISqlInjector sqlInjector() {    return new LogicSqlInjector();}
  1. 启动测试类

图20 逻辑删除结果

狂神MyBatisPlus学习笔记_第20张图片

图21 执行Select同之前的改变

狂神MyBatisPlus学习笔记_第21张图片

性能分析插件

  1. application.properties配置开发环境
# 设置开发环境
spring.profiles.active=dev
  1. config包下的配置类中添加SQL执行效率插件
// SQL执行效率插件
@Bean
@Profile({"dev", "test"})// 设置dev test环境开启,保证我们的效率
public PerformanceInterceptor performanceInterceptor() {
    PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
    performanceInterceptor.setMaxTime(1); // 设置sql的执行的最大时间,如果超过了则不执行,单位毫秒
    performanceInterceptor.setFormat(true);
    return performanceInterceptor;
}
  1. 启动测试类

图22 SQL执行超时

狂神MyBatisPlus学习笔记_第22张图片

  1. 修改配置类信息performanceInterceptor.setMaxTime(100)
  2. 启动测试类

图23 成功执行

狂神MyBatisPlus学习笔记_第23张图片

条件构造器:条件Wrapper

Wrapper是遵循链式编程的

图24 wrapper方法

狂神MyBatisPlus学习笔记_第24张图片

测试

@SpringBootTest
class WrapperTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    void testGe() {
//        查询name不为空的用户,并且邮箱不为空的用户,年龄大于等于12
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.isNotNull("name")
                .isNotNull("email")
                .ge("age", 12);
        userMapper.selectList(wrapper).forEach(System.out::println);
    }

    @Test
    void testEq() {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("name", "shuang");
//        查询一个的时候使用selectOne,查询多个的时候使用map,list
        System.out.println(userMapper.selectOne(wrapper));
    }

    @Test
    void testBetween() {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.between("age", 20, 30);
        System.out.println(userMapper.selectCount(wrapper));
    }

    @Test
    void testLike() {
//        模糊查询
//        likeRight,likeLeft
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.like("name","ccy")
                .likeRight("email",1);
        List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
        maps.forEach(System.out::println);
    }

    @Test
    void testInSql() {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
//        子查询
        wrapper.inSql("id","select id from user where id < 3");
        List<Object> objs = userMapper.selectObjs(wrapper);
        objs.forEach(System.out::println);
    }

    @Test
    void test() {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
//        降序查询
        wrapper.orderByDesc("id");
        List<User> list = userMapper.selectList(wrapper);
        list.forEach(System.out::println);
    }
}

代码生成器

public class KuangCode {
    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("狂神说");
        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();
        //执行
    }
}

图25 代码生成器效果图

狂神MyBatisPlus学习笔记_第25张图片

你可能感兴趣的:(学习笔记,mysql,数据库,java)