赞
踩
在pom.xml文件中加入以下依赖:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
在application.yml或application.properties中配置数据源,如:
spring: datasource: dynamic: primary: master #设置默认的数据源或者数据源组,默认值即为master strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源 datasource: master: url: jdbc:mysql://xx.xx.xx.xx:3306/dynamic username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver # 3.2.0开始支持SPI可省略此配置 slave_1: url: jdbc:mysql://xx.xx.xx.xx:3307/dynamic username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver slave_2: url: jdbc:mysql://xx.xx.xx.xx:3308/dynamic username: root password: 123456 driver-class-name: com.mysql.jdbc.Driver #......省略 #以上会配置一个默认库master,一个组slave下有两个子库slave_1,slave_2
其中,spring.datasource.dynamic.primary为默认数据源,后面的配置为各个数据源的配置。
在需要使用的地方使用@DS注解,指定使用的数据源,如:
//@DS("slave_1") @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @DS("slave_1") @Override public List<User> listUsersBySlave1() { return userMapper.listUsers(); } @Override public List<User> listUsersByMaster() { return userMapper.listUsers(); } }
@DS 可以注解在方法上和类上,同时存在方法注解优先于类上注解,如果没有写@DS注解,则默认使用master数据源。
有时候切换数据源需要根据业务动态切换,就不能使用注解,需要手动切换数据:
DynamicDataSourceContextHolder.push("slave_1");
//执行业务方法
DynamicDataSourceContextHolder.poll();
手动切换数据源会与springboot事务冲突,例如
@Transactional(rollbackFor = Exception.class)
public void add(DataSourceAddVo vo) {
DynamicDataSourceContextHolder.push("slave_1");
//执行业务方法
selectList();
handleAdd();
DynamicDataSourceContextHolder.poll();
}
上述代码中,执行handleAdd方法不能执行切换数据源,可以改造成:
//@Transactional(rollbackFor = Exception.class)
public void add(DataSourceAddVo vo) {
DynamicDataSourceContextHolder.push("slave_1");
//执行业务方法
selectList();
DynamicDataSourceContextHolder.poll();
}
@Transactional(rollbackFor = Exception.class)
public void handleAdd( ){
this.save(bean);
}
以上切换的数据源都是在配置文件上定义好了,如果需要由用户从界面添加数据源则需要动态维护数据源。
数据源由:数据源唯一编码、用户名、密码、url和驱动4个元素组成,见下图:
编写数据源管理的工具类:
package org.bitnei.modules.ds; import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; import com.baomidou.dynamic.datasource.creator.DataSourceCreator; import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; import javax.sql.DataSource; import java.util.Set; /** * 功能描述:数据源管理工具类 * * @author: zenghaiwen * @date: 2023年07月20日 10:05 */ @Component @Slf4j public class DynamicDataSourcesUtil { @Autowired private DataSource dataSource; @Autowired private DataSourceCreator dataSourceCreator; /** * 添加数据源 */ public Set<String> addDataSource(DataSourceDTO dto) { DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource; if(!this.existsDataSource(dto.getPoolName())){ new JdbcTemplate(dataSource); DataSourceProperty dataSourceProperty = new DataSourceProperty(); BeanUtils.copyProperties(dto, dataSourceProperty); DataSource dataSource = dataSourceCreator.createDataSource(dataSourceProperty); ds.addDataSource(dto.getPoolName(), dataSource); } return ds.getCurrentDataSources().keySet(); } public DataSource getDataSource(){ DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource; return ds.getDataSource("master"); } /** * 删除数据源 * @param name */ public void removeDataSource(String name){ DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource; ds.removeDataSource(name); } /** * 获取当前所有数据源 * @return */ public Set<String> allDataSource() { DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource; return ds.getCurrentDataSources().keySet(); } /** * 是否存在数据源 * @param name * @return */ public boolean existsDataSource(String name){ DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource; return ds.getCurrentDataSources().containsKey(name); } }
以下是调用工具类实现动态管理数据源的代码:
public void add(DataSourceAddVo vo) { DataSource bean = BeanUtil.copyProperties(vo,DataSource.class); //测试链接是否成功 boolean isConnect = checkDataSource(bean); AssertUtils.assertIsTrue(isConnect,"无法链接数据库"); //添加数据源 Set<String> dbSet = this.addDataSource(bean); //切换刚刚添加的数据源 DynamicDataSourceContextHolder.push(bean.getCode()); //执行业务方法 DynamicDataSourceContextHolder.poll(); handleAdd(bean,tableList,allVehicleList); } private Set<String> addDataSource(DataSource ds){ DataSourceDTO dto = buildDataSourceDTO(ds); return dynamicDataSourcesUtil.addDataSource(dto); } private DataSourceDTO buildDataSourceDTO(DataSource ds){ DataSourceDTO dto = new DataSourceDTO() .setPoolName(ds.getCode()) .setUsername(ds.getUsername()) .setPassword(ds.getPassword()) .setUrl(ds.getDbUrl()) .setDriverClassName(Constants.MYSQL_DRIVER); return dto; }
注:添加数据源必须检查数据源的连通性,否则会一直打印数据源错误。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。