动态创建EntityManager [英] Dynamic creation of EntityManager

查看:717
本文介绍了动态创建EntityManager的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题实际上很简单,但我真的没有找到一个很好的解决方案。



我目前在我的应用程序中管理几个DB:




  • 一个UNIQUE管理数据库(静态名称);

  • 一个客户端数据库,名称取决于客户端。



我使用JPA,我想为客户端DB创建动态的EntityManagers。但是当我以编程方式创建时,我会收到以下错误:
javax.persistence.TransactionRequiredException:在无法注册JTA事务的资源本地EntityManager上调用joinTransaction。



这里是代码:

  @Stateful 
public class ServiceImpl implements Service {

private EntityManagerFactory emf;
private EntityManager em;

@PostConstruct //当EJB构造和会话启动时自动调用
public void init(){
emf = Persistence.createEntityManagerFactory(punit);
em = emf.createEntityManager();
}
...

And

  @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文件中声明几个prsistenceunits。



在注入点,您可以执行以下操作:

  @PersistenceContext(unitName =unitName0,properties = {@ PersistenceProperty(...)} 
EntityManager emClient ;

@PersistenceContext(unitName =unitName1,properties = {@ PersistenceProperty(...)}
EntityManager emAdmin;

这样,您不必手动创建实体管理器,因此您可以获得容器事务管理。



未测试:



如果您有动态数据库名称,您将注入EntityManagerFactory



@PersistenceContext(unitName =name)
EntityManagerFactory emf;



//在你想要的EntityManager

  Map< String,String>道具; //将EM的连接属性放在这里
EntityManager em = emf.createEntityManager(props);

基于在J2EE环境中我们使用DataSources和ConnectionPooling的概念,几乎不可能实现这种动态数据源,而不需要手动创建entitymanagerfactory。



这是我的推理:
服务器管理连接池,并且jpa提供程序(如eclipselink)使用jndi来确定与数据库的连接。这意味着如果要更改数据库名称,那么它还必须具有连接池资源和关联的jdbc资源。这将使您的行为否定您想要做的事情。



基本解决方案:手动创建EntityManagerFactory并手动管理事务。
在持久化xml中指定该单元是非jta,以使其正常工作。



然后,您可以以编程方式提供基于用户会话的连接数据: / p>

这样的东西:



//这必须是会话具体的。

  class PersistenceSession {
static Map< String,String> clientSessionProps;

//当新会话启动并且新客户端登录时
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();
}

}


My problem is actually simple but I really do not find a good solution to it.

I've currently to manage several DB in my application:

  • one UNIQUE admin DB (with a static name);
  • one client DB, with a name depending on the client.

I'm using JPA and I would like to create dynamically EntityManagers for client DB. But when I create this programmatically, I get this error: javax.persistence.TransactionRequiredException: joinTransaction has been called on a resource-local EntityManager which is unable to register for a JTA transaction.

Here is the code:

@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();
}
...

And

@Stateful(mappedName = "CustomerService")
public class CustomerServiceImpl extends ServiceImpl implements CustomerService {

@Override
public void create(Customer cust) {
    getEm().joinTransaction();
    getEm().persist(cust);
}

More generally, I'v got problems with JPA. I just would like to connect to two databases, do some CRUD operations on them. But I really don't know how to manage transactions (my first approach was to let the container manage it...).

If someone could help me, could be great!

NB: I'm using a Glassfish Java EE server and PGSql DBs.

解决方案

In jpa, you can declare several prsistenceunits in the persistence.xml file.

At the point of injection, you can do something like this:

@PersistenceContext(unitName = "unitName0", properties={@PersistenceProperty(...)}
EntityManager emClient;

@PersistenceContext(unitName = "unitName1", properties={@PersistenceProperty(...)}
EntityManager emAdmin;

This way, you dont have to create the entity managers manually, hence you get the container transaction management.

NOT TESTED:

If you have dynamic database names, you would inject EntityManagerFactory

@PersistenceContext(unitName ="name") EntityManagerFactory emf;

//at the point you want the EntityManager

Map<String, String> props; //put the connection property for the EM here
EntityManager em = emf.createEntityManager(props);

Based on the fact that in a J2EE environment we use the concept of DataSources, and ConnectionPooling, it would be nearly impossible to implement this kind of dynamic datasources, without resorting to manual creation of entitymanagerfactory.

This is my reasoning: The server manages the connection pooling, and the jpa provider (such as eclipselink) uses jndi to determine the connection to the database. This implies that if you were to change the database name, then it must also have a connection pooling resources, and an associated jdbc resource. This will ofcourse negate what you want to do.

Basic solution: Create EntityManagerFactory manually and manually manage transactions. Specify in the persistence xml that the unit is non-jta for this to work.

Then you can programmatically supply connection data based on user-session:

Something of this sort:

//this must be session specific.

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;
  }
}

At the ejb level.

@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();
    }

}

这篇关于动态创建EntityManager的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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