Spring Data MongoDB 3.1.3运行时切换数据库(多租户)配置求助
多MongoDB数据库动态切换配置(Spring Data MongoDB 3.1.3)
核心实现思路
要实现Repository操作间的数据库动态切换,核心是让Spring Data MongoDB的Repository能根据线程上下文动态获取目标数据库,而非绑定固定的MongoTemplate。通过自定义MongoDatabaseFactory实现数据库路由,再基于该Factory构建动态MongoTemplate,就能让Repository自动感知租户上下文切换数据库。
具体步骤
1. 完善线程安全的租户上下文(复用你的现有实现)
确保租户ID存储在ThreadLocal中,保证线程隔离:
public class TenantContext { private static final ThreadLocal<String> CURRENT_TENANT = new ThreadLocal<>(); public static void setTenant(String tenantId) { CURRENT_TENANT.set(tenantId); } public static String getTenant() { return CURRENT_TENANT.get(); } public static void clear() { CURRENT_TENANT.remove(); } }
2. 自定义MongoDatabaseFactory实现动态路由
包装默认的数据库工厂,根据租户上下文动态切换目标数据库:
@Component public class TenantMongoDatabaseFactory implements MongoDatabaseFactory { private final MongoDatabaseFactory defaultDatabaseFactory; // 注入Spring自动配置的默认数据库工厂 public TenantMongoDatabaseFactory(MongoDatabaseFactory defaultDatabaseFactory) { this.defaultDatabaseFactory = defaultDatabaseFactory; } @Override public MongoDatabase getMongoDatabase() throws DataAccessException { String tenantId = TenantContext.getTenant(); // 存在租户ID则切换到对应数据库,否则用默认库 if (tenantId != null) { return defaultDatabaseFactory.getMongoClient().getDatabase(tenantId); } return defaultDatabaseFactory.getMongoDatabase(); } // 其他方法直接委托给默认工厂 @Override public MongoDatabase getMongoDatabase(String dbName) throws DataAccessException { return defaultDatabaseFactory.getMongoDatabase(dbName); } @Override public MongoClient getMongoClient() { return defaultDatabaseFactory.getMongoClient(); } @Override public PersistenceExceptionTranslator getExceptionTranslator() { return defaultDatabaseFactory.getExceptionTranslator(); } }
3. 配置动态MongoTemplate
基于自定义的DatabaseFactory创建MongoTemplate,确保Repository使用这个动态实例:
@Configuration public class MongoConfig { @Bean public MongoTemplate mongoTemplate(TenantMongoDatabaseFactory tenantMongoDatabaseFactory) { return new MongoTemplate(tenantMongoDatabaseFactory); } }
4. 业务层使用示例
按你的场景调用,注意务必清理租户上下文避免线程污染:
// 服务类中 @Autowired private DocumentARepository documentARepository; public void crossDatabaseInsert() { // 插入到默认数据库(Database A) documentARepository.insert(documentA); // 切换到Database B并执行插入 TenantContext.setTenant("Database B"); try { documentARepository.insert(documentB); // 自动插入到Database B的CollectionA } finally { // 清理线程上下文,防止线程池复用导致租户信息残留 TenantContext.clear(); } }
调试排查方法
如果需要自行验证操作时的Bean信息,可以用以下手段:
1. 断点调试数据库路由
在TenantMongoDatabaseFactory.getMongoDatabase()方法上打断点,每次Repository执行CRUD操作都会触发该方法,直接查看返回的数据库名称是否符合预期。
2. 验证Repository绑定的MongoTemplate
通过Spring容器获取Repository的代理目标对象,查看其绑定的MongoTemplate:
@Autowired private ApplicationContext context; public void checkRepositoryBinding() { DocumentARepository repo = context.getBean(DocumentARepository.class); // 获取Repository的真实实现类(Spring动态生成的代理) SimpleMongoRepository targetRepo = (SimpleMongoRepository) AopTestUtils.getTargetObject(repo); MongoTemplate usedTemplate = targetRepo.getMongoTemplate(); System.out.println("当前Repository使用的MongoTemplate: " + usedTemplate); System.out.println("当前连接的数据库: " + usedTemplate.getDb().getName()); }
3. 开启调试日志查看细节
在配置文件中开启Spring Data MongoDB的DEBUG日志,直接输出操作对应的数据库和集合信息:
logging: level: org.springframework.data.mongodb: DEBUG
内容的提问来源于stack exchange,提问作者Ftoy
相关产品推荐
相关产品推荐

