Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/393.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用JPA/EclipseLink/EJB从Java web应用程序访问多个数据库_Java_Jakarta Ee_Jpa_Glassfish_Eclipselink - Fatal编程技术网

使用JPA/EclipseLink/EJB从Java web应用程序访问多个数据库

使用JPA/EclipseLink/EJB从Java web应用程序访问多个数据库,java,jakarta-ee,jpa,glassfish,eclipselink,Java,Jakarta Ee,Jpa,Glassfish,Eclipselink,我已经构建了一个简单的SOAPjava应用程序(服务器端),我正在使用Glassfish4、JPA/EclipseLink、EJB。我已经在Glassfish中设置了db连接(资源/池)。请提供一些设计模式/知识,以利用单个应用程序中的多个数据库。创建多个持久性单元是多址访问的好主意吗??或者是否有其他优化的解决方案? 我有一个数据库访问的通用类 public class GenericDAO<T> { /* * private static final EntityManager

我已经构建了一个简单的
SOAP
java应用程序(服务器端),我正在使用
Glassfish4、JPA/EclipseLink、EJB
。我已经在Glassfish中设置了db连接(资源/池)。请提供一些设计模式/知识,以利用单个应用程序中的多个数据库。创建多个持久性单元是多址访问的好主意吗??或者是否有其他优化的解决方案? 我有一个数据库访问的通用类

public class GenericDAO<T> {

/*
* private static final EntityManagerFactory emf =
* Persistence.createEntityManagerFactory("icanPU"); private EntityManager
* em;
*/
/*
* Persistence context is injected with following @PersistenceContext
* annotation. This uses all persistence configurations as specified in the
* persistence.xml.
* 
* Note this kind of injection can only be done for JTA data sources.
*/
@PersistenceContext(unitName = "SavingBalanceDemoServer_PU")
private EntityManager em;
private Class<T> entityClass;

public EntityManager getEntityManager() {
return this.em;
}

public void joinTransaction() {
/* em = emf.createEntityManager(); */
em.joinTransaction();
}

public GenericDAO(Class<T> entityClass) {
this.entityClass = entityClass;
}

public void save(T entity) {
em.persist(entity);
}

// Added by Sudeep for bulk Insert of List object.
public void saveList(List<T> objList) {
for (Iterator<T> iterator = objList.iterator(); iterator.hasNext();) {
T t = (T) iterator.next();
em.persist(t);
}
}

public void delete(Object id, Class<T> classe) {
T entityToBeRemoved = em.getReference(classe, id);

em.remove(entityToBeRemoved);
}

public T update(T entity) {
return em.merge(entity);
}

public int truncateUsingNative(String tableName) {
Query qry = em.createNativeQuery("TRUNCATE TABLE " + tableName);

return qry.executeUpdate();
}

// Added by Sudeep for bulk Update of List object.
public void updateList(List<T> entity) {
for (Iterator<T> iterator = entity.iterator(); iterator.hasNext();) {
T t = (T) iterator.next();
em.merge(t);
}
}

public T find(int entityID) {
// em.getEntityManagerFactory().getCache().evict(entityClass, entityID);
return em.find(entityClass, entityID);
}

public T find(long entityID) {
// em.getEntityManagerFactory().getCache().evict(entityClass, entityID);
return em.find(entityClass, entityID);
}

public T find(Object compositePkObject) {
// em.getEntityManagerFactory().getCache().evict(entityClass, entityID);
return em.find(entityClass, compositePkObject);
}

public T findReferenceOnly(int entityID) {
return em.getReference(entityClass, entityID);
}

// Using the unchecked because JPA does not have a
// em.getCriteriaBuilder().createQuery()<T> method
@SuppressWarnings({ "unchecked", "rawtypes" })
public List<T> findAll() {
CriteriaQuery cq = null;
if (isDbAccessible()) {
try {
cq = em.getCriteriaBuilder().createQuery();
cq.select(cq.from(entityClass));
return em.createQuery(cq).getResultList();
} catch (org.eclipse.persistence.exceptions.DatabaseException ex) {
System.out.println("The zzz error is :" + ex.toString());
/*JSFMessageUtil jsfMessageUtil = new JSFMessageUtil();
jsfMessageUtil
.sendErrorMessageToUser("Database Server is unavailable or not accessible! Please, contact your system admin!");*/
return null;
}
}
return null;
}

private boolean isDbAccessible() {
return em.isOpen();
}

@SuppressWarnings("unchecked")
public List<T> findAllWithGivenCondition(String namedQuery,
Map<String, Object> parameters) {
List<T> result = null;
Query query = em.createNamedQuery(namedQuery);

if (parameters != null && !parameters.isEmpty()) {
populateQueryParameters(query, parameters);
}

result = (List<T>) query.getResultList();

return result;
}

@SuppressWarnings("unchecked")
public List<T> findAllWithGivenConditionLazyLoading(String namedQuery,
Map<String, Object> parameters,int startingAt, int maxPerPage) {
List<T> result = null;
Query query = em.createNamedQuery(namedQuery);

if (parameters != null && !parameters.isEmpty()) {
populateQueryParameters(query, parameters);
}
query.setFirstResult(startingAt);
query.setMaxResults(maxPerPage);

result = (List<T>) query.getResultList();

return result;

}

@SuppressWarnings("unchecked")
public List<T> findAllWithGivenConditionJpql(String jpql,
Map<String, Object> parameters) {
List<T> result = null;
Query query = em.createQuery(jpql);

if (parameters != null && !parameters.isEmpty()) {
populateQueryParameters(query, parameters);
}

result = (List<T>) query.getResultList();

return result;
}

@SuppressWarnings("unchecked")
public T findOneWithGivenConditionJpql(String jpql,
Map<String, Object> parameters) {
Query query = em.createQuery(jpql);

if (parameters != null && !parameters.isEmpty()) {
populateQueryParameters(query, parameters);
}
return (T) query.getSingleResult();
}

// Using the unchecked because JPA does not have a
// query.getSingleResult()<T> method
@SuppressWarnings("unchecked")
protected T findOneResult(String namedQuery, Map<String, Object> parameters) {
T result = null;

try {
if (!em.isOpen()) {
/*JSFMessageUtil jsfMessageUtil = new JSFMessageUtil();
jsfMessageUtil
.sendErrorMessageToUser("Database Server is unavailable or not accessible! Please, contact your system admin!");*/
} else {
Query query = em.createNamedQuery(namedQuery);

// Method that will populate parameters if they are passed not
// null and empty
if (parameters != null && !parameters.isEmpty()) {
populateQueryParameters(query, parameters);
}

result = (T) query.getSingleResult();
}

} catch (NoResultException e) {
// JSFMessageUtil jsfMessageUtil = new JSFMessageUtil();
// jsfMessageUtil.sendErrorMessageToUser("No Information Found...!");

// e.printStackTrace();
return null;
} catch (org.eclipse.persistence.exceptions.DatabaseException e) {
/*JSFMessageUtil jsfMessageUtil = new JSFMessageUtil();
jsfMessageUtil
.sendErrorMessageToUser("Database Server is unavailable or not accessible!");*/
e.printStackTrace();
}

return result;
}

private void populateQueryParameters(Query query,
Map<String, Object> parameters) {
for (Entry<String, Object> entry : parameters.entrySet()) {
query.setParameter(entry.getKey(), entry.getValue());
}
}

/**
* @param startingAt
* @param maxPerPage
* @param t
* @return list of persisted entities which belong to this class t
*/
@SuppressWarnings("unchecked")
public List<T> getAllLazyEntities(int startingAt, int maxPerPage, Class<T> t) {
// regular query that will search for players in the db
Query query = getEntityManager().createQuery(
"select p from " + t.getName() + " p");
query.setFirstResult(startingAt);
query.setMaxResults(maxPerPage);

return query.getResultList();
}

/**
* @param clazz
* @return count of existing entity rows from backend
*/
public int countTotalRows(Class<T> clazz) {
Query query = getEntityManager().createQuery(
"select COUNT(p) from " + clazz.getName() + " p");

Number result = (Number) query.getSingleResult();

return result.intValue();
}

/**
* @return count of existing entity rows from backend acccording to given
*         condition
*/
public int countTotalRowsWithCond(Class<T> clazz, String Cond) {
Query query = getEntityManager()
.createQuery(
"select COUNT(p) from " + clazz.getName() + " p "
        + Cond + "  ");

Number result = (Number) query.getSingleResult();

return result.intValue();
}
}
请在此文件中提出一些优化/更改建议

