[Реальный вопрос отмечен жирным шрифтом вниз.Ниже приведено как можно более короткое объяснение моей ситуации]
У меня есть следующие объекты JPA:
@Entity Genre{
private String name;
@OneToMany(mappedBy = "genre", cascade={CascadeType.MERGE, CascadeType.PERSIST})
private Collection<Novel> novels;
}
@Entity
class Novel{
@ManyToOne(cascade={CascadeType.MERGE, CascadeType.PERSIST})
private Genre genre;
private String titleUnique;
@OneToMany(mappedBy="novel", cascade={CascadeType.MERGE, CascadeType.PERSIST})
private Collection<NovelEdition> editions;
}
@Entity
class NovelEdition{
private String publisherNameUnique;
private String year;
@ManyToOne(optional=false, cascade={CascadeType.PERSIST, CascadeType.MERGE})
private Novel novel;
@ManyToOne(optional=false, cascade={CascadeType.MERGE, CascadeType.PERSIST})
private Catalog appearsInCatalog;
}
@Entity
class Catalog{
private String name;
@OneToMany(mappedBy = "appearsInCatalog", cascade = {CascadeType.MERGE, CascadeType.PERSIST})
private Collection<NovelEdition> novelsInCatalog;
}
Идея состоит в том, чтобы иметь несколько романов принадлежность каждого к определенному жанру , для которого может существовать больше, чем издание (другой издатель, год и т. д.).Для простоты NovelEdition может принадлежать только одному Каталогу , являющемуся таким Каталогом, представленным таким текстовым файлом:
Catalog: Name Of Catalog 1
-----------------------
"Title of Novel 1", "Genre1 name","Publisher1 Name", 2009
"Title of Novel 2", "Genre1 name","Pulisher2 Name", 2010
.....
Catalog: Name Of Catalog 2
-----------------------
"Title of Novel 1", "Genre1 name","Publisher2 Name", 2011
"Title of Novel 2", "Genre1 name","Pulisher1 Name", 2011
.....
Каждый объект связан с EJB без сохранения состояниякоторый действует как DAO, используя Transity Scoped EntityManager.Например:
@Stateless
public class NovelDAO extends AbstractDAO<Novel> {
@PersistenceContext(unitName = "XXX")
private EntityManager em;
protected EntityManager getEntityManager() {
return em;
}
public NovelDAO() {
super(Novel.class);
}
//NovelDAO Specific methods
}
Меня интересует, когда файлы каталога анализируются и создаются соответствующие объекты (я обычно читаю целую партию каталогов за раз).
Поскольку я выполняю синтаксический анализ строковой процедуры, я не хочу повторять такие действия, как novelDAO.getByName ("Название романа 1") , поэтому я хотел бы использовать централизованноекеш для отображений типа String-Identifier-> Entity object.
В настоящее время я использую 3 объекта: 1) Анализатор файлов, который делает что-то вроде:
final CatalogBuilder catalogBuilder = //JNDI Lookup
//for each file:
String catalogName = parseCatalogName(file);
catalogBuilder.setCatalogName(catalogName);
//For each novel edition
String title= parseNovelTitle();
String genre= parseGenre();
...
catalogBuilder.addNovelEdition(title, genre, publisher, year);
//End foreach
catalogBuilder.build();
2)CatalogBuilder является Stateful EJB, который использует Cache и переинициализируется каждый раз, когда новый файл каталога анализируется и удаляется после сохранения каталога.
@Stateful
public class CatalogBuilder {
@PersistenceContext(unitName = "XXX", type = PersistenceContextType.EXTENDED)
private EntityManager em;
@EJB
private Cache cache;
private Catalog catalog;
@PostConstruct
public void initialize() {
catalog = new Catalog();
catalog.setNovelsInCatalog(new ArrayList<NovelEdition>());
}
public void addNovelEdition(String title, String genreStr, String publisher, String year){
Genre genre = cache.findGenreCreateIfAbsent(genreStr);//**
Novel novel = cache.findNovelCreateIfAbsent(title, genre);//**
NovelEdition novEd = new NovelEdition();
novEd.setNovel(novel);
//novEd.set publisher year catalog
catalog.getNovelsInCatalog().add();
}
public void setCatalogName(String name) {
catalog.setName(name);
}
@Remove
public void build(){
em.merge(catalog);
}
}
3) Наконец,проблемный компонент: Cache .Для CatalogBuilder я использовал расширенный контекст персистентности (который мне нужен, так как Parser выполняет несколько последовательных транзакций) вместе с Stateful EJB;но в этом случае я не совсем уверен, что мне нужно.На самом деле, кеш :
- Должен оставаться в памяти до тех пор, пока синтаксический анализатор не завершит свою работу, но не дольше (не должен быть одноэлементным) при синтаксическом анализеэто просто очень специфическое действие, которое происходит редко.
- Должно держать все объекты в контексте и возвращать управляемые объекты из методов, отмеченных *, в противном случае попытка сохранитсядолжен произойти сбой каталога (дублированные вставки) .. *
- Следует использовать тот же контекст постоянства, что и CatalogBuilder.
То, что у меня сейчас есть:
@Stateful
public class Cache {
@PersistenceContext(unitName = "XXX", type = PersistenceContextType.EXTENDED)
private EntityManager em;
@EJB
private sessionbean.GenreDAO genreDAO;
//DAOs for other cached entities
Map<String, Genre> genreName2Object=new TreeMap<String, Genre>();
@PostConstruct
public void initialize(){
for (Genre g: genreDAO.findAll()) {
genreName2Object.put(g.getName(), em.merge(g));
}
}
public Genre findGenreCreateIfAbsent(String genreName){
if (genreName2Object.containsKey(genreName){
return genreName2Object.get(genreName);
}
Genre g = new Genre();
g.setName();
g.setNovels(new ArrayList<Novel>());
genreDAO.persist(t);
genreName2Object.put(t.getIdentifier(), em.merge(t));
return t;
}
}
Но, честно говоря Я не смог найти решение, которое бы удовлетворяло этим 3 точкам одновременно .Например, использование другого stateful bean-компонента с расширенным контекстом персистентности будет работать для 1-го проанализированного файла, но я понятия не имею, что должно произойти со 2-м файлом на самом деле. Действительно, для первого файла ПК будетсоздается и распространяется из CatalogBuilder в Cache , который затем будет использовать тот же компьютер.Но после возврата build () ПК из CatalogBuilder должен (я думаю) быть удален и воссоздан во время последовательного анализа, хотя ПК с кэшем должен оставаться «живым»: не должно ли в этом случае создаваться исключение?Другая проблема заключается в том, что делать, когда компонент Cache пассивирован.В настоящее время я получаю исключение:
"passivateEJB(), Exception caught ->
java.io.IOException: java.io.IOException
at com.sun.ejb.base.io.IOUtils.serializeObject(IOUtils.java:101)
at com.sun.ejb.containers.util.cache.LruSessionCache.saveStateToStore(LruSessionCache.java:501)"
Следовательно, я понятия не имею, как реализовать мой кеш.Как бы вы решили проблему?