zoukankan      html  css  js  c++  java
  • spring boot项目整合mybatis访问数据源

    JAVA 8

    Spring Boot 2.5.3

    PostgreSQL 10 (on Windows)

    org.mybatis:mybatis:3.5.7

    ---

    目录

    前言

    试验1:连接单个数据库(源)

    关于数据库连接池

    试验2:连接两个数据库(源)——lib1、lib2

    试验3:动态数据库——2个数据库(源)

    参考文档

    前言

    mybatis百度百科

    整合mybatis,可以方便地对数据库进行操作——关系型数据库

    mybatis最新版本:3.5.7(Apr, 2021)

    # Maven
    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.7</version>
    </dependency>
    
    # Gradle
    // https://mvnrepository.com/artifact/org.mybatis/mybatis
    implementation group: 'org.mybatis', name: 'mybatis', version: '3.5.7'
    

    上面的jar包,再加上对于的数据库驱动就可以使用了(尚未实践)。

    s.b. 中,也提供了官方依赖包:

    对应的依赖包如下:最新版 2.2.0 (May, 2021)

    <!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.2.0</version>
    </dependency>
    
    // https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter
    implementation group: 'org.mybatis.spring.boot', name: 'mybatis-spring-boot-starter', version: '2.2.0'

    其下依赖包:

    不过,本文没有使用 这个依赖包(没用过),于是,找到 参考文档1 ,使用其中的 com.baomidou:mybatis-plus-boot-starter 来进行试验。

    最新版 3.4.3.4(Sep, 2021)。

    <!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.4.3.4</version>
    </dependency>
    
    // https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter
    implementation group: 'com.baomidou', name: 'mybatis-plus-boot-starter', version: '3.4.3.4'

    其下依赖包:

    相比于官方的 mybatis-spring-boot-starter,多了 mybatis-plus包。

    MyBatis-Plus官网:https://baomidou.com/

    baomidou:苞米豆

    添加数据库PostgreSQL的驱动,即可开始。来自博客园

    s.b.官方也提供了PostgreSQL驱动:

    <dependency>
    	<groupId>org.postgresql</groupId>
    	<artifactId>postgresql</artifactId>
    	<scope>runtime</scope>
    </dependency>

    最新的是 42.3.1(Oct, 2021),而和 本文的 s.b. 2.5.3对应的是 42.2.23(Jul, 2021)。

    注:

    mybatis的包好多啊,除了上面的,还有 分页插件、代码生成器、通用Mapper 等,还没体验过呢!

    本文不涉及这些功能,或许另文进行。

    对了,还要和 Druid连接池 配合使用。

    那么,开始吧!

    依赖包汇总:

    项目3大依赖包
    <dependency>
    	<groupId>com.baomidou</groupId>
    	<artifactId>mybatis-plus-boot-starter</artifactId>
    	<version>3.4.3.4</version>
    </dependency>
    <dependency>
    	<groupId>org.postgresql</groupId>
    	<artifactId>postgresql</artifactId>
    	<scope>runtime</scope>
    </dependency>
    <dependency>
    	<groupId>org.projectlombok</groupId>
    	<artifactId>lombok</artifactId>
    	<optional>true</optional>
    </dependency>

    两个数据表:guser、device

    注,本来要建立 user表的,但是,user 在PostgreSQL中是关键字,无法使用。来自博客园

    试验1:连接单个数据库(源)

    guser的相关内容在 user包下,device的相关内容在 device包下。

    User:

    User和UserMapper
    @Data
    @TableName("guser") // import com.baomidou.mybatisplus.annotation.TableName; 指定表名为 guser
    public class User {
    	
        private Long id;
        private String name;
        private Integer age;
        private String email;
    	
    }
    
    // import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    public interface UserMapper extends BaseMapper<User> {
    
    }
    

    Device:

    Device和DeviceMapper
    @Data
    public class Device {
    
        private Long id;
        private Long sn;
        private String name;
        private Date createTime;
        
    }
    
    public interface DeviceMapper extends BaseMapper<Device> {
    }

    注,BaseMapper由 苞米豆 提供,包含一些方法。

    数据源配置:

    # application.properties
    spring.datasource.url=jdbc:postgresql://localhost:5432/lib1
    spring.datasource.username=postgres
    spring.datasource.password=123456
    spring.datasource.driver-class-name=org.postgresql.Driver

    使用@MapperScans+@MapperScan:来自博客园

    @SpringBootApplication
    // 扫描*Mapper
    @MapperScans({
    	@MapperScan(value="org.lib.postgresqlhello.user"),
    	@MapperScan(value="org.lib.postgresqlhello.device"),
    })
    public class PostgresqlHelloApplication {
    	// ...入口类,省略...
    }

    启动项目:启动成功(伪成功,此时还没有建立数据表呢,,mybatis不自动检测&建立吗?Spring Data JPA会自动建立的)。

    建立UserRunner 使用 UserMapper Bean操作数据:

    @Component
    @Slf4j
    public class UserRunner implements ApplicationRunner {
    
    	@Autowired
    	private UserMapper um;
    	
    	@Override
    	public void run(ApplicationArguments args) throws Exception {
    		User u = new User();
    		u.setName("tom");
    		u.setAge(1);
    		u.setEmail("tomt@lib.org");
    		// 1、新增
    		int ret1 = um.insert(u);
    		log.warn("ret1={}, u={}", ret1, u);
    		// 2、查询byId
    		User findu = um.selectById(u.getId());
    		log.warn("findu={}", findu);
    	}
    
    }

    启动项目:启动失败。

    启动错误日志
    Caused by: org.springframework.jdbc.BadSqlGrammarException: 
    ### Error updating database.  Cause: org.postgresql.util.PSQLException: 错误: 关系 "guser" 不存在
      位置:13
    ### The error may exist in org/lib/postgresqlhello/user/UserMapper.java (best guess)
    ### The error may involve org.lib.postgresqlhello.user.UserMapper.insert-Inline
    ### The error occurred while setting parameters
    ### SQL: INSERT INTO guser  ( id, name, age, email )  VALUES  ( ?, ?, ?, ? )
    ### Cause: org.postgresql.util.PSQLException: 错误: 关系 "guser" 不存在
      位置:13
    ; bad SQL grammar []; nested exception is org.postgresql.util.PSQLException: 错误: 关系 "guser" 不存在
      位置:13

    建立数据表 guser、device:来自博客园

    create table guser(id bigserial primary key, name varchar(100), email varchar(100), age integer);
    
    create table device(id bigserial primary key, sn bigint, name varchar(100),create_time timestamp default now());

    创建成功,再次启动项目:启动成功,数据添加、查询成功

    启动日志:
    device.DeviceRunner  : ret1=1, dv=Device(id=1459829342484152322, sn=123, name=device1, createTime=null)
    device.DeviceRunner  : finddv=Device(id=1459829342484152322, sn=123, name=device1, createTime=Sun Nov 14 18:23:32 CST 2021)
    llo.user.UserRunner  : ret1=1, u=User(id=1459829343234932738, name=tom, age=1, email=tomt@lib.org)
    llo.user.UserRunner  : findu=User(id=1459829343234932738, name=tom, age=1, email=tomt@lib.org)
    
    数据库查询结果:
    lib1=# select * from guser;
             id          | name |    email     | age
    ---------------------+------+--------------+-----
     1459829343234932738 | tom  | tomt@lib.org |   1
    (1 行记录)
    
    
    lib1=# select * from device;
             id          | sn  |  name   |        create_time
    ---------------------+-----+---------+----------------------------
     1459829342484152322 | 123 | device1 | 2021-11-14 18:23:32.383509
    (1 行记录)

    注意,

    数据库插入成功了,但是其 id不是像mysql一样是从1自增的,没有规律。这样看来,苞米豆 的 BaseMapper 对 PostgreSQL的支持不是太好的——需要自己写mapper的方法来实现,另文介绍。

    总之,数据库连接成功,可以操作数据了。

    说明:

    本试验 还没有用到各个Mapper 对应的*Mapper.xml 文件,后文再介绍。

    关于数据库连接池

    s.b.默认使用 HikariCP连接池,和数据库建立10个连接。

    在本试验中,如果没有 runner,默认是 不启用连接池的,此时,没有和数据库建立连接

    在 启用 runner后,需要操作数据库,此时会使用HikariCP连接池——默认和数据库建立10个连接。

    可以使用下面的命令查询:

    select pid,datid,datname,usename,application_name,state from pg_stat_activity;

    其中,application_name为“PostgreSQL JDBC Driver”的连接就是 连接池建立的。

    现在更换为 Druid连接池:添加依赖包,即可。

    <!-- https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.1.20</version>
    </dependency>
    
    // https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter
    implementation group: 'com.alibaba', name: 'druid-spring-boot-starter', version: '1.1.20'

    注,1.1.20(Aug, 2019)不是当前最新版本(1.2.8(Oct, 2021))。来自博客园

    启动项目,可以在日志中看到“c.a.d.s.b.a.DruidDataSourceAutoConfigure : Init DruidDataSource”,说明已经在使用 Druid连接池了。

    不过,Druid默认只建立一个 连接,可以配置。

    更多内容,可以看 Druid的文档。

    试验2:连接两个数据库(源)——lib1、lib2

    两个数据库:lib1、lib2,本试验来自同一个数据库服务器。

    更改配置文件:

    # 试验2:多数据库(源),2个
    # 数据库lib1
    # 多数据源时使用 jdbc-url
    #spring.datasource.one.url=jdbc:postgresql://localhost:5432/lib1
    spring.datasource.one.jdbc-url=jdbc:postgresql://localhost:5432/lib1
    spring.datasource.one.username=postgres
    spring.datasource.one.password=123456
    spring.datasource.one.driver-class-name=org.postgresql.Driver
    
    # 数据库lib2
    # 多数据源时使用 jdbc-url
    #spring.datasource.two.url=jdbc:postgresql://localhost:5432/lib2
    spring.datasource.two.jdbc-url=jdbc:postgresql://localhost:5432/lib2
    spring.datasource.two.username=postgres
    spring.datasource.two.password=123456
    spring.datasource.two.driver-class-name=org.postgresql.Driver

    注意,其中的 url 被替换为了 jdbc-url!否则,失败!

    取消 入口类PostgresqlHelloApplication的@MapperScans注解。

    添加2个数据源的配置类:DataSource1Config.java、DataSource2Config.java

    两个类 类似,下面是 DataSource1Config.java,修改其中的 类名、DS_TAG的值即可变为 DataSource2Config.java。

    关于@Primary 注解的使用:一般只在其中一个使用,但试验显示,两个都添加也行,但哪个是 主数据源呢?s.b.中的 主数据源有什么用呢?TODO

    另外,入口类的 @MapperScans迁到这里了。

    注意,@MapperScan有两个,但是,只启用了一个。原因是,两个数据源配置 类都扫描的话,会出现错误,导致项目启动失败。因此,数据源1 扫描user包,数据源2 扫描device包。

    注意,参考文档1 使用的是 SqlSessionFactoryBean,但启动不了,改为 MybatisSqlSessionFactoryBean 就可以了。来自博客园

    package org.lib.postgresqlhello.config;
    
    import javax.sql.DataSource;
    
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.SqlSessionTemplate;
    import org.mybatis.spring.annotation.MapperScan;
    import org.mybatis.spring.annotation.MapperScans;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.boot.jdbc.DataSourceBuilder;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
    
    import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
    
    /**
     * 数据源1
     * @author ben
     * @date 2021-11-04 20:50:28 CST
     */
    @Configuration
    @MapperScans({
    	@MapperScan(value="org.lib.postgresqlhello.user", sqlSessionFactoryRef = DataSource1Config.DS_TAG + "SqlSessionFactory")
    //	@MapperScan(value="org.lib.postgresqlhello.device", sqlSessionFactoryRef = DataSource1Config.DS_TAG + "SqlSessionFactory")
    })
    public class DataSource1Config {
    	
    	public static final String DS_TAG = "lib1";
    	public static final String DS_CONFIG_PREFIX = "spring.datasource.one";
    	
    	public static final String DS_NAME = DS_TAG + "DataSource";
    	public static final String DS_SSF = DS_TAG + "SqlSessionFactory";
    	public static final String DS_SSTLT = DS_TAG + "SqlSessionTemplate";
    
    	@Primary
    	@Bean(DS_NAME)
    	@ConfigurationProperties(prefix = DS_CONFIG_PREFIX)
    	public DataSource dataSource() {
    		return DataSourceBuilder.create().build();
    	}
    	
    	@Primary
    	@Bean(DS_SSF)
    	public SqlSessionFactory sqlSessionFactory(@Qualifier(DS_NAME) DataSource dataSource) throws Exception {
    		// 异常:org.apache.ibatis.binding.BindingException: Invalid bound statement (not found):
    //		SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
    		// 正常
    		MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
    		bean.setDataSource(dataSource);
    		
    		// 实践:下面的不一定要配置,,配置后可以在XML中写实现
    		// mapper的xml形式文件位置必须要配置,不然将报错
    		bean.setMapperLocations(new PathMatchingResourcePatternResolver()
    				.getResources("classpath*:/mapper/" + DS_TAG + "/*.xml"));
    		
    		return bean.getObject();
    	}
    	
    	@Primary
    	@Bean(DS_SSTLT)
    	public SqlSessionTemplate sqlSessionTemplate(@Qualifier(DS_SSF) SqlSessionFactory sqlSessionFactory) {
    		return new SqlSessionTemplate(sqlSessionFactory);
    	}
    }
    

    注意,@MapperScan注解的 sqlSessionFactoryRef属性 不要配置错了——看来,这个DS_TAG常量应该放到另外的地方。

    好了,开启Runner,启动项目:启动成功,数据操作成功,,lib1的user表新增了一条数据,lib2的device新增了一条数据。

    lib1=# select * from guser;
             id          | name |    email     | age |        create_time
    ---------------------+------+--------------+-----+---------------------------
     1459861260256710658 | tom  | tomt@lib.org |   1 | 2021-11-14 20:30:22.08904
    (1 行记录)
    
    
    lib1=#
    lib1=# \c lib2
    您现在已经连接到数据库 "lib2",用户 "postgres".
    lib2=# select * from device;
             id          | sn  |  name   |        create_time
    ---------------------+-----+---------+----------------------------
     1459861259325575170 | 123 | device1 | 2021-11-14 20:30:21.992877
    (1 行记录)

     来自博客园

    更多:前面提到 下面的 配置可以不需要

    // 实践:下面的不一定要配置,,配置后可以在XML中写实现
    // mapper的xml形式文件位置必须要配置,不然将报错
    bean.setMapperLocations(new PathMatchingResourcePatternResolver()
        .getResources("classpath*:/mapper/" + DS_TAG + "/*.xml"));

    无论是否配置,默认情况下,src/main/resources 下 可以没有 *Mapper.xml 文件。

    当然,可以添加——以便事项更丰富的数据操作功能。

    简单的示例:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="org.lib.postgresqlhello.user.UserMapper">
    
    </mapper>

    具体怎么使用,需要学习mybatis的相关知识。一般情况下,这里面会写很多业务相关的 CRUD等操作。

    小结:

    1、每个数据源一个配置,比较麻烦;

    2、项目开发之前,就需要设计好 哪些数据表 由哪个Mapper来操作;

    针对上面的问题,苞米豆 提供了动态数据源配置功能——dynamic-datasource-spring-boot-starter包,下面的 试验3 来玩玩。

    试验3:动态数据库——2个数据库(源)

    在试验2 的基础上进行改造。

    添加依赖包:

    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
        <version>2.5.6</version>
    </dependency>

    本文使用的是 2.5.6(Jul, 2019),最新版本是 3.4.1(Jul, 2021)。来自博客园

    配置:

    # 试验3:动态数据源
    # 使用Druid数据库连接池
    spring.datasource.dynamic.primary=lib1
    # lib1
    spring.datasource.dynamic.datasource.lib1.url=jdbc:postgresql://localhost:5432/lib1
    spring.datasource.dynamic.datasource.lib1.username=postgres
    spring.datasource.dynamic.datasource.lib1.password=123456
    spring.datasource.dynamic.datasource.lib1.driver-class-name=org.postgresql.Driver
    # lib2
    spring.datasource.dynamic.datasource.lib2.url=jdbc:postgresql://localhost:5432/lib2
    spring.datasource.dynamic.datasource.lib2.username=postgres
    spring.datasource.dynamic.datasource.lib2.password=123456
    spring.datasource.dynamic.datasource.lib2.driver-class-name=org.postgresql.Driver
    # other
    # 需要排除,否则会报错
    spring.autoconfigure.exclude=com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure

    注意,上面的主数据库为 lib1。

    注意,最后一行的配置是 需要的,否则,报错,也可以使用下面的配置类替代——主类上加注解:

    // baomidou-动态多数据源时,
    //加exclude 效果同 spring.autoconfigure.exclude的配置
    //@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)
    public class PostgresqlHelloApplication {

    取消 DataSource1Config、DataSource1Config 的配置:

    开启主类PostgresqlHelloApplication的 @MapperScans+@MapperScan的使用(同 单数据源)。

    好了,启动项目:启动成功,两个runner给 lib1 的数据表增加了记录:

    postgres=# \c lib1
    您现在已经连接到数据库 "lib1",用户 "postgres".
    lib1=#
    lib1=# select * from guser;
             id          | name |    email     | age |        create_time
    ---------------------+------+--------------+-----+----------------------------
     1459866409163321346 | tom  | tomt@lib.org |   1 | 2021-11-14 20:50:49.623428
    (3 行记录)
    
    
    lib1=# select * from device;
             id          | sn  |  name   |        create_time
    ---------------------+-----+---------+----------------------------
     1459866407779201026 | 123 | device1 | 2021-11-14 20:50:49.573958
    (2 行记录)

     来自博客园

    怎么把数据添加到 数据库lib2 的表你?使用 com.baomidou.dynamic.datasource.annotation.DS 注解

    package org.lib.postgresqlhello.user;
    
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    
    // 不使用时,默认是主库 lib1
    @DS("lib2")
    public interface UserMapper extends BaseMapper<User> {
    
    }
    
    // -----------------
    
    @DS("lib2")
    public interface DeviceMapper extends BaseMapper<Device> {
    
    }

    启动项目:启动成功,数据被写到了 lib2 的数据表了。

    lib1=# \c lib2
    您现在已经连接到数据库 "lib2",用户 "postgres".
    lib2=#
    lib2=# select * from guser;
             id          | name |    email     | age |        create_time
    ---------------------+------+--------------+-----+----------------------------
     1459867136388501506 | tom  | tomt@lib.org |   1 | 2021-11-14 20:53:43.003151
    (1 行记录)
    
    
    lib2=# select * from device;
             id          | sn  |  name   |        create_time
    ---------------------+-----+---------+----------------------------
     1459867134962438145 | 123 | device1 | 2021-11-14 20:53:42.948146
    (3 行记录)

    小结,

    好像,很方便了啊!写的代码少很多了!

    》》》全文完《《《

    只是用起来了,不过不太精通的啊!还需深入了解才是。来自博客园

    mybatis生态中,还有很多没玩呢,继续。

    其实,spring boot手册中 有一个 “Data Access”章,里面介绍了 访问多数据源的问题的。待试验,TODO

    目前的 spring boot手册中的内容如下:

    https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto.data-access

    变成第 8章 了,大家可以下载pdf下来学习的。来自博客园

    当然,把本文的 PostgreSQL 改为 MySQL 可以更好地玩耍吧

    参考文档

    1、springboot-整合多数据源配置

    作者:AizenSousuke

    2、

  • 相关阅读:
    学习笔记
    聊聊字节序
    SPDK发送和接收连接请求的处理
    企业设备维护——不仅仅是解决问题
    怎样快速找到某一行代码的git提交记录
    生产环境中利用软链接避免"rm -rf /"的方法
    程序员五年小结
    Django Model 数据库增删改查
    python中字符串列表字典常用方法
    python编辑配置
  • 原文地址:https://www.cnblogs.com/luo630/p/15552307.html
Copyright © 2011-2022 走看看