2015-03-16 3 views
0

У меня есть наследие базы данных со следующими таблицами:Случайные LazyInitializationException с @OneToMany

Police 
id (PK) 
data... 

Contract 
id(PK) 
version(PK) 
type 


Code 
tab(PK) 
code(PK) 
name 

У меня есть JPA Entity полиции

@Entity 
public class Police implements Serializable { 


@Id 
private long id 

@OneToMany(fetch = FetchType.LAZY) 
@JoinColumns(value = { @JoinColumn(name = "id", referencedColumnName = "id") }) 
private Set<Contract> contracts; 

} 

контракт лицо выглядит следующим образом:

@Entity 
public class Contract implements Serializable { 


@Id 
private long id; 

@Id 
private long version; 


private String type; 



@OneToMany(fetch = FetchType.LAZY) 
@JoinColumns({ @JoinColumn(name = "code", referencedColumnName = "type") }) 
@Where(clause = "tab = 'Type'") 
private Set<Code> type; 
} 

Код:

@Entity 
public class Code implements Serializable { 


    @Id 
    private String tab; 
    @Id 
    private String code; 

    private String name; 
} 

В таблице кодов есть много разных ключей/значений для разных приложений. В моем случае мне нужен тот, где «tab =« Тип »и code = type из моего Контракта.

Моя проблема в том, что если у меня есть более одного контракта для моей полиции, я СЛУЧАЙНО? получить org.hibernate.LazyInitializationException.

В моей TestCase, я следующее:

public static void main(String[] args) { 

    int countErrors = 0; 

    for (int i = 0; i < 15; i++) { 
     try { 
      readPolice(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
      countErrors++; 
     } 
    } 

    System.err.println("errors: " + countErrors); 

} 

private static void readPolice() throws Exception { 
    EntityManagerFactory factory =  EntityManagerFactoryHelper.getFactory(PersistenceUnitsEnum.TEST_STAGE); 
    EntityManager em = factory.createEntityManager(); 
    TypedQuery<Police> namedQuery = em.createNamedQuery(...); 
    Police result = namedQuery.getSingleResult(); 
    Set<Contract> contracts = result.getContract(); 
    Contract contract = contracts.iterator().next(); 
    Set<Code> type = contract.getType(); //should be a set with one Entry 

    System.out.println(type.size()); //<--- Chance for Exception!! 
    em.close(); 
} 

Стараюсь все это дело в петле 15 раз. Примерно в 5-8 попыток я получаю исключение LazyInitializationException. В других случаях это работает.

Любые мысли об этом? Почему он не терпит неудачу?

+0

Можете ли вы показать свою сущность «Code»? –

+0

@bigdestroyer: добавил объект кода – griFlo

+0

Я думаю, вам может понадобиться аннотация 'IdClass' на' Code', если вы хотите, чтобы у него был сформированный составной первичный ключ. Вот пример: http://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequision#Id_Class –

ответ

0

Если я переопределяю equals/hashcode в объекте Contract, он работает. Почему проблема возникла случайно ... Я не понимаю ...

0

Убедитесь, что код с println находится в транзакции.

LazyInitializationException означает, что вы загрузили объект в какой-либо транзакции, вышли из него, а затем попытались использовать какое-то ленивое свойство этого объекта.

+0

Я думаю, что все это в одной транзакции. Я делаю все это в одном «блоке», – griFlo

+0

, и если бы это была не та же транзакция, не должна ли она терпеть неудачу каждый раз? – griFlo

+0

вы можете опубликовать весь код класса, содержащего этот System.out.println (...)? –

0

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

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

+0

Именованный запрос возвращает тот же объект (есть только один с моими тестовыми параметрами) – griFlo

0

Вы должны убедиться, что создание EntityManagerFactory выполняется только один раз. Например:

public static void main(String[] args) { 
    EntityManagerFactory emf = EntityManagerFactoryHelper.getFactory(PersistenceUnitsEnum.TEST_STAGE); 
    for (int i = 0; i < 15; i++) { 
    readPolice(emf); 
    } 
} 

private static void readPolice(EntityManagerFactory emf) throws Exception { 
    EntityManager em = emf.createEntityManager(); 
    ... 
} 

Если вы используете какое-то одноплодный шаблон в EntityManagerFactoryHelper.getFactory(), убедитесь, что поточно.

Вы также можете попробовать обернуть readPolice() внутри транзакции по телефону em.getTransaction().begin() и em.getTransaction().commit(). Например:

private static void readPolice(EntityManagerFactory emf) throws Exception { 
    EntityManager em = emf.createEntityManager(); 
    em.getTransaction().begin(); 
    ... 
    em.getTransaction().commit(); 
    em.close(); 
} 
+0

Ваш anser сделал мне еще один шаг (я думаю). Если я выполню создание entitymanger только один раз (за каждый тестовый вызов), он работает каждый раз (или он не работает каждый раз) ... так что я думаю, что это зависит от entityManager, если он работает - или нет. Но что может вызвать это? – griFlo

1

Только что столкнулся с этим. Ключевое слово - «случайное». Один из моих коллег постоянно встречал это исключение на своем ноутбуке, пока я никогда не сталкивался с этим. Она могла воспроизвести исключение только на IE & Edge.

Наконец-то понял, что это связано с версиями Tomcat. У нее была более старая версия, а у меня была более поздняя версия - 8.5.8. Она обновила локальный Tomcat до этой версии, и исключение больше не встречается.

Смежные вопросы