Java 连接太多错误:休眠

Java 连接太多错误:休眠,java,database,hibernate,servlets,connection-pooling,Java,Database,Hibernate,Servlets,Connection Pooling,我在我的web应用程序中使用Hibernate,它是用纯Servlet和JSP开发的。我在执行代码时“有时”会遇到大麻烦。发生的情况是,我从Hibernate获得了太多的连接 为了寻找答案,我经历了很多问题,我找到了不同的解决方案。一些人建议使用第三方池系统,一些人建议线程安全,一些人建议使用一个SessionFactory等,因此我不确定哪一个适用于我的系统 下面是我的数据库层的一部分 package dao; import java.util.List; import model.main

我在我的web应用程序中使用Hibernate,它是用纯Servlet和JSP开发的。我在执行代码时“有时”会遇到大麻烦。发生的情况是,我从Hibernate获得了太多的连接

为了寻找答案,我经历了很多问题,我找到了不同的解决方案。一些人建议使用第三方池系统,一些人建议线程安全,一些人建议使用一个
SessionFactory
等,因此我不确定哪一个适用于我的系统

下面是我的数据库层的一部分

package dao;

import java.util.List;
import model.main.Familyvisa;
import model.main.Familyvisa;
import model.main.Familyvisa;
import model.main.Pensionhistory;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;

/**
 *
 * @author user
 */
public class FamilyVisaImpl implements FamilyVisaInterface
{
    private Session currentSession; 
    private Transaction currentTransaction;

        public Session openCurrentSession() {
        currentSession = getSessionFactory().openSession();
        return currentSession;
    }

    public Session openCurrentSessionwithTransaction() {
        currentSession = getSessionFactory().openSession();
        currentTransaction = currentSession.beginTransaction();
        return currentSession;
    }

    public void closeCurrentSession() {
        currentSession.close();
    }

    public void closeCurrentSessionwithTransaction() {
        currentTransaction.commit();
        currentSession.close();
    }

    private static SessionFactory getSessionFactory() {

            Configuration configuration = new Configuration().configure();
            StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder()
                            .applySettings(configuration.getProperties());
            SessionFactory sessionFactory = configuration.buildSessionFactory(builder.build());
            return sessionFactory;
    }

       public Session getCurrentSession() {
        return currentSession;
    }

    public void setCurrentSession(Session currentSession) {
        this.currentSession = currentSession;
    }

    public Transaction getCurrentTransaction() {
        return currentTransaction;
    }

    public void setCurrentTransaction(Transaction currentTransaction) {
        this.currentTransaction = currentTransaction;
    }

         @Override
    public void save(Familyvisa entity) {
        getCurrentSession().save(entity);
    }

    @Override
    public void update(Familyvisa entity) {
        getCurrentSession().update(entity);
    }

    @Override
    public Familyvisa findById(int id) {
        Familyvisa book = (Familyvisa) getCurrentSession().get(Familyvisa.class, id);
        return book; 
    }

     @Override
    public void delete(Familyvisa entity) {
        getCurrentSession().delete(entity);
    }   

    @Override
        public List<Familyvisa> findAll() {
        List<Familyvisa> remDur = (List<Familyvisa>) getCurrentSession().createQuery("from Familyvisa").list();
        return remDur;
    }




     public Familyvisa findByForiegnKey_Family(int idFamily) 
    {
        String hql = "FROM  Familyvisa WHERE idFamily = :famId";
        //String hql = "FROM  Visa WHERE idFamily = :famId";
        Query q = getCurrentSession().createQuery(hql);
        q.setParameter("famId", idFamily);

        Familyvisa v = new Familyvisa();

        if(!q.list().isEmpty())
        {
            v = (Familyvisa)q.list().get(0);
        }

        return v;
    }


    @Override
    public void saveOrUpdate(Familyvisa p) 
    {
        getCurrentSession().saveOrUpdate(p);
    }

    @Override
    public List<Object[]> findReminderActiveVisaWithFamilyAndEmployee() 
    {
        String sql = "";

        SQLQuery createSQLQuery = getCurrentSession().createSQLQuery(sql);
        return createSQLQuery.list();
    }

    @Override
    public void batchUpdate(List<Familyvisa> list)
    {
        for(int i=0;i<list.size();i++)
        {
            getCurrentSession().update(list.get(i));
        }
    }
}

