应该尝试 - 最后在这种情况下使用

时间:2015-10-16 09:02:47

标签: java exception stack try-catch

在DAO图层类中,假设我的代码如下:

private EntityManagerFactory factory;

public void update(T entity) {
    EntityManager entityManager = factory.createEntityManager();
    entityManager.getTransaction().begin();
    entityManager.merge(entity);
    entityManager.getTransaction().commit();
    entityManager.close();
}

现在在上面的代码块中,可能会在调用entityManager.close()之前(很少)发生RuntimeExceptions。所以,这样写它会很好:

public void update(T entity) {
    EntityManager entityManager = factory.createEntityManager();
    try {
        entityManager.getTransaction().begin();
        entityManager.merge(entity);
        entityManager.getTransaction().commit();
    }
     finally {
        entityManager.close();
    }
}

由于我方法中的所有对象都是本地的,因此一旦方法结束,它们就不会存在。那么,当方法内发生异常时,该方法的堆栈会发生什么?

我认为如果在异常的情况下堆栈存在,那么我确实需要finally块来关闭entityManager。实际发生了什么?

4 个答案:

答案 0 :(得分:4)

  

由于我方法中的所有对象都是本地的,因此一旦方法结束,它们就不会存在。

不,对象的引用是本地的,并且在方法范围完成时被删除,对象本身驻留在堆上,最终可能被垃圾回收。为了安全起见,我将在finally语句中添加对close()的调用。

看一下Hibernate 4.2.15的EntityManager.close()实现(我们不能使用Hibernate 4.3+但我猜它看起来很相似), close被传递给会话,事务协调器和 - 如果启用 - 统计信息收集器。所有这些类都将自己进行一些清理,无论是清除第一级缓存,关闭数据库连接,收集会话统计信息等。

答案 1 :(得分:3)

  

由于我方法中的所有对象都是本地的,因此它们不会存在一次   方法结束了。

在Java中,对象一直存在,直到垃圾收集器销毁它们。在声明对象的引用的范围的最终确定时,这不是必要的(通常,您无法预测对象何时将被垃圾收集)。因此,您应该关闭EntityManager。

无论如何,try with resources可能是个更好的主意。

  

try-with-resources语句是一个声明一个的try语句   或更多资源。资源是必须在之后关闭的对象   程序结束了。

答案 2 :(得分:1)

  

RuntimeExceptions可能会在(很少)之前发生   entityManager.close()被调用

如果您可以采取任何措施来处理您期望的RuntimeException,那么您甚至可以捕获并处理它们。如果你不能在那种情况下最终将是安全选项,以便关闭资源。如果它(EntityManager)实现Closeable接口,您还可以考虑自动调用关闭的try-with-resource语句。

答案 3 :(得分:0)

令我困惑的是,我发现的所有例子都没有使用finally子句。甚至在Hibernate或JPA的官方文档中。

在我看来,正确的代码应该始终使用finally子句。我没有正确地将实体映射到数据库表,并且在不使用finally子句时挂起了(Java SE)应用程序。

EntityManagerFactoryEntityManager都不能像某些人所建议的那样使用try-with-resources;它们不是AutoCloseable

修改我找到了一个doing it correctly的示例。 Heureka。

package com.zetcode;

import com.zetcode.model.City;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;

public class Application {

    private static final String PERSISTENCE_UNIT_NAME = "my-pu";

    public static void main(String[] args) {

        EntityManagerFactory emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
        EntityManager entityManager = emf.createEntityManager();

        try {

            entityManager.getTransaction().begin();

            Query query = entityManager.createQuery("SELECT c FROM City c");
            List<City> countries = query.getResultList();

            countries.stream().forEach((x) -> System.out.println(x));

            entityManager.getTransaction().commit();

        } finally {

            entityManager.close();
            emf.close();
        }
    }
}