我的问题其实很简单,但我确实没有找到好的解决方案。
我目前在我的应用程序中管理多个数据库:
- 一个唯一的管理数据库(具有静态名称);
- 一个客户端数据库,其名称取决于客户端。
我正在使用 JPA,我想为客户端数据库动态创建 EntityManager。但是当我以编程方式创建它时,我收到此错误: javax.persistence.TransactionRequiredException:已在无法注册 JTA 事务的资源本地 EntityManager 上调用 joinTransaction。
这是代码:
@Stateful
public class ServiceImpl implements Service{
private EntityManagerFactory emf;
private EntityManager em;
@PostConstruct // automatically called when EJB constructed and session starts
public void init() {
emf = Persistence.createEntityManagerFactory("punit");
em = emf.createEntityManager();
}
...
和
@Stateful(mappedName = "CustomerService")
public class CustomerServiceImpl extends ServiceImpl implements CustomerService {
@Override
public void create(Customer cust) {
getEm().joinTransaction();
getEm().persist(cust);
}
更一般地说,我在使用 JPA 时遇到了问题。我只想连接到两个数据库,对它们进行一些 CRUD 操作。但我真的不知道如何管理事务(我的第一个方法是让容器来管理它......)。
如果有人可以帮助我,那就太好了!
注意:我正在使用 Glassfish Java EE 服务器和 PGSql DB。
最佳答案
在jpa中,可以在persistence.xml文件中声明多个prsistenceunit。
在注入(inject)时,您可以执行以下操作:
@PersistenceContext(unitName = "unitName0", properties={@PersistenceProperty(...)}
EntityManager emClient;
@PersistenceContext(unitName = "unitName1", properties={@PersistenceProperty(...)}
EntityManager emAdmin;
这样,您就不必手动创建实体管理器,因此您可以获得容器事务管理。
未测试:
如果您有动态数据库名称,您将注入(inject) EntityManagerFactory
@PersistenceContext(unitName ="名称") EntityManagerFactory emf;
//在你想要EntityManager的时候
Map<String, String> props; //put the connection property for the EM here
EntityManager em = emf.createEntityManager(props);
基于在J2EE环境中我们使用DataSources和ConnectionPooling的概念,如果不手动创建entitymanagerfactory,几乎不可能实现这种动态数据源。
这是我的推理: 服务器管理连接池,jpa 提供程序(例如 eclipselink)使用 jndi 来确定与数据库的连接。这意味着如果您要更改数据库名称,那么它还必须具有连接池资源和关联的 jdbc 资源。这当然会否定你想做的事情。
基本解决方案:手动创建EntityManagerFactory并手动管理事务。 在持久性 xml 中指定该单元是非 jta 才能正常工作。
然后您可以根据用户 session 以编程方式提供连接数据:
类似的事情:
//这必须是特定于 session 的。
class PersistenceSession{
static Map<String, String> clientSessionProps;
//When new session starts and a new client has logged in.
static void setClientConnectionProperties(Client client){
.....
}
static Map<String, String> getClientSessionProps(){
return clientSessionProps;
}
}
在 ejb 级别。
@Stateless
public class TestEntityFacade extends AbstractFacade<TestEntity> {
private EntityManagerFactory emf;
@PostConstruct
void init(){
emf = Persistence.createEntityManagerFactory("name");
}
@Override
protected EntityManager getEntityManager() {
return emf.createEntityManager(PersistenceSession.getClientSessionProps());
}
public TestEntityFacade() {
super(TestEntity.class);
}
void add(Entity e){
EntityManager em = getEntityManager();
em.getTransaction().begin();
.....
em.getTransaction().commit();
}
}
关于java - 动态创建EntityManager,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24572705/