我可以通过在运行时指定数据库来使用JPA吗? [英] Can I use JPA by specifing the database during runtime?

查看:95
本文介绍了我可以通过在运行时指定数据库来使用JPA吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在生产服务器上使用MySQL,每个客户都有自己的数据库和数据库用户连接到他的数据库.每个数据库具有完全相同的结构.在服务器的生命周期内添加了客户(并因此添加了数据库).

I use MySQL on my production server, where every customer has its own database and its own database user to connect to his database. Each database has the exact same structure. Customers (and therefore databases) are added during the lifetime of the server.

当前,我使用类java.sql.DriverManager建立了MySQL数据库连接,该连接工作正常.数据库的url,用户,密码和驱动程序名称存储在几个属性文件中. Servlet从当前客户读取属性文件,并用java.sql.DriverManager创建java.sql.Connection.

Currently I establish a MySQL database connection with the class java.sql.DriverManager, which works just fine. The databases url, user, password and driver name are stored in several properties-files. The servlet reads the properties-file from the current customer and creates the java.sql.Connection with the java.sql.DriverManager.

我真的想使用JPA,但据我所知,只能通过在Web容器(在我的情况下为Tomcat)的配置中明确指定数据库来使用JPA.但这意味着,当新客户在我的平台上注册时,我必须将新数据库添加到webcontainer配置中,然后重新启动webcontainer,这听起来不是一个好主意.

I really want to use the JPA, but as far as I know the JPA can only be used by explicitly specifing the databases in the configuration of the webcontainer (in my case Tomcat). But that means, when a new customer registers on my platform, I have to add the new database to the webcontainer-configuration and restart the webcontainer, which does not sound like a good idea.

是否有一种使用JPA的方法,并且仍然可以在Web容器的生命周期内灵活地添加新数据库?

Is there a way to use the JPA and still have the flexibility to add new databases during the lifetime of the webcontainer?

推荐答案

您绝对可以按照自己的要求做,但细节在于恶魔.

You can definitely do what you ask, but the demon is in the details.

我将其称为JPA Multitenancy,而此处很有趣随机搜索提供的一篇文章,提出了一种使用CDI的有效方法.考虑到您还需要添加新租户的运行时这一事实,我将以一种更通用的方法开始.

I would call it JPA Multitenancy, and here is an interesting article provided by a random search, that proposes a valid method using CDI. I will start with a more generic approach, taking into account the fact that you also require runtime additions of new tenants.

还请注意,Hibernate提供了本地解决方案用于多租户.我不知道您使用的是哪个JPA提供程序,但是我猜想其他人也具有类似的功能.

Note also that Hibernate offers native solutions for multitenancy. I do not know which JPA provider you are using, but I would guess others have similar features.

必须使用单独的,特定于租户的EntityManagerFactory实例来完成.确切的数据库连接URL可以由传递给Persistence.createEntityManagerFactory()的映射给出.例如,假设META-INF/persistence.xml存在,则适用以下代码:

It has to be done using separate, tenant-specific EntityManagerFactory instances. The exact DB connection URL can be given by the map passed to Persistence.createEntityManagerFactory(). E.g., given that META-INF/persistence.xml exists, the following code applies:

HashMap props = new HashMap();
props.put("javax.persistence.jdbc.url", /* tenant-specific JDBC URL*/);
EntityManagerFactory tenantSpecificEntityManagerFactory =
    Persistence.createEntityManagerFactory("name-of-persistence-unit-from-persistence.xml", props);

props通常会覆盖persistence.xml中指定的所有属性.可能仅覆盖JDBC URL就足够了,也许您还需要覆盖用户名/密码或其他内容.从那时起,您可以获取特定于租户的持久性上下文并对其进行处理:

The props generally override any properties specified in persistence.xml. Probably overriding only the JDBC URL is enough, maybe you will need to override user/password or other things as well. From that point on, you can get the tenant-specific persistence context and work with it:

EntityManager tenantSpecificEm = tenantSpecificEntityManagerFactory.createEntityManager();

捕获:效率

您可以在每次需要特定于租户的EntityManager时执行以上代码(然后也关闭工厂).但是由于以下原因,这将严重无效:

Catch: Efficiency

You could execute the code above every time you need a tenant-specific EntityManager (and then close the factory as well). But it would be grossly inefficient for the following reasons:

  1. 每个请求重新创建EntityManagerFactory的过程很慢
  2. 根据每个请求重新创建数据库连接的速度甚至更慢
  1. Creating the EntityManagerFactory anew with each request is slow
  2. Creating the DB connection anew with each request is even slower

要解决这些问题,您将需要:

To address these issues you will need to:

  1. 缓存EntityManagerFactory实例
  2. 以某种方式使用连接池

缓存EntityManagerFactory实例

我假设有一个健壮的机制可以将每个请求与适当的租户相关联.另外,您将需要一个应用程序范围的租户名称的Map到对应的EntityManagerFactory实例.如何存储和使用它取决于应用程序,例如是否有任何依赖注入框架?第一个链接有一个使用CDI的解决方案,类似的解决方案将适用于其他DI容器.

Caching the EntityManagerFactory instances

I assume there is a robust mechanism to relate each request with the appropriate tenant. Additionally you will need an application-scoped Map of tenant name to the corresponding EntityManagerFactory instance. How this is stored and used depends on the application, e.g. is there any dependency injection framework in place? The first link has a solution with CDI, similar solutions would apply for other DI containers.

应用程序服务器提供数据库连接池. Tomcat也是如此.应用程序服务器可能允许您在运行时添加数据库连接池,而无需重新启动服务器.我不知道您所使用的Tomcat版本是否支持它(我想不会,但是请纠正我).所以:

Application servers offer DB connection pooling. Tomcat does too. Application servers might allow you to add DB connection pools at runtime without the need to restart the server. I do not know if the version of Tomcat you are using supports it (I would guess not, but please correct me). So:

  • 如果应用服务器(在这种情况下为Tomcat)支持运行时连接池的创建,请执行此操作并调整props以使用它
  • 否则,您将必须使用适用于每个EntityManagerFactory的自定义连接池.休眠似乎至少具有功能.
  • If the application server (Tomcat in this case) supports runtime connection pool creation, do that and tweak the props to use it
  • Otherwise you will have to use a custom connection pool that applies to each EntityManagerFactory. Hibernate at least seems to have this feature.

我想您已经弄清楚了,但是在运行时应用的设置(租户,租户名称到连接属性的映射)必须以某种方式持久化,以便在服务器重新启动时重新应用它们.这可能是配置文件或另一个管理"数据库.

I guess you already have figured this out, but the settings applied at runtime (tenants, tenant name to connection properties mappings) have to be persisted somehow, so that they are reapplied when the server restarts. This could be a configuration file or another "administration" database.

这篇关于我可以通过在运行时指定数据库来使用JPA吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