使用JPA / EclipseLink / EJB从Java Web应用程序访问多个数据库 [英] Accessing multiple database from a Java web application using JPA/EclipseLink/EJB

查看:155
本文介绍了使用JPA / EclipseLink / EJB从Java Web应用程序访问多个数据库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  public class GenericDAO< T> {
$ b / *
* private static final EntityManagerFactory emf =
* Persistence.createEntityManagerFactory(icanPU);私人EntityManager
* em;
* /
/ *
*持久化上下文被注入下面的@PersistenceContext
*注解。这将使用
* persistence.xml中指定的所有持久性配置。
*
*注意这种注入只能用于JTA数据源。
* /
@PersistenceContext(unitName =SavingBalanceDemoServer_PU)
private EntityManager em;
私人课程< 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);
}

//由Sudeep添加用于批量插入List对象。 (Iterator< T> iterator = objList.iterator(); iterator.hasNext();){
T t =(T($ T $ gt; $ T $ objList)
public void saveList(List< T> objList) )iterator.next();
em.persist(t);



public void delete(Object id,Class< T> class){
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();
}

//由Sudeep添加用于批量更新List对象。 (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);
返回em.find(entityClass,entityID);

$ b public T find(long entityID){
// em.getEntityManagerFactory()。getCache()。evict(entityClass,entityID);
返回em.find(entityClass,entityID);

$ b $ public T find(Object compositePkObject){
// em.getEntityManagerFactory()。getCache()。evict(entityClass,entityID);
返回em.find(entityClass,compositePkObject);


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

//使用未选中,因为JPA没有
// em.getCriteriaBuilder()。createQuery()< T>方法
@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(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;
}
}
返回null;


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

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

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

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

返回结果;
}

@SuppressWarnings(unchecked)
public List< T> findAllWithGivenConditionLazyLoading(String namedQuery,
Map< String,Object>参数,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();

返回结果;

}