您的代码在很多方面都是错误的:

  • 正如您已经承认的,代码不是线程安全的:

    private Session currentSession; 
    private Transaction currentTransaction;
    
    public Session openCurrentSession() {
        currentSession = getSessionFactory().openSession();
        return currentSession;
    }
    
    public Session openCurrentSessionwithTransaction() {
        currentSession = getSessionFactory().openSession();
        currentTransaction = currentSession.beginTransaction();
        return currentSession;
    }
    
    public void closeCurrentSession() {
        currentSession.close();
    }
    
    public void closeCurrentSessionwithTransaction() {
        currentTransaction.commit();
        currentSession.close();
    }
    
    服务层单例不应该存储状态,因为它们是由并发请求访问的。如果您有一个当前正在运行的会话,并且第二个请求也打开了一个新会话,该怎么办?第一个线程永远不会有机会关闭其会话,但它将尝试关闭上次打开的会话(例如currentSession)

  • 会话
    甚至不是线程安全的,因此您会遇到各种奇怪的并发修改或更改可见性错误

  • 您应该遵循Hibernate会话管理最佳实践,并选择由ThreadLocal会话存储支持的解决方案

  • 添加是处理连接/会话/事务管理的一种简单而有效的方法

  • 您的代码片段:

    for(int i=0;i<reminderSentList.size();i++)
       {
          Familyvisa familyVisa = service.findByForiegnKey_Family(reminderSentList.get(i).getIdFamily());
          familyVisa.setNumberOfReminders(familyVisa.getNumberOfReminders()+1);
          familyVisa.setLastReminderSent(Common.getCurrentDateSQL());
          visa.add(familyVisa);
       }
    

    上面的例子是线程安全的。因为您在单个函数中打开、操作和关闭会话


    Hibernate需要事务块,即使对于读取操作也是如此。因此,您必须像这样修复代码:

    Session session = ...
    try {
    session.beginTransaction();
    ...
    Your Loop
    ...
    session.getTransaction.commit();
    ...
    

    1.它不是线程安全的,因为
    类级别
    变量?但是它不是在
    Servlet
    中,而是在另一个类中?2.我没抓住要点。3.好像“关闭
    内的会话最终阻止
    ?4.我想我们太晚了。最后,如何创建
    SessionFactory
    ?看起来,它每次都在
    updateDatabase
    1的循环中打开新实例。多个请求可以调用
    openCurrentSession
    ,因此设置
    会话
    ,并且每个会话都应该绑定到调用线程。在您的例子中,
    会话
    保存最后打开的会话,而且这甚至不是线程安全的。3.即使您在finally块上调用close,您确定要关闭您首先打开的
    会话吗?
    1。多个请求可以调用openCurrentSession并因此设置会话,并且每个会话都应该绑定到调用线程
    -我如何才能做到这一点?。。请检查
    SessionFactory
    ,我正在一个方法中定义它。
    FamilyVisaService
    是单例的,它有一个
    familyvisimpl
    实例。多个请求调用
    FamilyVisaService
    方法,因此同时调用
    openCurrentSession()。因此,每次新的
    openCurrentSession()
    调用都会覆盖
    session
    变量。有意义吗?
    FamilyVisaService
    不是单身。我试着做一个,但后来我停了下来。这不是单例。很有趣,但似乎我必须做很多更改?@JustCause,实际上您只需将打开和关闭会话的操作移到
    .findbyforeignkey_Family()
    函数和循环之外即可拒绝非事务性操作。这就是安拉,所以你的整个代码都在一个函数中。好的,我认为
    会话
    是一个全局变量,因为您没有声明函数。我添加了一个更新,另一个有一些更改的小代码,我根据答案进行了更改。请看一看,让我知道是否有任何问题或是否可以。您忘记了事务块。最好添加它以防止意外结果。其余的都可以,应该可以。
    private Session currentSession; 
    private Transaction currentTransaction;
    
    public Session openCurrentSession() {
        currentSession = getSessionFactory().openSession();
        return currentSession;
    }
    
    public Session openCurrentSessionwithTransaction() {
        currentSession = getSessionFactory().openSession();
        currentTransaction = currentSession.beginTransaction();
        return currentSession;
    }
    
    public void closeCurrentSession() {
        currentSession.close();
    }
    
    public void closeCurrentSessionwithTransaction() {
        currentTransaction.commit();
        currentSession.close();
    }
    
    for(int i=0;i<reminderSentList.size();i++)
       {
          Familyvisa familyVisa = service.findByForiegnKey_Family(reminderSentList.get(i).getIdFamily());
          familyVisa.setNumberOfReminders(familyVisa.getNumberOfReminders()+1);
          familyVisa.setLastReminderSent(Common.getCurrentDateSQL());
          visa.add(familyVisa);
       }
    
    Session session = ...
    try {
    
      for(int i=0;i<reminderSentList.size();i++)
        {
            /* findByForiegnKey_Family() has Session argument now! */
            Familyvisa familyVisa = service.findByForiegnKey_Family(session, reminderSentList.get(i).getIdFamily());
            familyVisa.setNumberOfReminders(familyVisa.getNumberOfReminders()+1);
            familyVisa.setLastReminderSent(Common.getCurrentDateSQL());
            visa.add(familyVisa);
        } 
      } catch (Exception ex) {
          System.out.println("ERROR:"+ex);
      } finally {
          session.close();
      }
    
    Session session = ...
    try {
    session.beginTransaction();
    ...
    Your Loop
    ...
    session.getTransaction.commit();
    ...