«Кэшированный элемент заблокирован», вызывая оператор выбора в Hibernate - PullRequest
3 голосов
/ 13 марта 2009

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

У меня есть один объект, который содержит экземпляры самого себя. Например, часть, которая состоит из нескольких частей.

Мне действительно нужно минимизировать операторы выбора, которые Hibernate использует при входе обновленного объекта. После просмотра журналов я вижу этот вывод журнала, который вызывает оператор SELECT:

Кэшированный элемент был заблокирован: com.cache.dataobject.Part.parts # 1

Что я могу изменить в своих сопоставлениях аннотаций, файлах XML, поставщике кэширования или логике, чтобы не блокировать кэшированный элемент? Мне бы очень хотелось избавиться от этого оператора select.

Я включил Entity, DataObject, код, с которым я тестирую, и вывод журнала.

Версия Hibernate: 3,4

Версия EHCache: 1.2.3 (входит в комплект загрузки Hibernate)

Данные объектаObject:

package com.cache.dataobject;

import java.io.Serializable;
import java.lang.String;
import java.util.List;

import javax.persistence.*;

import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;

import static javax.persistence.CascadeType.ALL;

/**
 * Entity implementation class for Entity: Part
 * 
 */
@Entity
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Part implements Serializable {

    private int id;
    private String name;
    private static final long serialVersionUID = 1L;
    private Part mainPart;
    private List<Part> parts;

    public Part() {
        super();
    }

    @Id
    public int getId() {
        return this.id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Column(name = "PART_NAME")
    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @ManyToOne(cascade = ALL)
    public Part getMainPart() {
        return mainPart;
    }

    public void setMainPart(Part mainPart) {
        this.mainPart = mainPart;
    }

    @OneToMany(cascade = ALL)
    @JoinColumn(name = "mainPart_id", referencedColumnName = "id")
    @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
    public List<Part> getParts() {
        return parts;
    }

    public void setParts(List<Part> parts) {
        this.parts = parts;
    }

}

CacheDao:

package com.cache.dao;

import java.util.List;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import com.cache.dataobject.Part;

/**
 * Session Bean implementation class CacheDao
 */
@Stateless(mappedName = "ejb/CacheDao")
public class CacheDao implements CacheDaoRemote {

    @PersistenceContext(unitName="CacheProjectUnit")
    EntityManager em;

    /**
     * Default constructor. 
     */
    public CacheDao() {
        // TODO Auto-generated constructor stub
    }

    public Part addPart(Part part){
        System.out.println("CALLED PERSIST");
        em.persist(part);
        return part;
    }

    public Part updatePart(Part part){
        System.out.println("CALLED MERGE");
        em.merge(part);
        return part;
    }

}

Тестовый код клиента:

package com.cache.dao;

import java.util.ArrayList;
import java.util.List;

import javax.naming.InitialContext;
import javax.naming.NamingException;

import com.cache.dao.CacheDaoRemote;
import com.cache.dataobject.Part;


public class test {

    /**
     * @param args
     */
    public static void main(String[] args) {
        InitialContext ctx;
        try {
            ctx = new InitialContext();
            CacheDaoRemote dao = (CacheDaoRemote) ctx.lookup("ejb/CacheDao");
            Part computer = new Part();
            computer.setId(1);
            computer.setName("Computer");

            List<Part> parts = new ArrayList<Part>();

            Part cpu = new Part();
            cpu.setId(2);
            cpu.setName("CPU");

            Part monitor = new Part();
            monitor.setId(3);
            monitor.setName("Monitor");

            parts.add(cpu);
            parts.add(monitor);

            computer.setParts(parts);

            dao.addPart(computer);

            computer.setName("DellComputer");

            dao.updatePart(computer);


        } catch (NamingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

}

persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
    xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
    <persistence-unit name="CacheProjectUnit">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <!-- JNDI name of the database resource to use -->
        <jta-data-source>jdbc/H2Pool</jta-data-source>
        <properties>
            <!-- The database dialect to use -->
            <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
            <!-- drop and create tables at deployment -->
            <property name="hibernate.hbm2ddl.auto" value="create-drop" />
            <property name="hibernate.max_fetch_depth" value="3" />
            <property name="hibernate.cache.provider_class" value="org.hibernate.cache.EhCacheProvider" />
        </properties>
    </persistence-unit>
</persistence>

EhCache.xml

<ehcache>
    <diskStore path="java.io.tmpdir"/>

    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="true"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU"
            />


    <cache name = "com.cache.dataobject.Part"
        maxElementsInMemory="100000"
        eternal="true"
        diskPersistent="false"
        timeToIdleSeconds="0"
        timeToLiveSeconds="0"
    />


    <cache name = "com.cache.dataobject.Part.parts"
        maxElementsInMemory="100000"
        eternal="true"
        diskPersistent="false"
        timeToIdleSeconds="0"
        timeToLiveSeconds="0"
    />


</ehcache>

Выходной журнал:

INFO: CALLED PERSIST
FINEST: Cache lookup: com.cache.dataobject.Part#1
FINE: key: com.cache.dataobject.Part#1
FINE: Element for com.cache.dataobject.Part#1 is null
FINEST: Cache miss: com.cache.dataobject.Part#1
FINEST: Cache lookup: com.cache.dataobject.Part#2
FINE: key: com.cache.dataobject.Part#2
FINE: Element for com.cache.dataobject.Part#2 is null
FINEST: Cache miss: com.cache.dataobject.Part#2
FINEST: Cache lookup: com.cache.dataobject.Part#3
FINE: key: com.cache.dataobject.Part#3
FINE: Element for com.cache.dataobject.Part#3 is null
FINEST: Cache miss: com.cache.dataobject.Part#3
FINEST: Invalidating: com.cache.dataobject.Part.parts#1
FINE: key: com.cache.dataobject.Part.parts#1
FINE: Element for com.cache.dataobject.Part.parts#1 is null
FINE: insert into Part (mainPart_id, PART_NAME, id) values (?, ?, ?)
FINE: insert into Part (mainPart_id, PART_NAME, id) values (?, ?, ?)
FINE: insert into Part (mainPart_id, PART_NAME, id) values (?, ?, ?)
FINE: update Part set mainPart_id=? where id=?
FINE: update Part set mainPart_id=? where id=?
FINEST: Inserting: com.cache.dataobject.Part#1
FINE: key: com.cache.dataobject.Part#1
FINE: Element for com.cache.dataobject.Part#1 is null
FINEST: Inserted: com.cache.dataobject.Part#1
FINEST: Inserting: com.cache.dataobject.Part#2
FINE: key: com.cache.dataobject.Part#2
FINE: Element for com.cache.dataobject.Part#2 is null
FINEST: Inserted: com.cache.dataobject.Part#2
FINEST: Inserting: com.cache.dataobject.Part#3
FINE: key: com.cache.dataobject.Part#3
FINE: Element for com.cache.dataobject.Part#3 is null
FINEST: Inserted: com.cache.dataobject.Part#3
FINEST: Releasing: com.cache.dataobject.Part.parts#1
FINE: key: com.cache.dataobject.Part.parts#1

INFO: CALLED MERGE
FINEST: Cache lookup: com.cache.dataobject.Part#1
FINE: key: com.cache.dataobject.Part#1
FINEST: Cache hit: com.cache.dataobject.Part#1
FINEST: Cache lookup: com.cache.dataobject.Part#1
FINE: key: com.cache.dataobject.Part#1
FINEST: Cache hit: com.cache.dataobject.Part#1
FINEST: Cache lookup: com.cache.dataobject.Part#2
FINE: key: com.cache.dataobject.Part#2
FINEST: Cache hit: com.cache.dataobject.Part#2
FINEST: Cache lookup: com.cache.dataobject.Part#2
FINE: key: com.cache.dataobject.Part#2
FINEST: Cache hit: com.cache.dataobject.Part#2
FINEST: Cache lookup: com.cache.dataobject.Part#3
FINE: key: com.cache.dataobject.Part#3
FINEST: Cache hit: com.cache.dataobject.Part#3
FINEST: Cache lookup: com.cache.dataobject.Part#3
FINE: key: com.cache.dataobject.Part#3
FINEST: Cache hit: com.cache.dataobject.Part#3
FINEST: Cache lookup: com.cache.dataobject.Part.parts#1
FINE: key: com.cache.dataobject.Part.parts#1
FINEST: Cached item was locked: com.cache.dataobject.Part.parts#1
FINE: select parts0_.mainPart_id as mainPart3_1_, parts0_.id as id1_, parts0_.id as id18_0_, parts0_.mainPart_id as mainPart3_18_0_, parts0_.PART_NAME as PART2_18_0_ from Part parts0_ where parts0_.mainPart_id=?
FINEST: Caching: com.cache.dataobject.Part.parts#1
FINE: key: com.cache.dataobject.Part.parts#1
FINEST: Cached: com.cache.dataobject.Part.parts#1
FINEST: Invalidating: com.cache.dataobject.Part.parts#2
FINE: key: com.cache.dataobject.Part.parts#2
FINE: Element for com.cache.dataobject.Part.parts#2 is null
FINEST: Invalidating: com.cache.dataobject.Part.parts#3
FINE: key: com.cache.dataobject.Part.parts#3
FINE: Element for com.cache.dataobject.Part.parts#3 is null
FINEST: Invalidating: com.cache.dataobject.Part.parts#1
FINE: key: com.cache.dataobject.Part.parts#1
FINEST: Invalidating: com.cache.dataobject.Part#1
FINE: key: com.cache.dataobject.Part#1
FINE: update Part set mainPart_id=?, PART_NAME=? where id=?
FINE: update Part set mainPart_id=null where mainPart_id=?
FINE: update Part set mainPart_id=null where mainPart_id=?
FINEST: Updating: com.cache.dataobject.Part#1
FINE: key: com.cache.dataobject.Part#1
FINEST: Updated: com.cache.dataobject.Part#1
FINEST: Releasing: com.cache.dataobject.Part.parts#2
FINE: key: com.cache.dataobject.Part.parts#2
FINEST: Releasing: com.cache.dataobject.Part.parts#3
FINE: key: com.cache.dataobject.Part.parts#3
FINEST: Releasing: com.cache.dataobject.Part.parts#1
FINE: key: com.cache.dataobject.Part.parts#1

1 Ответ

1 голос
/ 18 марта 2009

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

Исходя из этой ошибки, исправление может заключаться в использовании нового сеанса для вызовов добавления / обновления. Вы можете получить EntityManagerFactory вместо EntityManager и запрашивать новый Entity Manager для каждого вызова. Очевидно, что от того, насколько это уместно, зависит более широкий контекст вашего кода.

...