@SuppressWarnings(unchecked)
public List< T> findAllWithGivenConditionJpql(String jpql,
Map< String,Object>参数){
List< T> result = null;
查询查询= em.createQuery(jpql);

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

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

返回结果;

$ b @SuppressWarnings(unchecked)
public T findOneWithGivenConditionJpql(String jpql,
Map< String,Object>参数){
查询查询= em.createQuery(jpql);

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

//使用未选中,因为JPA没有
// query.getSingleResult()< T>方法
@SuppressWarnings(unchecked)
protected T findOneResult(String namedQuery,Map< String,Object> parameters){
T result = null;

尝试{
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);

//如果传递的参数将会填充参数的方法不是
// null和空
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();
返回null;
} catch(org.eclipse.persistence.exceptions.DatabaseException e){
/ * JSFMessageUtil jsfMessageUtil = new JSFMessageUtil();
jsfMessageUtil
.sendErrorMessageToUser(Database Server is unavailable or not accessible!); * /
e.printStackTrace();
}

返回结果;

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


$ b $ **
* @param startingAt
* @param maxPerPage
* @param t
* @return属于这个类的持久实体列表t
* /
@SuppressWarnings(unchecked)
public List< T> getAllLazyEntities(int startingAt,int maxPerPage,Class< T> t){
//常规查询,用于搜索db
中的玩家Query query = getEntityManager()。createQuery(
)select p from+ t.getName()+p);
query.setFirstResult(startingAt);
query.setMaxResults(maxPerPage);

返回query.getResultList();

$ b / **
* @param clazz
* @return从后端对现有实体行进行计数
* /
public int countTotalRows(Class< T> clazz){
Query query = getEntityManager()。createQuery(
from+ clazz.getName()+p)选择COUNT(p)

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

return result.intValue();
}

/ **
* @根据给定的
*条件从后端返回现有实体行的数量
* /
public int countTotalRowsWithCond(Class clazz,String Cond){
Query query = getEntityManager()
.createQuery(
)从+ clazz.getName()+中选择COUNT(p) p
+ Cond +);

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

return result.intValue();




$ b

动态修改 unitName @PersistenceContext(unitName =SavingBalanceDemoServer_PU)一个好主意?请给我建议。



我的 persistence.xml 是:

 <?xml version =1.0encoding =UTF-8?> 
< persistence version =2.1
xmlns =http://xmlns.jcp.org/xml/ns/persistencexmlns: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>
< /余辉>

请在此文件中提出一些优化/更改。



我一直在使用 EJB 来利用Generic类。
eg:

  @Stateless 
public class MemberEJB extends GenericDAO< MemRegMcgEntity> {
/ **
* see GenericDAO#GenericDAO(Class< T>)
* /
public MemberEJB(){
super(MemRegMcgEntity.class);
// TODO自动生成的构造函数存根
}

公共列表< MemRegMcgEntity> getListOfMemberByName(String name){
Map< String,Object>参数= new HashMap< String,Object>();
parameters.put(memName,name +'%');

返回super.findAllWithGivenCondition(Mem.getMemberByName,parameters);
}

}

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

解决方案

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

 $ @ b 





$ EntityManagerFactory {

@PersistenceContext(unitName =second_PU)
EntityManager secondEm;
$ b $ public EntityManager getEntityManager(Environment env){
switch(env){
case this:
return firstEm;
案例:
返回secondEm;
默认值:
返回null;



code
$ b示例枚举:

  public enum环境{
DEV,PROD
}
pre>

在您的情况下,GenericDAO将以这种方式进行重构:

  public class GenericDAO< T> {

@EJB
private EntityManagerFactory entityManagerFactory;

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

}

然后你的客户会打电话给 dao.save(someEntity,Environment.DEV)



你的persistence.xml最终会像这样:

 <?xml version =1.0encoding =UTF-8?> 
< persistence version =2.1
xmlns =http://xmlns.jcp.org/xml/ns/persistencexmlns: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_PUtransaction-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_PUtransaction-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>

< /持久性>


I have built a simple SOAP java application(server side) and I am using Glassfish4,JPA/EclipseLink,EJB. I have set the db connections(resources/pools) in Glassfish. Please suggest some design pattern/knowledge to utilize multiple databases from a single application. Is creating multiple persistence-unit a good idea for multiple access?? Or is there any other optimized solution ? I have a generic class of database access.

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

Is dynamically modifying unitName in @PersistenceContext(unitName = "SavingBalanceDemoServer_PU") a good idea ? Please suggest me.

My persistence.xml is :

<?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>

Please suggest some optimization/changes in this file.

And I have been using EJB to utilize the Generic class. eg:

@Stateless
public class MemberEJB extends GenericDAO<MemRegMcgEntity> {
/**
* @see GenericDAO#GenericDAO(Class<T>)
*/
public MemberEJB() {
super(MemRegMcgEntity.class);
// TODO Auto-generated constructor stub
}

public List<MemRegMcgEntity> getListOfMemberByName(String name){
Map<String, Object> parameters = new HashMap<String, Object>();
parameters.put("memName", name+'%');

return super.findAllWithGivenCondition("Mem.getMemberByName", parameters);
}

}

The client app provides the database name to use and every database has same structure. I just need to access multiple database according to client's request.

解决方案

We faced the same use case and ended up creating multiple persistence-unit and building an entity manager factory which returns the correct entity manager according to an parameter sent by the client (as an enum in our case, Environment). Then, instead of injecting the persistence context in the clients, we inject this factory and call getEntityManager(environment).

@Stateless
public class EntityManagerFactory {

    @PersistenceContext(unitName = "first_PU")
    EntityManager firstEm;

    @PersistenceContext(unitName = "second_PU")
    EntityManager secondEm;

    public EntityManager getEntityManager(Environment env) {
        switch (env) {
        case THIS:
            return firstEm;
        case THAT:
            return secondEm;
        default:
            return null;
        }
    }
}

Example enum:

public enum Environment{
    DEV, PROD
}

In your case, the GenericDAO would be refactored this way:

public class GenericDAO<T> {

    @EJB
    private EntityManagerFactory entityManagerFactory;

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

}

And then your client would call with dao.save(someEntity, Environment.DEV).

Your persistence.xml would end up like this:

<?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>

这篇关于使用JPA / EclipseLink / EJB从Java Web应用程序访问多个数据库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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