多数据源配置及使用,在同一个方法下切换数据源。

时间:2025-02-08 13:47:52

切换数据源方法:

1. 通过注解切换数据源,可以在方法上使用也可以在类上使用,遵循就近原则

@DS(“数据源名”)

注意:在同一个方法使用多个数据源不要使用@Transactional,会导致报错。

2. 方法中手动切换

切换数据源类似压栈,弹栈操作。引入依赖和配置文件见示例。

//引入jar包
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;

@Override
public OperaResponse testSelectCompanyAndUser() {
    //方法体内部
    //切换数据源
    DynamicDataSourceContextHolder.push("mysql1");
    //数据操作

    //释放数据源
    DynamicDataSourceContextHolder.poll();

    //切换数据源
    DynamicDataSourceContextHolder.push("mysql2");
    //数据操作

    //释放数据源
    DynamicDataSourceContextHolder.poll();
    return OperaResponse.ok();
}

示例使用场景,使用方法1

将测试服务器的企业与用户的关联关系映射到本地服务器中。

本例在mapper类上使用@DS切换数据源

引入依赖

<properties>        
    <dynamic-datasource.version>3.5.0</dynamic-datasource.version>
</properties>

<!-- Mybatis-plus多数据源 -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
    <version>${dynamic-datasource.version}</version>
</dependency>

配置文件yml

datasource:
    dynamic:
      primary: mysql1 #设置默认的数据源或者数据源组,默认值即为mysql1
      strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
      datasource:
        mysql1: # 数据源名
          driverClassName: com.mysql.cj.jdbc.Driver
          url: 数据源地址?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
          username: 用户名
          password: 密码
        mysql2: # 数据源名
          driverClassName: com.mysql.cj.jdbc.Driver
          url: 数据源地址?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
          username: 用户名
          password: 密码
    # 以下非必须,配置数据库连接池
    type: com.zaxxer.hikari.HikariDataSource
    hikari:
      connection-timeout: 30000       # 等待连接池分配连接的最大时长(毫秒),超过这个时长还没可用的连接则发生SQLException, 默认:30秒
      minimum-idle: 5                 # 最小连接数
      maximum-pool-size: 20           # 最大连接数
      auto-commit: true               # 自动提交
      idle-timeout: 600000            # 连接超时的最大时长(毫秒),超时则被释放(retired),默认:10分钟
      pool-name: DateSourceHikariCP     # 连接池名字
      max-lifetime: 1800000           # 连接的生命时长(毫秒),超时而且没被使用则被释放(retired),默认:30分钟 1800000ms
      connection-test-query: SELECT 1

Mapper.java

@Repository
@DS("mysql2")
public interface CompanyUserMapper extends BaseMapper<CompanyUser> {
}

UserService.java

public interface IUserService extends IService<User> {
    /**
     * 将测试服务器的企业与用户的关联关系映射到本地服务器中
     *
     * 多数据源中@Transactional(rollbackFor = Exception.class) 事务失效并会导致切换数据源报错
     * @DS("mysql1"),@DS("mysql1")切换数据源可以在方法上使用,也可以在类上使用。
     *     如在mapper类或方法上使用,或在serviceImpl类或方法上使用。
     * @return
     */
    OperaResponse CompanyAndUserMapping();
}

UserServiceImpl.java

@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private CompanyUserMapper companyUserMapper;

    @Override
    public OperaResponse CompanyAndUserMapping() {
        //查询所有企业部门用户信息
        List<CompanyUser> companyUserList = companyUserMapper.selectList(new QueryWrapper<>());
        //将企业部门用户信息根据用户id进行分组
        Map<Long, List<CompanyUser>> map = companyUserList.stream().collect(Collectors.groupingBy(CompanyUser::getUserId));

        List<User> userList = this.list();
        //将企业id映射到用户表中
        for(User user : userList){
            if(map.containsKey(user.getId())){
                List<CompanyUser> companyUserList1 = map.get(user.getId());
                if(CollectionUtils.isEmpty(companyUserList1)){
                    return OperaResponse.error(ErrStatus.ERR_COMPANY);
                }
                if(companyUserList1.size() > 1){
                    log.info("用户id为:" + user.getId() + "的用户存在多个企业。"+"企业信息为:"+ companyUserList1.toString());
                }
                user.setCompanyId(companyUserList1.get(0) == null ? null : companyUserList1.get(0).getCompanyId());
                //更新用户信息
                this.updateById(user);
            }
        }
        return OperaResponse.ok();
    }
}

UserController.java

@RestController
@RequestMapping("/management/user")
public class UserController {

    @Autowired
    private IUserService userService;
 
   /**
     * 将测试服务器的企业与用户的关联关系映射到本地服务器中
     *
     * 多数据源中@Transactional(rollbackFor = Exception.class) 事务失效并会导致切换数据源报错
     * @DS("mysql1"),@DS("mysql1")切换数据源可以在方法上使用,也可以在类上使用。
     *     如在mapper类或方法上使用,或在serviceImpl类或方法上使用。
     * @return
     */
    @GetMapping("/CompanyAndUserMapping")
    @WebLog(description = "映射企业与用户关系")
    public OperaResponse CompanyAndUserMapping(){
        return userService.CompanyAndUserMapping();
    }
}