我一直在使用
EJB
来利用泛型类。 例如:

@无状态
公共类MemberEJB扩展了GenericDAO{
/**
*@see GenericDAO#GenericDAO(类)
*/
公共成员EJB(){
super(memregmentity.class);
//TODO自动生成的构造函数存根
}
公共列表getListOfMemberByName(字符串名称){
映射参数=新的HashMap();
参数.put(“memName”,name+'%');
返回super.findAllWithGivenCondition(“Mem.getMemberByName”,参数);
}
}

客户端应用程序提供要使用的数据库名称,并且每个数据库都具有相同的结构。我只需要根据客户的要求访问多个数据库。

当处理一个应用程序和多个DBs时,EclipseLink提供两种解决方案。哪一个更适合您取决于您的用例,如果

用户需要将多个持久性单元映射为单个持久性单元 应用程序中的持久性上下文

看看

如果你是这样的话

多个应用程序客户端必须共享数据源,并具有专用 访问他们的数据 环境

而不是看一眼

或者,这描述了一种设计多租户的方法,无需绑定到特定于供应商的功能

关于评论的更新


我不认为您所追求的动态数据源路由类型作为glassfish的现成构造存在。但实施起来也不难。您应该看看它们提供的和参考实现。您应该能够在它的基础上编写自己的路由器,而不会出现太多问题

