【问题标题】:Hibernate does not return connection if exectuted in another thread如果在另一个线程中执行,Hibernate 不会返回连接
【发布时间】:2023-03-08 15:07:01
【问题描述】:

我遇到了需要并行运行多个任务的问题。
为此,我正在使用期货。
其中一项任务是通过休眠对 postgres 数据库进行简单选择,问题是每次执行此任务时都会创建一个新的 postgres 连接,很快 postgres 将不再接受任何连接。
该应用程序在 tomcat 服务器上运行并使用连接池。
如果我不在不同的线程中执行任务,它工作正常。

这是使用hibernate的方法:

@Override
public Future<MonitoringResult> performMonitoringAction()  {

    return getExecutorService().submit(() -> {
        long milliseconds = System.currentTimeMillis();

        Session session = null;
        Transaction tx = null;
        try {
            session = HibernateUtil.getCurrentInstance().newSession();
            tx = session.beginTransaction();
            List<Entity> sle = (List<Entity>) session.createQuery("from Entity").list();

            return new MonitoringResult(System.currentTimeMillis() - milliseconds, true);
        } catch (Exception e) {
            return new ExceptionMonitoringResult(System.currentTimeMillis() - milliseconds, e);
        } finally {
            if (tx != null) {
                tx.commit();
        }
            if (session != null) {
                session.close();
            }
        }
    });
}

这就是它的调用方式:

public Response all() {

    List<Future<MonitoringResult>> runningMonitorTasks = new ArrayList<>(monitoredServices.length);

    // start all monitoring services
    for (MonitorableService monitoredService : monitoredServices) {
        runningMonitorTasks.add(monitoredService.performMonitoringAction());
    }

    HashMap<String, MonitoringResult> resultMap = new HashMap();

    // collect results of monitoring services
    for (int i = 0; i < monitoredServices.length; i++) {
        MonitorableService monitoredService = monitoredServices[i];
        Future<MonitoringResult> runningTask = runningMonitorTasks.get(i);

        MonitoringResult result;
        try {
            result = runningTask.get(60, TimeUnit.SECONDS); // wait till task is finished
        } catch (TimeoutException | InterruptedException | ExecutionException ex) {
            LOGGER.log(Level.SEVERE, "Monitoring task failed", ex);
            result = new ExceptionMonitoringResult(-1, ex);
        }

        logIfUnreachable(result, monitoredService);
        resultMap.put(monitoredService.getServiceName(), result);
    }

    return Response.ok(resultMap).build();
}

这样调用它工作正常:

public Response all() {

    HashMap<String, MonitoringResult> resultMap = new HashMap();

    // execute monitoring services
    for (MonitorableService monitoredService : monitoredServices) {
        Future<MonitoringResult> result = monitoredService.performMonitoringAction();
        MonitoringResult get;
        try {
            get = result.get();
            logIfUnreachable(get, monitoredService);

        } catch (InterruptedException | ExecutionException ex) {
            Logger.getLogger(RestMonitorService.class.getName()).log(Level.SEVERE, null, ex);
            get = new ExceptionMonitoringResult(-1, ex);
        }
        resultMap.put(monitoredService.getServiceName(), get);

    }

    return Response.ok(resultMap).build();
}

HibernateUtil 类:

public class HibernateUtil implements ServletContextListener {

    private static HibernateUtil currentInstance;
    private SessionFactory sessionFactory;
    private ServletContext servletContext;

    private final Log logger = LogFactory.getLog(LoginInfo.class);

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        // set current instance
        currentInstance = this;

        Configuration cfg = new Configuration().configure();
        StandardServiceRegistryBuilder builder = new    StandardServiceRegistryBuilder().applySettings(
                cfg.getProperties());
        sessionFactory = cfg.buildSessionFactory(builder.build());

        servletContext = sce.getServletContext();
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        // close session factory
        if(sessionFactory!=null){
            sessionFactory.close();
        }
        sessionFactory = null;

    }

    public static HibernateUtil getCurrentInstance() {
        return currentInstance;
    }

    public Session newSession() {
        return sessionFactory.openSession();
    }
}

【问题讨论】:

  • 嗨,你为什么不将你的连接的引用传递给你的线程,以便它保持相同而不是创建新的连接?
  • 我不明白为什么我应该通过。你的意思是应该使用 'sessionFactory.getCurrentSession()' 吗?
  • 是的,我会得到 HibernatueUtil.getSessionFactory().getCurrentSession();并将其作为参数传递给您的受监控服务构造函数。然后在每个线程中:打开连接,打开事务,做你的事情,提交和释放你的线程。
  • 我已经试过了,它的行为是一样的。
  • 在 HibernateUtil 中:currentInstance 字段是静态的,而 SessionFactory 不是。我不明白为什么......你有没有尝试重构它

标签: java multithreading hibernate connection-pooling


【解决方案1】:

还不能评论,可能值得检查HibernateUtil.getCurrentInstance() 的来源,看看它在做什么,它可能使用一些线程本地或创建一个新的连接池。通常当连接耗尽时,可能是由于创建新池而不是使用现有池来获取连接。

【讨论】:

  • 不知道你的配置是什么,所以可以看看这个帖子stackoverflow.com/questions/8046662/…
  • 你到底是什么意思。这篇文章对我来说就像newSession() 是正确的做法。我将hibernate.current_session_context_class 设置为thread
  • getExecutorService() 每次都创建一个新池吗?
  • 不,只是一个新的连接
  • 它只是一个由构造函数传递的变量的获取。
【解决方案2】:

答案是真实的答案是问题发生在与我预期不同的地方。但我也会分享我的解决方案。

另一项服务(不是我的问题)使用休眠。 我在 web 应用程序中的一个正常调用有一个监听器,它在关闭连接之前和之后打开连接。 但是由于服务现在在不同的线程上执行,连接被打开但从未关闭,因为没有调用监听器。

【讨论】:

    猜你喜欢
    • 2020-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-10
    • 2022-12-31
    • 1970-01-01
    • 2011-04-24
    • 2018-04-10
    相关资源
    最近更新 更多