如何让JPA应用程序访问不同的数据库?

时间:2012-02-16 17:02:27

标签: jpa-2.0 persistence.xml

我正在编写一个Java SE(桌面)应用程序,它必须访问不同的数据库,所有这些数据库都具有相同的数据模型(相同的模式,表格等)。我想重用已经在每个数据库前面的Java EE应用程序中使用的JPA实体。

要重用现有的entity.jar文件,我必须使用具有resource_local数据源的不同persistence.xml重新打包它。这是构建时间的不便,但不是一个大问题。

问题是我的桌面应用程序将仅限于使用persistence.xml文件中定义的数据源。我可以定义多个持久性单元并选择在运行时使用哪个,但是当添加新数据库时,我将不得不更改persistence.xml并更新所有桌面二进制文件。

我希望能够在.properties文件中定义每个用户都可以配置的新数据源。有没有办法在运行时覆盖或添加到persistence.xml中声明的持久性单元?

我不想仅使用Web服务接口构建Java EE应用程序来支持此桌面应用程序。 Java EE应用程序有不同的用途,我希望将桌面功能保留在桌面应用程序中。

感谢。

2 个答案:

答案 0 :(得分:6)

您可以通过提供属性在运行时创建EntityManagerFactory。

Map<String, Object> properties = new HashMap<String, Object>();

properties.put(TRANSACTION_TYPE, PersistenceUnitTransactionType.RESOURCE_LOCAL.name());
properties.put(JDBC_DRIVER, driver);
properties.put(JDBC_URL, db_url);
properties.put(JDBC_USER, "userName");
properties.put(JDBC_PASSWORD, "password");

EntityManagerFactory factory = Persistence.createEntityManagerFactory("PERSISTENT_UNIT_NAME", properties);

此外,您可以尝试使用属性文件,在运行时将属性加载到地图中。因此,它会将数据库配置与代码分离。

编辑:属性键(JDBC_URL等)是特定于供应商的,应相应地替换它们。

答案 1 :(得分:3)

拿烟,

我需要扩展您的答案,因为它不完整。

使用属性动态创建EntityManagers的令人困惑的事情是JPA中有三个createEntityManagerFactory()方法,并且所有3个方法都采用持久性单元名称。在检查JPA 2.0规范之前,我没有意识到属性会覆盖persistenceunit名称。第9.4.3节说明属性覆盖了persistence.xml中给出的值。它还显示了标准属性名称。

(JavaDocs没有告诉你什么可以进入属性,他们也没有说这些属性覆盖了persistence.xml中的内容。另一个JavaDocs很糟糕的例子。)

您的示例使用不在Java EE 6 API Javadoc中的属性名称,如“JDBC_URL”。 JPA规范解释了除标准属性外还可以使用特定于供应商的属性名称。 EclipseLink文档通过非标准PersistenceUnitProperties类显示实现支持的属性名称:

http://www.eclipse.org/eclipselink/api/2.3/index.html

因此,为了拥有动态EntityManagers,必须使用特定于供应商的属性,因此动态实体管理器不可移植。我想你不能拥有一切。

动态EntityManagers可移植的一种情况是使用标准的javax.persistence.jtaDataSource属性。您必须将数据源添加到Java EE容器中,但这与在容器中运行时一样动态。在Java SE中,它看起来不像任何可移植的动态选项。

JavaDocs需要更好地解释属性如何与createEntityManagerFactory()方法一起使用。