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、

  • 相关阅读:
    949. Largest Time for Given Digits
    450. Delete Node in a BST
    983. Minimum Cost For Tickets
    16. 3Sum Closest java solutions
    73. Set Matrix Zeroes java solutions
    347. Top K Frequent Elements java solutions
    215. Kth Largest Element in an Array java solutions
    75. Sort Colors java solutions
    38. Count and Say java solutions
    371. Sum of Two Integers java solutions
  • 原文地址:https://www.cnblogs.com/luo630/p/15552307.html
Copyright © 2011-2022 走看看