SpringBoot项目中如何使用MybatisPlus及其生成器,Mybatis,如何进行多数据源的配置和切换,如何配置数据库连接池,如何加密数据库用户名和密码(详细介绍及其为什么,实战版)

1.MybatisPlus使用和介绍

先不谈多数据源及其数据库连接池,就从最基础的MybatisPlus及其基础的数据库配置说起。
为什么使用:见名知意,Plus就是Mybatis的增强版本,并且支持原来Mybatis的配置及其写法。
(1)它简化了我们的CRUD的写法,简单来说它提供了很多CRUD的方法供我们直接使用
(2)它提供了代码生成器,可以帮我们直接生成entity,mapper,service,mapper的映射文件
主要作用就是(1),本来增删改也没啥含金量,能直接调用别人写好的不是更方便嘛。
下面直接上代码看看是怎么简化的。

1.1引入MybatisPlus起步依赖和数据库Mysql连接的依赖

        <!-- springboot基础依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <!-- web依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- mybatis-plus起步以来 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>

        <!--mysql连接依赖-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.32</version>
            <scope>runtime</scope>
        </dependency>

1.2创建数据库和对应的包名

数据库,我这就一个学生表student,方便我们进行测试

CREATE TABLE `student` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '学生姓名',
  `age` int NOT NULL COMMENT '学生年龄',
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=94 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='学生表';

现在创建我们的包,只创建包不创建具体的类,类我们下面用Mybatis提供给我们的代码生成器去生成,直接节省N倍工作量,创建entity,mapper,service,mapper的映射文件包xml。

1.3引入代码生成器依赖

        <!-- mybatis-plus代码生成器 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.5.1</version>
        </dependency>

它为我们提供了不同类型的模版类,例如生成entity的模板类,service的模板类,我们代码生成器最终生成的实体都是按照这个去生成的。
现在稍微看一下这个模板类,引入以来后已经帮我们提供了

接下来我们随便看一个,例如我们的实体类entity.java.vm,这里主要看一下他的大概样子即可。我随便截取一段。

其实它里面大都是if else操作。大概逻辑是如果存在,就显示,例如

这个相当于你做了序列化的配置我就把 private static final long serialVersionUID = 1L;这句话加到你的实体类中,一个实体所有的东西都是这么判断显示的,例如包,类名,字段,注释等等。

上面的模板类了解以后,我们接下来就写代码生成的工具类GenreatorUtil

public class GeneratorUtil {
    
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入作者: ");
        String author = scanner.nextLine();//作者
        System.out.print("请输入数据库表名: ");
        String tableName = scanner.nextLine();//数据库表名
        String url = "jdbc:mysql://127.0.0.1:3306/test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8";
        String username = "root";//数据库名用户
        String password = "daz123456";//数据库密码
        String path = System.getProperty("user.dir");//获取当前项目的根目录
        FastAutoGenerator.create(url,username, password)
                //全局配置
                .globalConfig(builder -> {
                    builder.author(author) // 设置作者
                            .fileOverride() // 覆盖已生成文件
                            .outputDir(path+"/src/main/java/")// 指定输出目录
                            .disableOpenDir()//禁止打开输出目录
                            .commentDate("yyyy/MM/dd");//设置日期格式

                })
                //包配置
                .packageConfig(builder -> {
                    builder.parent("com.test") // 设置父包名
                            .pathInfo(Collections.singletonMap(OutputFile.mapperXml, path+"/src/main/resources/xml")); // 设置mapperXml生成路径
                })
                //策略配置
                .strategyConfig(builder -> {
                    builder.addInclude(tableName); // 设置需要生成的表名
                    builder.entityBuilder()
                            .enableLombok()//开启lombok,不开启会帮你生成set,get方法
                            .formatFileName("%sDO")//生成的实体类的格式,%s:这个是表名
                            .idType(IdType.AUTO);//设置ID主键自增
                })
                .execute();
    }
    
}

上面的配置,每一项需要自己根据自己创建的目录去配置,需要输入作者和表名进行生成,最终它会根据我们的模板类去生成,我们先用它给我的模板去看看结果是什么。

看看我们生成的目录及其效果。

可以看出所有的都生成了,我们进去看看他提供的默认的模板,例如entity。

或多或少都存在一些小问题,此时就需要我们自己去定义一个符合我们要求的或者样式的。