当然,它可以用更复杂的方式完成,但我想到的还有一个简单的解决方案。如果部署尽可能多的应用程序和数据库,并设计一个小型请求路由应用程序,该应用程序将通过请求中提供的“databaseId”将所有客户请求转发到相应的应用程序,会怎么样。此解决方案在分布式环境中非常有效。

我的解决方案是为第二个数据库添加第二个持久性单元,然后重构GenericDAO,使EntityManager不是类的属性,而是传递给每个方法。然后,我将为每个数据库创建facade对象,将GenericDAO和相关EntityManager注入其中。如果您真的需要,可以使用一个公共接口来保持api不变。可能是这样的:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">

    <persistence-unit name="first_PU" transaction-type="JTA">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <jta-data-source>jdbc/simfin_1</jta-data-source>
        <class>org.demo.model.MemRegMcgEntity</class>
        <class>org.demo.model.SavAccHolderMcgEntity</class>
        <class>org.demo.model.SavAccMcgEntity</class>
        <class>org.demo.model.SavTransactionEntity</class>
    </persistence-unit>

    <persistence-unit name="second_PU" transaction-type="JTA">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <jta-data-source>jdbc/simfin_2</jta-data-source>
        <class>org.demo.model.MemRegMcgEntity</class>
        <class>org.demo.model.SavAccHolderMcgEntity</class>
        <class>org.demo.model.SavAccMcgEntity</class>
        <class>org.demo.model.SavTransactionEntity</class>
    </persistence-unit>

</persistence>
persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">

    <persistence-unit name="SavingBalanceDemoServer_PU" transaction-type="JTA">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <jta-data-source>jdbc/simfin</jta-data-source>
        <class>org.demo.model.MemRegMcgEntity</class>
        <class>org.demo.model.SavAccHolderMcgEntity</class>
        <class>org.demo.model.SavAccMcgEntity</class>
        <class>org.demo.model.SavTransactionEntity</class>
    </persistence-unit>

    <persistence-unit name="MySecondPersistenceUnit_PU" transaction-type="JTA">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <jta-data-source>jdbc/other-jta-datasource</jta-data-source>
        <class>org.demo.model.OtherEntityOne</class>
        <class>org.demo.model.OtherEntityTwo</class>
        <class>org.demo.model.OtherEntityThree</class>
        <class>org.demo.model.OtherEntityFour</class>
    </persistence-unit>

</persistence>
实体类:

public class SomeEntity implements IEntity {
    ....
}
DAO Facade数据库一:

public class GenericFacadeOne {

@PersistenceContext(unitName = "SavingBalanceDemoServer_PU")
private EntityManager em; 
@Autowired
private GenericDao dao;

@Transactional(propogation=Propogation.REQUIRED)
public void saveSomeEntity(SomeEntity entity) {
    getDao().save(getEm(), entity);
}

public void setEm(EntityManager em) {
    this.em = em;
}   

public EntityManager getEntityManager() {
    return this.em;
}

public void setDao(GenericDao dao) {
    this.em = em;
}   

public GenericDao getDao() {
    return this.dao;
}
}
DAO Facade数据库二:

public class GenericFacadeTwo {

@PersistenceContext(unitName = "MySecondPersistenceUnit_PU")
private EntityManager em; 
@Autowired
private GenericDao dao;

@Transactional(propogation=Propogation.REQUIRED)
public void saveSomeEntity(SomeEntity entity) {
    getDao().save(getEm(), entity);
}

public void setEm(EntityManager em) {
    this.em = em;
}   

public EntityManager getEntityManager() {
    return this.em;
}

public void setDao(GenericDao dao) {
    this.em = em;
}   

public GenericDao getDao() {
    return this.dao;
}
}

希望这是有道理的,让我知道如果你需要任何澄清

我们面对相同的用例,最终创建了多个持久化单元并构建了一个实体管理器工厂,该工厂根据客户端发送的参数返回正确的实体管理器(在我们的例子中,作为枚举,
环境
)。然后,我们不在客户机中注入持久性上下文,而是注入这个工厂并调用
getEntityManager(环境)

示例枚举:

public enum Environment{
    DEV, PROD
}
在您的情况下,GenericDAO将按照以下方式重构:

public class GenericDAO<T> {

    @EJB
    private EntityManagerFactory entityManagerFactory;

