【问题标题】:Setting JPA persistence properties dynamically动态设置 JPA 持久性属性
【发布时间】:2012-07-26 13:46:32
【问题描述】:

假设我有以下persistence.xml,其中连接url、用户和密码都是硬编码的。

以下内容适用于 Hibernate 3.2。对于 Hibernate 3.5 ++,我们必须将“hibernate.connection”更改为“javax.persistence”。但是让我问这个问题,不管文字是“hibernate.connection”还是“javax.persistence”。

<persistence-unit name="obamacare" transaction-type="RESOURCE_LOCAL">
  <provider>org.hibernate.ejb.HibernatePersistence</provider>
  <exclude-unlisted-classes>false</exclude-unlisted-classes>
  <properties>
    <property name="hibernate.archive.autodetection" value="class, hbm"/>
    <property name="hibernate.connection.driver_class" value="oracle.jdbc.driver.OracleDriver"/>
    <property name="hibernate.connection.url" value="blah blah blah"/>
    <property name="hibernate.connection.username" value="careuser"/>
    <property name="hibernate.connection.password" value="carepass"/>
    <property name="hibernate.dialect" value="org.hibernate.dialect.OracleDialect"/>
    <property name="hibernate.show_sql" value="true"/>
  </properties>
  </persistence-unit>
</persistence>

但是,我们需要动态设置 url、用户和密码。有一个提议的身份验证服务器,它提供 url、用户和密码。这样我们就不需要单独配置使用某种形式的 jdbc、hibernate 或 JPA 的无数 webapps。除了不想在可见文本文件上存储/管理密码的安全问题。

就 JPA 而言,如何动态设置这些 JPA 属性?我正在寻求两组答案:

  1. 对于独立于 JPA 供应商的解决方案(toplink、eclipselink、hibernate 等) - 是否有任何 JPA 功能可以让我动态设置这三个属性?

  2. 1234563 /p>

如果您还希望在 JNDI 上投入两美分/英镑/卢比以及如何使用它来替换 persistence.xml 属性的功能,我会很高兴。但是,这不是问题的优先级。

【问题讨论】:

  • 您想要完成的大部分事情都可以使用 Spring 轻松完成。我使用 Spring 已经有几个星期了,我一点也不后悔切换。 Spring 看起来工作量很大,但实际上很容易。

标签: java hibernate jpa jpa-2.0


【解决方案1】:

这取决于您如何引导 EntityManagerFactory。 2 个规范定义的方法都允许您传入 java.util.Map 值。这些值应该优先于持久性单元中定义的值。

在“SE 方法”中没有问题,因为引导过程通常由您的应用程序控制:javax.persistence.Persistence#createEntityManagerFactory(String puName, Map config。现在,如果其他东西(咳咳,Spring)为您“管理” EMF,您可能会遇到问题......

在“EE 方法”中,我不知道有什么好的全局方法。这个 Map of values 在 bootstrapping 中仍然存在,但问题是 EE 容器是调用这个方法的那个。

在这两种情况下都可以使用的一种特定于 Hibernate 的方法是使用配置变量替换。因此,在您的持久性单元中,您将使用${some.key} 定义用户名或密码,Hibernate 将为您替换这些。这是否真的有效取决于您最终要如何设置这些值; Hibernate 仍然需要访问名为 some.key 的配置值才能使其正常工作...

另一种“全局方法”...引导 EMF 的“EE 方法”是让容器实例化 javax.persistence.spi.PersistenceProvider 并调用其 javax.persistence.spi.PersistenceProvider#createContainerEntityManagerFactory。 createContainerEntityManagerFactory 在这里有一个有趣的签名。本质上,它传递了一个 javax.persistence.spi.PersistenceUnitInfo,它是已解析的持久性单元以及其他一些东西的对象表示。一种选择是使用这种方法来引导并传入您构建自己的 javax.persistence.spi.PersistenceUnitInfo 的实例。 javax.persistence.spi.PersistenceProvider 是一个接口。要实例化它,您需要知道您想要使用的提供者以及他们的 impl 的 FQN。但这通常不是问题,因为这些都是众所周知的。

您专门询问 JDBC 连接创建/池。您可以在那里专门选择其他选项。您可以让您的“凭证服务”创建数据源,而您的 JPA 提供者只需使用该数据源。所有 JPA 提供程序都支持通过 JNDI 查找定位数据源。在“EE 引导”中,提供者也可以通过 PersistenceUnitInfo#getJtaDataSource 和/或 PersistenceUnitInfo#getNonJtaDataSource 传递数据源以使用。 Hibernate 交替接受一个 DataSource 实例来代替典型的 DataSource JNDI 名称设置。如果您不想使用 DataSource(出于某种奇怪的原因),则特定于 Hibernate 的替代方法是自己实现 Hibernate 的 ConnectionProvider 契约,这是 Hibernate 用于在需要时获取和释放 JDBC 连接的契约(接口)。实现 ConnectionProvider 你可以以任何你想要的方式配置底层连接。

很多选择:)

【讨论】:

  • 另一种“全局方法”...引导 EMF 的“EE 方法”是实例化 javax.persistence.spi.PersistenceProvider 并调用它的 javax.persistence.spi.PersistenceProvider#createContainerEntityManagerFactory。 createContainerEntityManagerFactory 在这里有一个有趣的签名。本质上,它传递了一个 javax.persistence.spi.PersistenceUnitInfo,它是已解析的持久性单元以及其他一些东西的对象表示。一个选项是使用这种方法来引导并传入您构建自己的 javax.persistence.spi.PersistenceUnitInfo
  • 最后一条评论空间不足 :) javax.persistence.spi.PersistenceProvider 是一个接口。要实例化它,您需要知道您想要使用的提供者以及他们的 impl 的 FQN。但这通常不是问题,因为这些都是众所周知的。
  • 史蒂夫,感谢您的努力。您是否有机会将您的 cmets 转移到答案区域? ${some.key} 替换方法正是我正在寻找的。你能给我一个例子,如何在hibernate的persistence.xml上做到这一点。因为我们的生产机器是 jboss 4.x,所以我们必须使用 hibernate 3.2 而不是 hibernate 3.6 - 所以很多新的 hibernate 功能不适用。
  • @BlessedGeek 例如,现在你有&lt;property name="hibernate.connection.username" value="careuser"/&gt;,所以你应该说&lt;property name="hibernate.connection.username" value="${the.db.user}"/&gt;。就像我说的那样,您仍然需要将the.db.user 定义为可以在某个地方进行休眠的属性。也许是系统属性。如果不了解更多有关您如何引导的信息,很难给出具体细节。
【解决方案2】:

对于您的第二个问题,我可以提供仅 Hibernate 的解决方案。

package dev.stackoverflow;

import java.util.Properties;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class DynamicHibernateSessionFactory {
    public Session setProperties(final String provider,
                                 final Boolean excludeUnlisted,
                                 final Properties properties) {
        properties.setProperty("provider", provider);
        properties.setProperty("exclude-unlisted-classes", excludeUnlisted.toString());
        Configuration configuration = new Configuration();
        configuration.setProperties(properties);
        SessionFactory sessionFactory = configuration.configure().buildSessionFactory();
        return sessionFactory.openSession();
    }
}

【讨论】:

    猜你喜欢
    • 2021-02-17
    • 2011-06-30
    • 1970-01-01
    • 1970-01-01
    • 2013-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多