1.4自定义代码生成的模板模板

其实就是把系统提供给我们的给修改了,如果我们在resources/templates目录下有定义这几个模板,优先会在那好我们定义的模板进行生成。我们如何自定义呢?其实很简单,把它提供给我们默认的直接copy到templates目录下面。拿我们的entity.java.vm举例子。

其实也很简单,就拿那个注释来举例,我们直接把P标签直接去掉,加上我们的@description xxx

还有那个setter,getter,我们也不要直接换成@Data。

其次是那个@TableId没有对齐我们给他设置对齐,就是把前面的空格删掉。

接下来,我们把原来生成的删掉重新生成看效果。

基本上所有的样式都成我们自定义的啦,按需修改就行,都是些微调简单的东西,service,mapper等其他的模板修改操作也是如此,这样我们的代码生成器就完成了,以后如果你想要生成代码直接走这个。如果你想要生成多个,当然也可以,输入表明的时候用","分隔开,搞个循环去创建,自己可以试试。

1.5看看MybatisPlus生成的service和mapper的与我们自己定义的区别

首先看mapper,其实就是多继承了一个BaseMapper

BaseMapper是什么?

其实可以看出就是为我们提供好了很多的增删改查的方法直接使用,这样我们不用再到mapper的映射文件去写sql了,简单的增删改也没必要写对吧。

接下里看一下service及其service的实现类。

其实可以看出来,Service继承了IService,那IService里面又有什么呢?

其实说白了,它里面放的也是增删改查的方法,并且多提供了一些方法,例如listByIds,那这里有个疑问,为什么mapper已经提供了,我们直接使用mapper的不就行了,为什么还要多出一个service,这就是我们三层结构的原因,你总不能在controller直接调用mapper层吧,不符合规范,我们一般在controller调用service,并且我们在service层还可以进行自定义的方法去调用。如果你非要在controller层去调用mapper,那我也没办法。

1.6在controller进行测试

在写之前,先将我们mapper层的@Mapper注解加上,生成的好像没有,并且生成的controller上面的@Controller要改成@RestController,所以你自定义去实现,或者手动加上或修改,再配一下application.yml文件连接数据库。

server:
  port: 9999
spring:
  application:
    name: test
  datasource:
    type:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: daz123456
    url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=true&rewriteBatchedStatements=true

我们现在看看我们查询有多简单,在我们生成的controller去写个获取列表的测试方法。

@RestController
@RequestMapping("/student")
public class StudentController {

    @Autowired
    private IStudentService iStudentService;

    @RequestMapping("/list")
    public List<StudentDO> list(){
        List<StudentDO> list = iStudentService.list();
        return list;
    }

}

可以看出我们就一行代码iStudentService.list就获取了列表,接下来介绍一下,条件查询我们该怎么去查。其实这个list是个重载的方法,支持我们传入一个参数叫wrapper。

这个wrapper,这里你可以把它理解为我们sql里面的where查询条件,他是接口,他的实现类如下

重点就看Querywrapper和UpdateWrapper就行。我们就直接看写法就行。

可见查出年龄全为23岁的啦,其实那个接下来就介绍一下QueryWapper条件查询常见的方法。

1.lambda,这个就是相当于将QueryWrapper换成了LambdaQueryWrapper的写法,这样就支持我们的lambda的写法,例如.eq方法的第一个参数,本来应该写个字段的名称例如"age",但是这样呢不易维护,如果你后期字段名称修改了,你很多地方都需要修改,那直接取类的某个字段作为字段名称的写法就很方便,并且以后修改了,只用改类里面,看起来也比较雅观。
2.eq方法,这个简单,前者就是字段名,后者是条件

这些全是,足够我们的查询使用了,自己私下都去试试每个方法是干嘛的。

它的修改方法以及传什么样的wrapper都已经告诉你了,自己都去试试,我这就不多介绍了。

下面就介绍一下它的分页查询怎么优化的,怎么更简单的。

1.7如何进行分页查询

作为后台系统来说,必不可少的就是分页查询,那MybatisPlus怎么实现的呢?
1.配置一个MybatisPlusInterceptor拦截器交给Spring去管理,编写MyabtisPlusConfig配置类

