spring boot项目整合mybatis访问数据源
JAVA 8
Spring Boot 2.5.3
PostgreSQL 10 (on Windows)
org.mybatis:mybatis:3.5.7
---
目录
整合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中是关键字,无法使用。来自博客园
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的文档。
两个数据库: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 来玩玩。
在试验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 可以更好地玩耍吧
作者:AizenSousuke
2、