Cache JPA Сутнасці з EJB

[Рэальны пытанне адзначаны ў <моцны> паўтлусты ўніз. Тут варта за як мага больш кароткі расказ маёй сітуацыі]

У мяне ёсць наступныя JPA сутнасцяў:

@Entity Genre{
 private String name;
 @OneToMany(mappedBy = "genre", cascade={CascadeType.MERGE, CascadeType.PERSIST})
 private Collection 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 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 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
.....

Кожны аб'ект мае звязаны з Stateless EJB, які дзейнічае як DAO, выкарыстоўваючы транзакцыю ня EntityManager. Напрыклад:

@Stateless
public class NovelDAO extends AbstractDAO {
    @PersistenceContext(unitName = "XXX")
    private EntityManager em;

    protected EntityManager getEntityManager() {
        return em;
    }

    public NovelDAO() {
        super(Novel.class);
    }
    //NovelDAO Specific methods
}

I am interested at when the catalog files are parsed and the corresponding entities are built (I usually read a whole batch of Catalogs at a time).

Being the parsing a String-driven procedure, I don't want to repeat actions like novelDAO.getByName("Title of Novel 1") so I would like to use a centralized cache for mappings of type 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, які выкарыстоўвае кэш і атрымлівае паўторна ініцыялізуецца кожны раз, калі новы файл каталог разабраны і атрымлівае «выдалены» пасля таго, як каталог захоўваецца.

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

    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) <моцны> Нарэшце, праблематычная фасолю: Кэш . Для CatalogBuilder я выкарыстаў кантэксце пашырэння настойлівасці (які мне патрэбен як сінтаксічны аналізатар выконвае некалькі аперацый succesive) разам з Stateful EJB; але ў дадзеным выпадку я не зусім упэўнены, што мне трэба. На самай справе, <моцны> кэш :

  1. Should stay in memory until the parser is finished with its job, but not longer (should not be a singleton) as the parsing is just a very particular activity which happens rarely.
  2. Should keep all of the entities in context, and should return managed entities form methods marked with *, otherwise the attempt to persist the catalog should fail (duplicated INSERTs)..*
  3. Should use the same persistence context as the 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 genreName2Object=new TreeMap();

    @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());
    genreDAO.persist(t);
    genreName2Object.put(t.getIdentifier(), em.merge(t));
return t;
}
}

Але, калі шчыра я не мог знайсці рашэнне, якое задавальняе гэтыя 3 ачкі, у той жа час . Напрыклад, з дапамогай іншага з улікам стану боб з пашыраным кантэксце інэрцыйнасці будзе працаваць на 1-м разабраны файл, але ў мяне ёсць паняцця не маю, што павінна адбыцца з 2-га файла на .. Сапраўды, для першага файла на ПК будзе створаны і распаўсюджваецца ад CatalogBuilder да Кэш , які будзе выкарыстоўваць адзін і той жа кампутар , Але пасля зборкі() вяртае ПК з CatalogBuilder павінна (я мяркую), выдаліць і нанава ствараецца пры паслядоўным разборы, хоць PC кэша павінен застацца «ў жывых»: калі ў дадзеным выпадку не выключэнне кідае? Іншая праблема заключаецца ў што рабіць, калі боб 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)"

Такім чынам, я паняцця не маю, як рэалізаваць свой кэш. Як бы вы вырашыць гэтую праблему?

2
Вы не зацікаўлены ў L2 падзялянай кэш, які выкарыстоўваецца JPA падзяліцца кэшаваныя аб'екты паміж PersistenceContexts?
дададзена аўтар Piotr Nowicki, крыніца
Прывітанне! Наколькі я зразумеў, кэш L2 уключаны па змаўчанні ў EclipseLink. Для таго, каб пераканацца, каб актываваць яго, я дадаў <агульны-кэш-рэжым> ALL на мой persistence.xml. Калі не вынік кожнага запыту аўтаматычна кэшуюцца тады? Я змяніў мой клас Cache непасрэдна ў звароце да БД (Паўсюдна DAOs'methods) замест таго, каб захоўваць значэнні ў карты, але з FINE ўзроўню часопіса можна ўбачыць запыты SQL выконваюцца кожны раз, калі я называю метадам findXXXCreateIfAbsent() .. Што дрэннага ў такім падыходзе?
дададзена аўтар Federico, крыніца

1 адказы

EclipseLink configuration :

  • You can have specify property in configuration file for all entites.

  • At entity level with @Cache annotation, specifying different attributes.

<Моцны> Канфігурацыя Агульныя JPA:

  • At entity level by using @Cacheable annotation with value attribute as true.

  • Specifying the retrieval mode by CacheRetrieveMode, attribute USE to enable else BYPASS.

    entityManager.setProperty("javax.persistence.cache.retrieveMode", CacheRetrieveMode.USE);

  • Configuring the storage in cache by CacheStoreMode with attribute BYPASS, USE or REFRESH.

    entityManager.setProperty("javax.persistence.cache.storeMode",CacheStoreMode.REFRESH);

  • Cache interface represents shared cache. To remove all or some cached entity, you can call one of the evict methods. You can get reference of cache interface from EntityManagerFactory.

0
дададзена