    public void save(T entity, Environment env) {
        entityManagerFactory.getEntityManager(env).persist(entity);
    }

}

另一种解决方案是以编程方式创建持久上下文

定义一个不带连接的persistent.xml。类似于:

persistent.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" ... >
    <persistence-unit name="UserInfo" transaction-type="JTA">
        <class>mx.saaskun.model.UserInfo</class>
    </persistence-unit>
</persistence>
然后,您可以将其用作:

 public class UserService{
     @EJB
     DynamicResource radResources;

     public List<UserInfo> listAll(){
          List<UserInfo allUsers = new ArrayList<>();
          String[] databases = new String[]{"jndi/simfin","jndi/simfin2"};
          for(String db:databases){
               List results = listServerUsers("simfin", db);
               allUsers.addAll(results);
          }
          return allUsers;
     }

     protected List<UserInfo> listServerUsers(String unitName, String jndi){
         EntityManager em= radResources.getEntityManager(unitName,jndi);
         try {
             Query q = em.createNamedQuery("UserInfo.findAll");
             return (List<UserInfo>) q.getResultList();
         } finally {
             em.close();
         }
     }
 }
公共类用户服务{
@EJB
动态资源;
公共列表listAll(){

ListThank U for reply。我的要求是客户端请求具有数据库名称的应用程序,我应该在运行时点击所需的数据库并进行回复。即,应该为每个客户端请求动态设置数据库连接。所有数据库都是相同的,只是数据库名称不同,客户端可以有多个re同时,Web服务应该做出相应的响应。您是否要使用persistence.xml中定义的具有相同对象关系映射的多个数据库?换句话说:所有数据库都将使用相同的一组实体?是的。您说得非常对..而且可以帮上忙..我也像您一样考虑这个问题,但是应该有更有效的方法。客户端不仅发送“databaseId”,还发送其他参数。请详细说明??这很简单,但我还是添加了一些细节。我很欣赏你的解决方案,但每个数据库的实现都需要DAO Facade。请详细说明实体接口<代码>公共接口City
?由@Virgi提供的解决方案也是一个很好的解决方案。我同意@Virgi提供了一个简单而有效的解决方案。我想这取决于您的需求-我希望我的通用dao中包含所有CRUD操作,然后有一个门面将我的持久性逻辑封装到单个事务中(并提供一个可读性好的api)。另一个选项是使用单个持久性单元并动态更新其中的属性,请在此处查看此答案
public enum Environment{
    DEV, PROD
}
public class GenericDAO<T> {

    @EJB
    private EntityManagerFactory entityManagerFactory;

    public void save(T entity, Environment env) {
        entityManagerFactory.getEntityManager(env).persist(entity);
    }

}
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">

    <persistence-unit name="first_PU" transaction-type="JTA">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <jta-data-source>jdbc/simfin_1</jta-data-source>
        <class>org.demo.model.MemRegMcgEntity</class>
        <class>org.demo.model.SavAccHolderMcgEntity</class>
        <class>org.demo.model.SavAccMcgEntity</class>
        <class>org.demo.model.SavTransactionEntity</class>
    </persistence-unit>

    <persistence-unit name="second_PU" transaction-type="JTA">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <jta-data-source>jdbc/simfin_2</jta-data-source>
        <class>org.demo.model.MemRegMcgEntity</class>
        <class>org.demo.model.SavAccHolderMcgEntity</class>
        <class>org.demo.model.SavAccMcgEntity</class>
        <class>org.demo.model.SavTransactionEntity</class>
    </persistence-unit>

</persistence>
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" ... >
    <persistence-unit name="UserInfo" transaction-type="JTA">
        <class>mx.saaskun.model.UserInfo</class>
    </persistence-unit>
</persistence>
@Stateless
@LocalBean
public class DynamicResource implements Serializable{
    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
    public EntityManagerFactory getEntityManager(unitName, jndiConnection){
        Map properties = new HashMap();
        properties.put("javax.persistence.jtaDataSource", jndiConnection);
        return Persistence.createEntityManagerFactory(unitName, properties);
    }
}
 public class UserService{
     @EJB
     DynamicResource radResources;

     public List<UserInfo> listAll(){
          List<UserInfo allUsers = new ArrayList<>();
          String[] databases = new String[]{"jndi/simfin","jndi/simfin2"};
          for(String db:databases){
               List results = listServerUsers("simfin", db);
               allUsers.addAll(results);
          }
          return allUsers;
     }

     protected List<UserInfo> listServerUsers(String unitName, String jndi){
         EntityManager em= radResources.getEntityManager(unitName,jndi);
         try {
             Query q = em.createNamedQuery("UserInfo.findAll");
             return (List<UserInfo>) q.getResultList();
         } finally {
             em.close();
         }
     }
 }