Как использовать JPA EclipsElink для подключения к БД в многослойной среде (REST + EJB + CORE)?

StackOverflow https://stackoverflow.com/questions/3521681

Вопрос

Я использую сервер Glassfish V3.

Обычно соединение DB с EJB3 + JPA (EclipsElink) осуществляется посредством инъекции, с @persistenceunit или @persistencecontext.

Однако в моем приложении есть 3 уровня:

  • Core (содержит бизнес -логику, объекты, обработка исключений и т. Д.)

  • EJB на вершине этого, вызывая правильные основные объекты и методы для выполнения работы. Этот EJB называется другими внутренними модулями нашей ERP.

  • Уровень отдыха на нем для использования на веб -сайтах Frontend.

Я не хочу получить ни EntityManager, ни ЭДС (EM EM Factory) в EJB, потому что я хочу, чтобы мой средний слой не знал, что под ним используется DB. В конце концов, позже я мог бы принять решение изменить свою основную реализацию для не использующей DB.

Я вижу только два плохих решения:

  • 1) Добавляйте параметр EM каждый раз, когда я вызываю метод слоя ядра, который нуждается в соединении DB. Очень уродливо и снова идет то, что я сказал выше.

  • 2) В каждом методе ядра, нуждающегося в подключении DB, я создаю фабрику, их, использую их, а затем закрываю их обоих.

Я пытался разрезать вещи в середине, имея одну фабрику на класс основного уровня, и EMS создана и закрыта в каждом методе. Но у меня все еще есть утечки памяти, как это:

javax.servlet.ServletException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.0.0.v20091127-r5931): org.eclipse.persistence.exceptions.DatabaseException

Internal Exception: java.sql.SQLException: Error in allocating a connection. Cause: In-use connections equal max-pool-size and expired max-wait-time. Cannot allocate more connections.

Я думаю, это потому, что если один из моих методов EJB использует 10 разных объектов, он создает 10 заводов EM, и ни один из них не закрыт.

Пример типичного использования в основном объекте:

 EntityManager em = emf.createEntityManager();
 em.getTransaction().begin();
 // do some stuff with em; for example persist, etc
 em.flush();
 em.close();

Стоит ли пойти на решение 2? Есть ли способ использовать одну фабрику EM на этом основном уровне? Кажется, что спецификация JPA предполагает, что вы собираетесь использовать объекты только на уровне EJB, что плохо в многослойных приложениях.

РЕДАКТИРОВАТЬ: Вот текущий статус после попытки @Inject:

  • Добавлен пустой файл beans.xml в каталоге /meta-inf в моей основной банке.

  • Родительский класс DAO теперь такой:

    public class examplebzl {

     public EntityManagerFactory emf;
     @Inject public Emf emfobject;
    
     public ExampleBZL()
     {
        this.emf = emfobject.emf;
     }
    
  • Класс EMF очень прост и без сохранения состояния.

    @StateLess Public Class EMF реализует emfabStract {

    @PersistenceUnit(unitName = Setup.persistenceUnitName)
    public EntityManagerFactory emf;
    
    public Emf()
    {
    }
    

    }

Я, должно быть, делаю что -то не так, но инъекция не работает, в целом в стеклянной рыбке, которую я вижу »[EJB, Weld, Web]» в списке двигателей, поэтому CDI загружается.

Servlet.service() for servlet Jersey Web Application threw exception
java.lang.NullPointerException
    at com.blablabla.core.bizlogic.ExampleBZL.<init>(ExampleBZL.java:40)

Мне не хватает других аннотаций ?? Действительно ли это работает, чтобы сделать внедрение в банке с этими двумя небольшими аннотациями (без гражданства с одной стороны, инъекция с другой)?

Это было полезно?

Решение

Что если у вас было две сеансовые бобы? Один с инъецированным EntityManager, который может использовать JTA, а другой - ваш текущий сессионный фасоль.

В настоящее время я собираю серию на мой блог Используя сеанс фасоль в качестве службы отдыха с помощью Eclipselink & Glass Fish v3:

Ниже я вводит EntityManager в свой сессионный бон, который служит моей службой отдыха:

package org.example.customer;

import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.ws.rs.Path;

import org.eclipse.persistence.rest.JPASingleKeyResource;

@Stateless
@LocalBean
@Path("/customers")
public class CustomerService  {

    @PersistenceContext(unitName="CustomerService", type=PersistenceContextType.TRANSACTION)
    EntityManager entityManager;

}

Вы можете связать свои сеансовые бобы, используя аннотацию @EJB:

package org.example;

import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.naming.Context;
import javax.naming.InitialContext;

@Stateless
@LocalBean
@EJB(name = "someName", beanInterface = CustomerService.class)
public class OtherSessionBean {

    public Customer read(long id) {
        try {
            Context ctx = new InitialContext();
            CustomerService customerService = (CustomerService) ctx.lookup("java:comp/env/someName");
            return customerService.read(id);
        } catch(Exception e) {
            throw new RuntimeException(e);
        }
    }

}

Другие советы

С Javaee 6 вы можете определить свои классы основного уровня как бобы и вводить там ресурсы. Пожалуйста, проверьте контекст и инъекцию зависимости (CDI) с Javaee 6.

Я не уверен, что это хороший ответ, но я нашел это:Ссылка форума Сказание:

Похоже, что взаимодействие между JPA и CDI рассматривалось, но не стало частью спецификации по какой -то неизвестной причине. Если я узнаю о причине, я обновлю этот поток. В среднем, когда он был отправлен в качестве отзывов для соответствующих людей. Итак, этот определенно не ошибка в стеклянной рыбке.

Итак, это объясняет, почему мой @Inject (из класса, содержащего менеджер сущностей) в классе Java, не работает?

Вот последний рабочий код, благодаря Blaise:

  • Класс отца, который «получает» связь

    Import com.wiztivi.apps.wsp.billing.interfaces.bin.db.newinterface; Импорт javax.ejb.localbean; Импорт javax.ejb.stateless; Импорт javax.naming.context; Импорт javax.naming.initialContext; Импорт javax.persistence.entityManager;

    @Stateless
    @LocalBean
    public class FatherService {
    
     public EntityManager em;
    
     public FatherService()
     {
     }
    
    
    
     public EntityManager getGoodEm()
     {
        try {
            Context ctx = new InitialContext();
            NewInterface dp = (NewInterface) ctx.lookup("java:global/billing-ear/billing-connection/DataProvider");
            em = dp.getEm();
        } catch(Exception e) {
            throw new RuntimeException(e);
        }
         return em;
     }
    
    }
    
  • Класс, который «обеспечивает» соединение (в отдельной банке подключения с объектами)

    Импорт javax.ejb.localbean; Импорт javax.ejb.stateless; Импорт javax.persistence.entityManager; Импорт javax.persistence.persistencecontext; Импорт javax.persistence.persistencecontexttype;

    @StateLess @Localbean Public Class DataProvider реализует newInterface {

    @PersistenceContext(unitName=Setup.persistenceUnitName, type=PersistenceContextType.TRANSACTION)
    public EntityManager entityManager;
    
    public DataProvider() {
    }
    
    @Override
    public EntityManager getEm()
    {
        return entityManager;
    }
    

    }

Что -то важное: вы должны поместить @stateless на любой класс слоя «более высокого уровня», который будет вызывать EJB Fatherservice (в моем случае остальные классы). Орденс -слой должен быть упакован в качестве EJB, а также соединение тоже, оба в ухе

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top