springboot之mybaitsPlus

mybaitsPlus是国内开发的,并不是springboot的项目,只是学习的时候直接就是适配的springboot。

在这里插入图片描述

MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 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 操作智能分析阻断,也可自定义拦截规则,预防误操作

快速开始

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user`
(
    id BIGINT NOT NULL COMMENT '主键ID',
    name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
    age INT NULL DEFAULT NULL COMMENT '年龄',
    email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
    PRIMARY KEY (id)
);


DELETE FROM `user`;

INSERT INTO `user` (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://192.168.52.3:3306/mybatisplus?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
    #    url: jdbc:mysql://192.168.66.3:3306/mybatis?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
    username: root
    password: root

mybatis-plus:
  configuration:
#    配置日志
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
package com.example.mybatisplus;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@MapperScan("com.example.mybatisplus.dao")
@SpringBootApplication
public class SpringbootMybatisplusApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootMybatisplusApplication.class, args);
    }

}

package com.example.mybatisplus.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.mybatisplus.pojo.User;
import org.springframework.stereotype.Repository;

// 继承基本的类 BaseMapper
// 所有的crud操作都已经编写完成了,不需要再写方法和xml了
// 如果需要复杂的查询,BaseMapper没有提供,编写的方式就和mybatis一样了
@Repository
public interface UserMapper extends BaseMapper<User> {


}

package com.example.mybatisplus;

import com.example.mybatisplus.dao.UserMapper;
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 SpringbootMybatisplusApplicationTests {


    @Autowired
    UserMapper userMapper;

    @Test
    void contextLoads() {

        List list = userMapper.selectList(null);
        System.out.println(list);
    }


	// 更新
	@Test
    public void testUpdate(){
        User user = new User(4L, "sundy", 19, "test19@163.com");
        userMapper.updateById(user);
    }

}

主键策略

在这里插入图片描述

// 数据库名与实体类名不一致时的映射
// @TableName("tb_user")
public class User {

    /**
     * public enum IdType {
     *     AUTO(0), 自增,数据库id也必须是自增
     *     NONE(1), 未设置主键
     *     INPUT(2), 手动输入
     *     ID_WORKER(3), 默认,全局唯一id
     *     UUID(4), uuid
     *     ID_WORKER_STR(5); // ID_WORKER 的string形式
     */
    @TableId
    private Long id;



@Test
    public void testInsert(){
        User user = new User();
        user.setName("ks");
        user.setAge(12);
        user.setEmail("139@qq.com");

        userMapper.insert(user);
        System.out.println(user);
        // ==>  Preparing: INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? )
        // ==> Parameters: 1765291692593553409(Long), ks(String), 12(Integer), 139@qq.com(String)

        // 在这儿我们并没有指定id,是mybatisplus帮我们生成的id
        // 主键的生成方式有 uuid 自增id 雪花算法 redis zookeeper
    }

自动填充

public class User {

	// 标记需要填充内容的字段
	// 实体类与表的名字不一样,也可以进行映射
	// exists 该字段是否在数据库表中存在
    @TableField(fill = FieldFill.INSERT,exists = false)
    private LocalDateTime createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;



package com.example.mybatisplus.handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

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

    // 更新时的填充策略
    @Override
    public void updateFill(MetaObject metaObject) {

        log.info("start update fill...");
        this.setFieldValByName("updateTime", LocalDateTime.now(),metaObject);

    }
}

乐观锁

在这里插入图片描述

public class User {
	@Version // 乐观锁version注解,同时给数据库添加version字段
    private Integer version;


// 注册组件
package com.example.mybatisplus.config;

import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@EnableTransactionManagement
@Configuration
public class MybatisPlusConfig {


    // 注册乐观锁插件
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor(){
        return new OptimisticLockerInterceptor();
    }


}

// 测试乐观锁成功
    @Test
    public void testOptimisticLockerSuccess(){
        User user = userMapper.selectById(1L);
        user.setAge(7);
//      ==>  Preparing: UPDATE user SET name=?, age=?, email=?, version=?, update_time=? WHERE id=? AND version=?
//      更新的时候会自动把version条件带上
        userMapper.updateById(user);
    }


    // 测试乐观锁失败!多线程下
    @Test
    public void testOptimisticLockerLose(){

        // 模拟线程1
        User user = userMapper.selectById(1L);
        user.setAge(1);
//      ==>  Preparing: UPDATE user SET name=?, age=?, email=?, version=?, update_time=? WHERE id=? AND version=?
//      更新的时候会自动把version条件带上


        User user2 = userMapper.selectById(1L);
        user2.setAge(2);
        // 模拟线程2 执行了插队操作

        // 执行更新操作的时候 线程1被线程2插队了
        userMapper.updateById(user2);
        userMapper.updateById(user); // 如果没有乐观锁就会覆盖插队线程的值
        // 如果非要更新成功,可以使用自旋锁来多次尝试提交!

        /**
         *
         *
         *
        Creating a new SqlSession
        SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6413d7e7] was not registered for synchronization because synchronization is not active
        2024-03-07 10:46:44.052  INFO 18316 --- [           main] c.e.m.handler.MyMetaObjectHandler        : start update fill...
        JDBC Connection [HikariProxyConnection@1759328722 wrapping com.mysql.jdbc.JDBC4Connection@67022ea] will not be managed by Spring
==>  Preparing: UPDATE user SET name=?, age=?, email=?, version=?, update_time=? WHERE id=? AND version=?
==> Parameters: sundy(String), 2(Integer), test163@163.com(String), 2(Integer), 2024-03-07 10:46:44.058(Timestamp), 1(Long), 1(Integer)
                <==    Updates: 1
        Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6413d7e7]





        Creating a new SqlSession
        SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@999b951] was not registered for synchronization because synchronization is not active
        2024-03-07 10:46:44.070  INFO 18316 --- [           main] c.e.m.handler.MyMetaObjectHandler        : start update fill...
        JDBC Connection [HikariProxyConnection@1708084589 wrapping com.mysql.jdbc.JDBC4Connection@67022ea] will not be managed by Spring
==>  Preparing: UPDATE user SET name=?, age=?, email=?, version=?, update_time=? WHERE id=? AND version=?
==> Parameters: sundy(String), 1(Integer), test163@163.com(String), 2(Integer), 2024-03-07 10:46:44.07(Timestamp), 1(Long), 1(Integer)
                <==    Updates: 0
        Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@999b951]
         */
    }

查询、分页、删除

mybatis-plus:
  configuration:
#    配置日志
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

  # 逻辑删除
  global-config:
    db-config:
      logic-delete-value: 1
      logic-not-delete-value: 0
public class User {
	@TableLogic // 逻辑删除
    private Integer deleted;


package com.example.mybatisplus.config;

import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@EnableTransactionManagement
@Configuration
public class MybatisPlusConfig {


    // 注册乐观锁插件
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor(){
        return new OptimisticLockerInterceptor();
    }

    // 分页插件
    @Bean
    public PaginationInterceptor paginationInterceptor(){

        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();

        return paginationInterceptor;
    }



    // 逻辑删除组件
    @Bean
    public ISqlInjector sqlInjector(){
        return new LogicSqlInjector();
    }


}

@Test
    public void testSelect(){
        User user = userMapper.selectById(1L);
        List<User> users = userMapper.selectList(null);
        List<User> users1 = userMapper.selectBatchIds(Arrays.asList(1L, 2L, 3L));

        Map<String,Object> map = new HashMap<>();
        map.put("name","sundy");
        List<User> users2 = userMapper.selectByMap(map);


        System.out.println(user);
        System.out.println(users);
        System.out.println(users1);
        System.out.println(users2);
    }



// 分页查询
    @Test
    public void testPage(){
        // 当前页面,每页多少条数据
        Page<User> page = new Page<>(1,5);
        userMapper.selectPage(page,null);
		// page中有分页的所有信息
        System.out.println(page.getRecords());
    }





@Test
    public void testDelete(){
        userMapper.deleteById(10L);
        userMapper.deleteBatchIds(Arrays.asList(8L,9L));

        Map<String,Object> map = new HashMap<>();
        map.put("name","ks");
        userMapper.deleteByMap(map);
    }

在这里插入图片描述
配置完后,删除的方法就变成了更新的操作,

性能分析插件

在这里插入图片描述

/**
     * sql执行效率插件
     * @return
     */
    @Bean
    @Profile({"dev","test"}) // 设置 dev test 环境开启
    public PerformanceInterceptor performanceInterceptor(){
        PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
        performanceInterceptor.setMaxTime(100); // ms 设置sql执行的最大时间,如果超过了则不执行
        // The SQL execution time is too large, please optimize !
        performanceInterceptor.setFormat(true); // 让sql更好看
        return performanceInterceptor;
    }




spring:
	profiles:
    	active: dev

条件构造器

在这里插入图片描述

@Test
    public void testWrapper(){


        System.out.println("=================isNotNull ge===================================");

        // 查询name、邮箱不为空,年龄大于等于12
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.isNotNull("name")
                .isNotNull("email")
                .ge("age",12);
        System.out.println(userMapper.selectList(userQueryWrapper));


        System.out.println("=================eq===================================");



        QueryWrapper<User> userQueryWrapper2 = new QueryWrapper<>();
        userQueryWrapper2.eq("name","sindy");
        System.out.println(userMapper.selectOne(userQueryWrapper2));



        System.out.println("=======================between=============================");

        QueryWrapper<User> userQueryWrapper3 = new QueryWrapper<>();
        userQueryWrapper3.between("age",15,20);
        userMapper.selectCount(userQueryWrapper3);
        System.out.println(userMapper.selectList(userQueryWrapper3));



        System.out.println("=======================like=============================");
        QueryWrapper<User> userQueryWrapper4 = new QueryWrapper<>();
        // AND name NOT LIKE '%e%'
        // AND email LIKE '%m'
        userQueryWrapper4
                .notLike("name","e")
                // %t
                .likeLeft("email","m");
        System.out.println(userMapper.selectList(userQueryWrapper4));






        System.out.println("=======================in=============================");
        QueryWrapper<User> userQueryWrapper5 = new QueryWrapper<>();


        // 这儿只是测试这么写,要不然直接id=就可以了
        /**
         * AND id IN (
         *             select
         *                 id
         *             from
         *                 user
         *             where
         *                 id < 3
         *         )
         */
        userQueryWrapper5.inSql("id","select id from user where id < 3");

        System.out.println(userMapper.selectList(userQueryWrapper5));



        System.out.println("=======================order by=============================");

        QueryWrapper<User> userQueryWrapper6 = new QueryWrapper<>();
        userQueryWrapper6.orderByDesc("age");
        System.out.println(userMapper.selectList(userQueryWrapper6));


    }

lambda 写法

@Test
    public void testLambdaWrapper(){

        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userLambdaQueryWrapper.eq(User::getAge,6);
        userLambdaQueryWrapper.eq(User::getName,"Tom");

        List<User> users = userMapper.selectList(userLambdaQueryWrapper);
    }

代码自动生成器

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>springboot-mybatisplus-codegenerate</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-mybatisplus-codegenerate</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.0.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>2.0</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.28</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>


</project>

package com.example.mybatisplus.codegenerate;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
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 org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Arrays;

// 代码自动生成器
@Component
public class CodeGenerate {

//    private static String staticDriverName;
//    private static String staticUrl;
//    private static String staticUsername;
//    private static String staticPassword;
//
//    @Value("${spring.datasource.driver-class-name}")
//    private String driverName;
//
//    @Value("${spring.datasource.url}")
//    private String url;
//
//    @Value("${spring.datasource.username}")
//    private String username;
//
//    @Value("${spring.datasource.password}")
//    private String password;
//
//    @PostConstruct
//    private void init(){
//        staticDriverName = driverName;
//    }






    public static void main(String[] args) {
        // 构建一个代码自动生成器对象
        AutoGenerator autoGenerator = new AutoGenerator();

        // 配置策略

        // 1. 全局配置
        GlobalConfig globalConfig = new GlobalConfig();
        // 只能到项目,不能到模块儿
        // C:\Users\EDY\Desktop\git\interview-materials\code\springboot-study-project
        String projectPath = System.getProperty("user.dir");
        globalConfig.setOutputDir(projectPath + "/springboot-mybatisplus-codegenerate/src/main/java");
        globalConfig.setAuthor("awu");
        globalConfig.setOpen(false); // 生成之后打开生成的文件夹
        globalConfig.setFileOverride(false); // 是否覆盖之前生成的
        globalConfig.setServiceName("%sService"); // todo
        globalConfig.setIdType(IdType.ID_WORKER);
        globalConfig.setDateType(DateType.ONLY_DATE);
        globalConfig.setSwagger2(true);
        autoGenerator.setGlobalConfig(globalConfig);

        // 2. 设置数据源
        DataSourceConfig dataSourceConfig = new DataSourceConfig();
        dataSourceConfig.setUrl("jdbc:mysql://192.168.52.3:3306/mybatisplus?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC");
        dataSourceConfig.setDriverName("com.mysql.jdbc.Driver");
        dataSourceConfig.setUsername("root");
        dataSourceConfig.setPassword("root");
        dataSourceConfig.setDbType(DbType.MYSQL);


        // 3. 包的配置
        PackageConfig packageConfig = new PackageConfig();
        packageConfig.setModuleName("blog");
        packageConfig.setParent("com.awu");  // com.awu.blog
        packageConfig.setEntity("pojo");
        packageConfig.setMapper("dao");
        packageConfig.setService("service");
        packageConfig.setController("controller");
        autoGenerator.setPackageInfo(packageConfig);


        // 4. 策略配置
        StrategyConfig strategyConfig = new StrategyConfig();
        strategyConfig.setInclude("user"); // 设置要映射的数据库的表
        strategyConfig.setNaming(NamingStrategy.underline_to_camel); // 数据库字段转下划线
        strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);
        strategyConfig.setEntityLombokModel(true);
        strategyConfig.setRestControllerStyle(true);
        strategyConfig.setLogicDeleteFieldName("deleted");


        // 自动填充配置
        TableFill createTime = new TableFill("create_time", FieldFill.INSERT);
        TableFill updateTime = new TableFill("update_time", FieldFill.INSERT_UPDATE);
        strategyConfig.setTableFillList(Arrays.asList(createTime,updateTime));
        autoGenerator.setStrategy(strategyConfig);


        // 乐观锁
        strategyConfig.setVersionFieldName("version");

        strategyConfig.setControllerMappingHyphenStyle(true); // localhost:8080/hello_id_2


        autoGenerator.setDataSource(dataSourceConfig);
        autoGenerator.execute();


    }
}

我一向讨厌睡眠的必要性,它跟死亡一样,能让最强大的人倒下。
纸牌屋

部分内容转载自:
https://www.bilibili.com/video/BV17E411N7KN/?p=5&spm_id_from=pageDriver&vd_source=64c73c596c59837e620fed47fa27ada7

  • 22
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值