@Component
public class MybatisPlusConfig {
    /**
     * 分页插件,不配置否则分页不生效
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }

}

如果你不配置,下面我们虽然能去调用相关的方法,但是不会有分页的效果。

2.调用它的page方法。

可以可看到需要一个page参数和一个queryWrapper,queryWrapper已经有了,Page参数MybatisPlus也为我们提供好了,这个Page主要是为了设置,当前页和分页大小的。

完整代码:

@RequestMapping("/list")
    public List<StudentDO> list(){
        QueryWrapper<StudentDO> studentDOQueryWrapper = new QueryWrapper<>();//创建wrapper
        studentDOQueryWrapper.lambda().eq(StudentDO::getAge,23);//添加where查询条件
        Page<StudentDO> page = new Page<>(1,2);//配置当前页和分页大小
        Page<StudentDO> studentPage = iStudentService.page(page, studentDOQueryWrapper);
        return studentPage.getRecords();
    }

我们断点来看一下这个studentPgae分页结果是什么?
可以看到分页的信息,总条数这写结果都有,足够我们使用了。

所以可看出我们的分页查询也够用。

1.8为什么还要用Mybatis

虽然提供了我们很CRUD的方法,但是上面大都是单表或者是链一两张表都可以解决,但是如果我们一个查询涉及到多张表(7张左右),此时你没办法处理,你总不能查询一张拿出结果再查另外一张,以此类推,这个首先读取多少次磁盘暂且不说,你这样会非常麻烦,那么此时还是需要我们去写Mapper的映射文件,但是MybatisPlus也支持Mybatis的写法,只是application.yml配置文件的写法可能稍有不同。看看MybatisPlus的写法。

mybatis-plus:
  # xml扫描,多个目录用逗号或者分号分隔(告诉 Mapper 所对应的 XML 文件位置)
  mapper-locations: classpath:xml/*Mapper.xml
  # 以下配置均有默认值,可以不设置
  global-config:
    db-config:
      #主键类型  auto:"数据库ID自增" 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID";
      id-type: auto
      #字段策略 IGNORED:"忽略判断"  NOT_NULL:"非 NULL 判断")  NOT_EMPTY:"非空判断"
      field-strategy: NOT_EMPTY
      #数据库类型
      db-type: MYSQL
      logic-delete-field: flag  # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
      logic-delete-value: 0 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 1 # 逻辑未删除值(默认为 0)
  configuration:
    # 是否开启自动驼峰命名规则映射:从数据库列名到Java属性驼峰命名的类似映射
    map-underscore-to-camel-case: true
    # 如果查询结果中包含空值的列,则 MyBatis 在映射的时候,不会映射这个字段
    call-setters-on-nulls: true
    # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

可以看出我们可以配置mapper映射文件及其开启驼峰命名等等配置都是有的。

2.SpringBoot配置数据库连接池

2.1为什么使用数据库连接池

  1. 提高性能:通过复用已有的连接,减少创建和销毁连接的开销。
  2. 减少资源消耗:有效管理和限制同时连接数据库的数量,避免过度占用数据库资源。
  3. 增强应用响应速度:减少每次数据库操作时的连接建立时间,提高响应速度。
  4. 提高稳定性:提供连接池健康检查和故障恢复机制,确保连接的稳定性和可靠性。
  5. 支持并发访问:允许多个线程或用户同时安全地访问数据库,提升并发处理能力

2.2数据库连接池的种类介绍

Hikari:SpringBoot默认提供的
DBCP:Apache提供的
C3p0
Druid:由阿里巴巴提供,提供了强大的监控功能。
我们此处将一下Druid,好处就是提供了监控的功能。

2.3如何使用Druid数据库连接池

1.引入依赖

        <!-- druid数据库连接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.21</version>
        </dependency>

2.在application中配置druid的数据库连接池的配置

spring:
  application:
    name: test
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: daz123456
    url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=true&rewriteBatchedStatements=true
    type: com.alibaba.druid.pool.DruidDataSource
    # 数据连接池配置
    druid:
      #连接池最大连接数
      max-active: 150
      #获取连接的最大等待时间
      max-wait: 60000
      #连接池最小连接数
      min-idle: 15
      #连接池初始化大小
      initial-size: 15
      filters: stat,wall,slf4j
      connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
      max-pool-prepared-statement-per-connection-size: 20
      pool-prepared-statements: false
      test-on-borrow: false
      test-on-return: false
      test-while-idle: true
      validation-query: SELECT 1
      min-evictable-idle-time-millis: 300000
      time-between-eviction-runs-millis: 60000
      #监控信息   localhost:${server.port}/druid/login.html
      stat-view-servlet:
        login-username: xxx
        login-password: xxx
        #允许哪个机器登录
        allow:
        #sql监控开关
        enabled: true
      #url监控
      web-stat-filter:
        enabled: true
        #session监控
        session-stat-enable: true
      filter:
        stat:
          log-slow-sql: true
          slow-sql-millis: 1000

主要是配置datasource.type这个指定使用数据库连接池的类型,不指定默认使用Hikari。

下面就是durid数据库连接池的配置,例如最大连接数,最小连接数,最长连接等待时间,以及监控信息的配置,一定要做好监控,也发挥它的优势所在。

3.SpringBoot实现多数据源的配置

3.1为什么要进行多数据源的配置

1.读写分离:为了分担数据库的压力,一般是将增删改和读的操作分别操作不同的数据库。
2.不同模块所操作的数据源也是不同的,例如登录模块,核心业务模块和财务模块使用的数据库都是不同的,也需要配置多数据源

3.2如何进行多数据源的配置

1.引入dynamic的起步依赖

        <!-- 用来配置多数据源 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
            <version>2.5.5</version>
        </dependency>

2.在application进行配置多数据源

spring:
  autoconfigure:
    exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
  application:
    name: test
  datasource:
    dynamic:
      primary: master
      strict: false
      datasource:
        master:
          type: com.alibaba.druid.pool.DruidDataSource
          username: root
          password: daz123456
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=true&rewriteBatchedStatements=true

跟我们之前的写法稍有不同,这次是在配置我们datasource之前多了一个dynamic的配置。
dynamic.primary:这个是配置默认使用的数据源的。
dynamic.strict:这个是不开启严格检查,避免严格检查导致的报错。
上面还有一个配置spirng.autoconfiguration.exclude这个,必须要配置,排除druid数据库连接池的自动配置,否则他会跟我们配置的起冲突,导致启动项目时就会报错。
dynamic.datasource.xxx:这个xxx就是我们数据库的别名,用于我们后续使用,你有多少个我就配置多少个数据库,通过xxx名称来区分他们,现在我模拟两个数据源,一个主:(用来增删改),一个从数据库(用于读取),分别对应不同的数据库。
master(数据库test):
放一条数据,名字为张三
slaver_rea(数据库slave_test):也放一条数据,名字叫李四

接下来就是我们如何去使用不同的数据库。

3.3测试多数据源

其实就是一个注解即可,@DS("xxx"),就是你刚才配置的master或者slave_read

我现在写三个方法去测试,看看结果如何。

@RestController
@RequestMapping("/student")
public class StudentController {

    @Autowired
    private IStudentService iStudentService;

    /**
     * 1.不指定看看默认操作的数据源是不是我们primary指定的
     */
    @RequestMapping("/list")
    public List<StudentDO> list(){
        List<StudentDO> list = iStudentService.list();
        return list;
    }

    /**
     * 2.模拟向主数据库插入一条数据
     */
    @RequestMapping("/insert")
    public void insert(){
        StudentDO student = new StudentDO();
        student.setName("王五");
        student.setAge(30);
        iStudentService.save(student);
    }

    /**
     * 3.使用注解@DS指定从从数据库路进行读取数据
     */
    @DS("slave_read")
    @RequestMapping("/listBySlave")
    public List<StudentDO> listBySlave(){
        List<StudentDO> list = iStudentService.list();
        return list;
    }

}

方法一和方法二都未指定@DS从哪个数据库获取,默认就从我们的primary配置的master中获取。
我们master目前存储的是张三,方法一查询的结果也应该是张三

结果是对的,现在执行方法二,插入王五,再执行方法一,看看结果。

结果多了一条王五的数据。
我们再来看看方法三,它使用@DS注解指定从slave_read从数据库获取,里面只有一个李四,看结果

结果显示正确,也验证了我们的配置和想法,也实现了多数据源的配置。再来看看@DS这个注解

这个注解可以用在方法上,也可以用在类上。用在类上的时候是有一些数据库它并不分主从,例如财务模块的数据库,就不分主从,直接加在类上,不过具体还得分情况。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值