Как использовать кеш второго уровня Hibernate с JPA?

Я реализую механизм сохранения на основе значений атрибутов сущности. Весь доступ к БД осуществляется через Hibernate. У меня есть таблица, содержащая пути для узлов, она чрезвычайно проста, просто идентификатор и путь (строка). Путей будет немного, около нескольких тысяч.

В основной таблице миллионы строк, и вместо того, чтобы повторять пути, я нормализовал пути к их собственной таблице. Ниже приведено поведение, которое я хочу при вставке в основную таблицу

1) Проверить, существует ли путь в таблице путей (запрос через диспетчер объектов, используя значение пути в качестве параметра)

2) если он не существует, вставить и получить идентификатор (сохранить через диспетчер объектов)

3) поместить идентификатор в качестве значения внешнего ключа в строку основной таблицы и вставить его в основную таблицу.

Это будет происходить тысячи раз для набора объектов предметной области, которые соответствуют большому количеству строк в основной таблице и некоторых других таблицах. Таким образом, шаги, описанные выше, повторяются с использованием одной транзакции, например:

    EntityTransaction t = entityManager.getTransaction();
    t.begin();
    //perform steps given above, check, and then persist etc..
    t.commit();

Когда я выполняю шаг 2, это приводит к огромному падению производительности всей операции. Напрашивается кеширование, потому что через какое-то время та таблица будет максимум 10-20к записей с очень редкими новыми вставками. Я пытался сделать это с помощью Hibernate и потерял почти 2 дня.

Я использую Hibernate 4.1 с аннотациями JPA и ECache.Я попытался включить кэширование запросов, даже используя один и тот же объект запроса во всех вставках, как показано ниже:

Query call = entityManager.createQuery("select pt from NodePath pt " +
                "where pt.path = :pathStr)");
        call.setHint("org.hibernate.cacheable", true);  
        call.setParameter("pathStr", pPath);
        List<NodePath> paths = call.getResultList();
        if(paths.size() > 1)
            throw new Exception("path table should have unique paths");
        else if (paths.size() == 1){
            NodePath path = paths.get(0);
            return path.getId();
        }
        else {//paths null or has zero size
            NodePath newPath = new NodePath();
            newPath.setPath(pPath);
            entityManager.persist(newPath);
            return newPath.getId();
        }

Сущность NodePath аннотируется следующим образом:

@Entity
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
@Table(name = "node_path", schema = "public")
public class NodePath implements java.io.Serializable {

Насколько я вижу, кэш запросов используется из статистики, но не сообщается об использовании кеша второго уровня:

queries executed to database=1
query cache puts=1
query cache hits=689
query cache misses=1
....
second level cache puts=0
second level cache hits=0
second level cache misses=0
entities loaded=1
....

Простая, написанная от руки хеш-таблица в качестве кеша работает, как и ожидалось, резко сокращая общее время. Я предполагаю, что мне не удается запустить кэширование Hibernate из-за характера моих операций.

Как мне использовать кэш второго уровня гибернации с этой настройкой?Для записи, это мой XML-файл сохраняемости:

http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd " версия = "2.0">

<provider>org.hibernate.ejb.HibernatePersistence</provider> 
<class>...</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>

  <properties>
   <property name="hibernate.connection.driver_class" value="org.postgresql.Driver" />
    <property name="hibernate.connection.password" value="zyx" />
    <property name="hibernate.connection.url" value="jdbc:postgresql://192.168.0.194:5432/testdbforml" />
    <property name="hibernate.connection.username" value="postgres"/>
    <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
    <property name="hibernate.search.autoregister_listeners" value="false"/>
    <property name="hibernate.jdbc.batch_size" value="200"/>
     <property name="hibernate.connection.autocommit" value="false"/> 
     <property name="hibernate.generate_statistics" value="true"/>
    <property name="hibernate.cache.use_structured_entries" value="true"/>

    <property name="hibernate.cache.use_second_level_cache" value="true"/>
     <property name="hibernate.cache.use_query_cache" value="true"/>           

     <property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory"/>              

  </properties>

7
задан mahonya 15 May 2012 в 12:30
поделиться