DS注解作用
@DS(“#header.dbTenantId”) 是 MyBatis-Plus 框架中的注解,用于指定数据源。其中 #header.dbTenantId 表示从请求头中获取 dbTenantId 参数的值,作为数据源的标识。
@DS(“#tenantId”)中的 #tenantId 表示从方法参数中获取 tenantId 参数的值,作为数据源的标识。
@DS(“master”) 中的 “master” 表示数据源的标识,即指定使用名为 master 的数据源。
在多租户系统中,不同的租户可能需要连接不同的数据库,因此需要动态切换数据源。使用 @DS 注解可以方便地实现动态切换数据源的功能。通过在注解中指定数据源的标识,可以让 MyBatis-Plus 框架自动切换到对应的数据源,从而实现动态切换数据源的功能。
需要注意的是,使用 @DS 注解需要在 Spring Boot 配置文件中配置多个数据源,并在注解中指定数据源的标识。同时,也需要在代码中使用 @Mapper 注解标注 Mapper 接口,以便 MyBatis-Plus 框架能够自动扫描并生成对应的 Mapper 实现类。
样例:
spring:datasource:tenant1:url: jdbc:mysql://localhost:3306/tenant1_db?useUnicode=true&characterEncoding=utf-8&useSSL=falseusername: rootpassword: rootdriver-class-name: com.mysql.jdbc.Drivertenant2:url: jdbc:mysql://localhost:3306/tenant2_db?useUnicode=true&characterEncoding=utf-8&useSSL=falseusername: rootpassword: rootdriver-class-name: com.mysql.jdbc.Driver
在上面的配置文件中,定义了两个数据源,分别为 tenant1 和 tenant2。其中,tenant1 数据源连接的是 tenant1_db 数据库,tenant2 数据源连接的是 tenant2_db 数据库。
在代码中,可以使用 @DS 注解动态指定使用哪个租户的数据源。例如:
@Service
public class UserServiceImpl implements UserService {@Autowiredprivate UserMapper userMapper;@DS("#tenantId")@Overridepublic List<User> listUsers(Long tenantId) {return userMapper.selectList(null);}
}
失效情况:
updateUser方法的数据源会覆盖掉getUserById方法的数据源
可以将getUserById方法放到另一个类中,使之代理注解生效
@Service
public class UserServiceImpl implements UserService {@Autowired@Qualifier("dataSource1")private DataSource dataSource1;@Autowired@Qualifier("dataSource2")private DataSource dataSource2;@Override@DS("dataSource1")@Transactional(value = "transactionManager1")public User getUserById(int id) {// 使用dataSource1查询用户信息// ...}@Override@Transactional(value = "transactionManager2")@DS("dataSource2")public void updateUser(User user) {// 在这里调用getUserById方法,应该使用dataSource1数据源User oldUser = getUserById(user.getId());// 使用dataSource2更新用户信息// ...}
}
原因:
@DS注解是通过AOP实现的,它会在方法执行前切换数据源。而@Transactional注解也是通过AOP实现的,它会在方法执行前开启事务,并在方法执行后提交或回滚事务。
当一个方法同时被@DS和@Transactional注解修饰时,Spring会先创建一个代理对象,这个代理对象会同时包含@DS和@Transactional的功能。当代理对象调用这个方法时,它会先切换数据源,然后开启事务。在事务执行期间,如果这个方法调用了另一个方法,那么这个方法也会被代理对象所代理,也就是说,这个方法也会被切换到当前数据源,并且也会被包含在当前事务中。
如果在调用另一个方法时,这个方法上也有@DS注解,那么这个注解会被代理对象所覆盖,也就是说,这个方法会使用当前数据源,而不是它本来应该使用的数据源。这就是为什么@DS注解会被覆盖的原因。