Zajmuję się tworzeniem prostego projektu "Book Store" przy użyciu Struts 1.3 + JPA (z Hibernate jako dostawcą trwałości). Nie mogę przełączyć się na Spring lub inne bardziej zaawansowane środowisko programistyczne (np. Jboss) i nie mogę używać żadnej konkretnej techniki Hibernate (np. Klasa Session
).EntityManager ThreadLocal pattern with JPA w JSE
Biorąc pod uwagę, że jestem w środowisku JSE, muszę jawnie zarządzać całym cyklem życia EntityManager.
Jednostka Book
jest zdefiniowany w następujący sposób:
@Entity
public class Book {
@Id private String isbn;
private String title;
private Date publishDate;
// Getters and Setters
}
I określonych trzy Action
klas, które odpowiadają, odpowiednio, pobierania wszystkich przypadków książki, odzyskanie jednego wystąpienia książki po ISBN i łączenia odłączoną książki do DB.
W celu zwiększenia rozbieżności między kodami biznes-logicznymi a kodem dostępu do danych, wprowadziłem prosty obiekt BookDAO
, który jest odpowiedzialny za wykonywanie operacji CRUD. W idealnym przypadku wszystkie połączenia związane z dostępem do danych powinny być delegowane do warstwy trwałości. Na przykład, ListBookAction
jest zdefiniowany w następujący sposób:
public class ListBookAction extends Action {
private BookDAO dao = new BookDAO();
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
// Retrieve all the books
List<Book> books = dao.findAll();
// Save the result set
request.setAttribute("books", books);
// Forward to the view
return mapping.findForward("booklist");
}
}
Przedmiotem BookDAO potrzebuje uzyskać dostęp do wystąpienia EntityManager
w tym celu każdą operację. Biorąc pod uwagę, że EntityManger
nie jest bezpieczny wątku, I wprowadził klasę pomocniczą o nazwie BookUnitSession
który hermetyzuje EntityManager w zmiennej ThreadLocal
:
public class BookUnitSession {
private static EntityManagerFactory emf = Persistence.createEntityManagerFactory("BookStoreUnit");
private static final ThreadLocal<EntityManager> tl = new ThreadLocal<EntityManager>();
public static EntityManager getEntityManager() {
EntityManager em = tl.get();
if (em == null) {
em = emf.createEntityManager();
tl.set(em);
}
return em;
}
}
Wszystko wydaje się działać, ale nadal mam pewne obawy. Mianowicie:
- Czy to rozwiązanie jest najlepsze? która jest najlepsza praktyka w tym przypadku?
- Nadal muszę wyraźnie zamknąć zarówno EntityManager, jak i EntityManagerFactory. Jak mogę to zrobić?
Dzięki
Dobra robota, ale prawdopodobnie masz na myśli JEE zamiast JSE. –
Dziękuję. Obecnie używam Tomcat 7 i Struts 1.3 bez żadnego serwera aplikacji. Dlatego powiedziałbym, że nie jestem całkowicie zgodny z JEE. Z punktu widzenia trwałości, jest jak bycie w środowisku JSE. Właśnie dlatego podałem tytuł JSE w tytule. –
Witam, czy to rozwiązanie wyszło na końcu? Słyszałem o pewnych problemach z użyciem ThreadLocal. –