java – How to avoid LazyExceptions?

Question:

My application faces numerous problems with LazyExceptions and what causes "dirt" in the server log. I understand that they occur because the database connection has already been closed and I am trying to retrieve some attribute/object that has not been initialized.

The most recent issue I had was getting a LazyException in the filter because the ProductValue retailers were not initialized. These only occur in a specific flow of the system.

Service

List<ProdutoValorETO> valores = mgrProdutoValorEDAO.findByProdutoId(produto.getId());
Optional<ProdutoValorETO> optionalProdValor = valores.stream()
                        .filter(v -> v.getLojista().getId().equals(lojista.getId()))
                        .findFirst();

DAO

public List<ProdutoValorETO> findByProdutoId(Long id) {
        if (id != null) {
            String query =
                    " SELECT * " +
                            " FROM produtovalor " +
                            " WHERE idproduto = " + id + " AND ativo = TRUE; ";
            SQLQuery eQuery = getCurrentSession().createSQLQuery(query).addEntity(ProdutoValorETO.class);
            List<ProdutoValorETO> lista = CastUtils.castList(eQuery.list(), ProdutoValorETO.class);
        }
        return new ArrayList<>();
    }

I solved it as follows, but it looks more like a workaround:

public List<ProdutoValorETO> findByProdutoId(Long id) {
        if (id != null) {
            String query =
                    " SELECT * " +
                            " FROM produtovalor " +
                            " WHERE idproduto = " + id + " AND ativo = TRUE; ";
            SQLQuery eQuery = getCurrentSession().createSQLQuery(query).addEntity(ProdutoValorETO.class);
            List<ProdutoValorETO> lista = CastUtils.castList(eQuery.list(), ProdutoValorETO.class);
            for (ProdutoValorETO item : lista) {
                Hibernate.initialize(item);
            }
        }
        return new ArrayList<>();
    }

Settings

<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
    <property name="poolName" value="springHikariCP" />
    <property name="dataSourceClassName" value="org.postgresql.ds.PGSimpleDataSource" />
    <property name="leakDetectionThreshold" value="30000"/>
    <property name="connectionTimeout" value="30000" />
    <property name="idleTimeout" value="600000"/>
    <property name="maxLifetime" value="1800000"/>
    <property name="maximumPoolSize" value="5"/>
    <property name="registerMbeans" value="true"/>
    <!-- <property name="jdbcUrl" value="${jdbc.url}"/> -->
    <property name="connectionTestQuery" value="select 1"/>

    <property name="dataSourceProperties">
        <props>
            <prop key="url">${jdbc.url}</prop>
            <prop key="user">${jdbc.username}</prop>
            <prop key="password">${jdbc.password}</prop>
        </props>
    </property>
</bean>

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="packagesToScan" value="br.com.example.*.to"/>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">${hibernate.dialect}</prop>
            <prop key="hibernate.hbm2ddl.auto">update</prop>
            <prop key="hibernate.show_sql">false</prop>
            <prop key="hibernate.cache.use_query_cache">true</prop>
            <prop key="hibernate.cache.use_second_level_cache">true</prop>
            <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
        </props>
    </property>
</bean>

Product Value ETO

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "idProduto")
    private ProdutoETO produto;

ETO Product

    @OneToMany(mappedBy = "produto", targetEntity = ProdutoValorETO.class, cascade = {CascadeType.ALL}, fetch = FetchType.LAZY)
    @Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.DELETE_ORPHAN})
    private List<ProdutoValorETO> valores;
  1. When we perform a very large flow in the system, is it more likely that a Lazy will occur? I got the list of values ​​one line above when I try to access the items and I already got the exception.
  2. Is there any mechanism in Spring JPA or newer versions of Hibernate to better handle this? (This application uses Spring 3 Hibernate 3.2)
  3. Is there any implication that Lazy occurs when writing the select directly instead of using Hibernate criteria?
  4. Are there better ways to solve this case (other than Eager)?

Answer:

When we perform a very large flow in the system, is it more likely that a Lazy will occur? I got the list of values ​​one line above when I try to access the items and I already got the exception.

Yes, if you are using entities outside of the transaction.

I believe that you can organize your code in a way that entities are not used outside of a transaction, avoiding the error. You can achieve this by mapping the information to other classes (DTOs) which, then, are outside the transaction, being used to fill screens, reports, etc.

Every application I've seen had a lot of LazyException problems because the entities were used outside of the transaction. In fact, this is a practice to be avoided for different reasons that go beyond the LazyException .

Is there any mechanism in Spring JPA or newer versions of Hibernate to better handle this? (This application uses Spring 3 Hibernate 3.2)

There are resources to help you already have information without depending on the open transaction: EAGER (used in the relationship, but I don't recommend it ) and FETCH (used in the query).

Is there any implication that Lazy occurs when writing the select directly instead of using Hibernate criteria?

Not that I know of. Equivalent queries in JPQL and Criteria should generate the same SQL.

Are there better ways to solve this case (other than Eager)?

Yes, using FETCH :

SELECT pv
FROM produtovalor pv
JOIN FETCH pv.lojista 
WHERE pv.idproduto = :id AND pv.ativo = TRUE;
Scroll to Top