【发布时间】: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