12

假设我有以下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 的 webapp。除了不想在可见文本文件上存储/管理密码的安全问题。

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

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

  2. 如果允许我完全依赖 Hibernate,除了可能的 JPA 唯一途径之外,还有没有办法在不涉及 Spring 框架的情况下实现这一点(这似乎是一个到处都是触手的巨大怪物)?

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

4

2 回答 2

7

这取决于您如何引导 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 连接的契约(接口)。

很多选择:)

于 2012-07-27T23:11:31.740 回答
3

对于您的第二个问题,我可以提供仅 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();
    }
}
于 2012-07-27T21:09:46.703 回答