SpringBoot多数据源(一)
- 1.多数据源使用场景
- 1.1 业务复杂(数据量大)
- 1.2 读写分离
- 2.多数据源配置
- 3.应用
- 4.测试
1.多数据源使用场景
1.1 业务复杂(数据量大)
简单理解就是业务量复杂,将庞大的数据拆到多个数据库中。或者由于公司有多个子项目,各用各的数据库,涉及数据共享
1.2 读写分离
为了解决数据库的读性能瓶颈(读比写性能更高,写锁会影响读阻塞,从而影响读的性能)。
与上述1.1不同的是,在读写分离中,主库和从库的数据库是一致的(不考虑主从延迟)。数据更新操作(insert
、update
、delete
)都是在主库上进行的,主库将数据更新信息同步给
从库。在查询时,可以在从库上进行。从而分担主库的压力。
2.多数据源配置
spring:datasource:#数据源1datasource1:driver-class-name: com.mysql.cj.jdbc.Driverjdbc-url: jdbc:mysql://localhost:3306/test_masterusername: rootpassword: rootdruid:initial-size: 1min-idle: 1max-active: 20test-on-borrow: true#数据源2datasource2:driver-class-name: com.mysql.cj.jdbc.Driverjdbc-url: jdbc:mysql://localhost:3306/test_slaveusername: rootpassword: rootdruid:initial-size: 1min-idle: 1max-active: 20test-on-borrow: true# mybatis的配置
mybatis:type-aliases-package: com.rql.entitymapper-locations: classpath:mybatis/*.xml
这里在配置时,特别注意在使用多配置源时,要将url
改为jdbc-url
。
对应两个数据库:
3.应用
下面是一个简单的SpringBoot整合mybatis的项目目录层级:
其中DataSourceConfig
用于定义DataSource Bean
,并通过@ConfigurationProperties
注解将配置文件中的属性映射到该Bean
的属性上
DataSourceConfig.java
@Configuration
public class DataSourceConfig {@Bean@ConfigurationProperties(prefix = "spring.datasource.datasource1")public DataSource dataSource1(){return DataSourceBuilder.create().build();}@Bean@ConfigurationProperties(prefix = "spring.datasource.datasource2")public DataSource dataSource2(){return DataSourceBuilder.create().build();}
}
上面只是创建了两个DataSource
的Bean
,分别为dataSource1
和dataSource2
,如果想要动态地根据操作去调用不同的数据源,那么就需要再创建一个Bean
,类似于代理的角色,根据条件来选择不同的数据源。
因此,创建DynamicDataSource.java
,并实现了DataSource
接口。
@Component
@Primary
public class DynamicDataSource implements DataSource, InitializingBean {public static ThreadLocal<String> name=new ThreadLocal<>();@AutowiredDataSource dataSource1;@AutowiredDataSource dataSource2;@Overridepublic Connection getConnection() throws SQLException {if (name.get().equals("w")) {return dataSource1.getConnection();}else {return dataSource2.getConnection();}}@Overridepublic Connection getConnection(String username, String password) throws SQLException {return null;}@Overridepublic PrintWriter getLogWriter() throws SQLException {return null;}@Overridepublic void setLogWriter(PrintWriter out) throws SQLException {}@Overridepublic void setLoginTimeout(int seconds) throws SQLException {}@Overridepublic int getLoginTimeout() throws SQLException {return 0;}@Overridepublic Logger getParentLogger() throws SQLFeatureNotSupportedException {return null;}@Overridepublic <T> T unwrap(Class<T> iface) throws SQLException {return null;}@Overridepublic boolean isWrapperFor(Class<?> iface) throws SQLException {return false;}@Overridepublic void afterPropertiesSet() throws Exception {name.set("w");}
}
这里主要通过getConnection()
方法来选择需要连接的数据源,因此根据读写操作的不同,设置一个值来区别(一般是使用枚举值,这样后面修改时不至于到代码中挨个去找),文中主要设置了一个参数,为了讲述方面。
public static ThreadLocal<String> name=new ThreadLocal<>();
注意到DynamicDataSource.java
也实现了InitializingBean
接口。
InitializingBean接口是Spring Framework中的一个重要接口,其主要目的是在Bean实例化后进行初始化操作。具体来说,当一个Bean实现了InitializingBean接口并被Spring容器创建后,Spring会在该Bean的属性设置完成后自动调用afterPropertiesSet()方法来执行一些额外的初始化逻辑。
因此,这里在Bean
实例化后,设置了name
的初始值。
4.测试
@RestController
@RequestMapping("user")
public class UserController {@Autowiredprivate UserDao userDao;@GetMapping("/a")public List<User> selectUsers(){DynamicDataSource.name.set("r");return userDao.findAll();}@PostMapping("/b")public void insertUser(@RequestBody User user){DynamicDataSource.name.set("w");userDao.inserUser(user);}}