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("[email protected]");
		// 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 protected])
llo.user.UserRunner  : findu=User(id=1459829343234932738, name=tom, age=1, [email protected])

數據庫查詢結果:
lib1=# select * from guser;
         id          | name |    email     | age
---------------------+------+--------------+-----
 1459829343234932738 | tom  | [email protected] |   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  | [email protected] |   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  | [email protected] |   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  | [email protected] |   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、

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章