我们说有@Service
和@Repository
接口,如下所示:
@Repository
public interface OrderDao extends JpaRepository<Order, Integer> {
}
public interface OrderService {
void saveOrder(Order order);
}
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderDao orderDao;
@Override
@Transactional
public void saveOrder(Order order) {
orderDao.save(order);
}
}
这是工作应用程序的一部分,所有内容都配置为访问单个数据库,一切正常。
现在,我希望能够使用纯Java 创建具有自动连线OrderDao 的独立工作实例,并使用Java中指定的 jdbcUrl代码,类似这样:
final int tenantId = 3578;
final String jdbcUrl = "jdbc:mysql://localhost:3306/database_" + tenantId;
OrderService orderService = someMethodWithSpringMagic(appContext, jdbcUrl);
正如您所看到的,我想向现有的基于Spring的应用程序引入多租户架构和每个数据库的租户策略。
请注意,在使用自我实现的jdbcTemplate类逻辑之前,我能够非常轻松地实现 ,并且JDBC事务正常工作,因此这是非常有效的任务。
请注意,我需要非常简单的事务逻辑来启动事务,在该事务范围内的service方法中执行多个请求,然后在异常时提交/回滚。
关于Spring的多租户的大多数解决方案建议在xml配置中指定具体的持久性单元和/或使用基于注释的配置非常不灵活因为为了添加新的数据库url整体应该停止应用程序,应该更改xml配置/注释代码并启动应用程序。
所以,基本上我正在寻找一段能够创建@Service
的代码,就像Spring在从XML配置/注释中读取属性后在内部创建它一样。我也在考虑使用ProxyBeanFactory
,因为Spring使用AOP
来创建服务实例(所以我想简单的旧的可重用OOP不是这里的方法)。
Spring足够灵活允许这种相对简单的代码重用吗?
任何提示都将受到高度赞赏如果我找到这个问题的完整答案,我会在这里发布以供后代使用:)
答案 0 :(得分:2)
为带注释的服务创建事务代理并不是一项艰巨的任务,但我不确定您是否真的需要它。要为tenantId选择数据库,我想您只需要专注于DataSource
界面。
例如,使用简单的驱动程序托管数据源:
public class MultitenancyDriverManagerDataSource extends DriverManagerDataSource {
@Override
protected Connection getConnectionFromDriverManager(String url,
Properties props) throws SQLException {
Integer tenant = MultitenancyContext.getTenantId();
if (tenant != null)
url += "_" + tenant;
return super.getConnectionFromDriverManager(url, props);
}
}
public class MultitenancyContext {
private static ThreadLocal<Integer> tenant = new ThreadLocal<Integer>();
public static Integer getTenantId() {
return tenant.get();
}
public static void setTenatId(Integer value) {
tenant.set(value);
}
}
当然,如果要使用连接池,则需要对其进行详细说明,例如每个租户使用一个连接池。
答案 1 :(得分:2)
HIbernate有out of the box support for multi tenancy,在尝试自己之前检查一下。 Hibernate需要一个MultiTenantConnectionProvider
和CurrentTenantIdentifierResolver
,其默认实现是开箱即用的,但您始终可以编写自己的实现。如果它只是一个模式更改,实际上很容易实现(在返回连接之前执行查询)。否则,保存数据源地图并从中获取实例,或创建新实例。
大约8年前,我们已经编写了一个通用解决方案,其中记录了here,代码为here。它不是特定于休眠的,并且可以基本上用于切换所需的任何内容。我们将它用于DataSource
s以及一些与网络相关的事物(其中包括其他内容)。