【问题标题】:Hibernate opening a bunch of connections with MySQLHibernate 打开一堆与 MySQL 的连接
【发布时间】:2017-05-31 00:13:01
【问题描述】:

我遇到了另一个奇怪的 Hibernate 问题。我已经在 SO 上搜索并搜索了答案,但找不到任何我理解的内容。

当一个人导航到我们的主页时,它会打开 1 到 59 个连接/会话。它从来都不是一致的。它们通常不会关闭,但有时会关闭。在这方面也没有明显的一致性。我尝试使用 getStatistics 只返回零。

DAO.java

package com.grandcircus.spring.util;

import com.grandcircus.spring.controller.HomeController;
import com.grandcircus.spring.models.FamiliesEntity;
import com.grandcircus.spring.models.UsersEntity;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.Restrictions;
import org.hibernate.stat.Statistics;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;

/**
 * Class description
 *
 * @author Sarah Guarino
 * @version 1.0
 */

@Repository
@Transactional
public class DAO {
    private static Configuration configurationObject = new Configuration().configure("hibernate.cfg.xml");
    private static SessionFactory sessionFactory = configurationObject.buildSessionFactory();

    public static FamiliesEntity newFamily(String famName) {
        Session browsingSession = sessionFactory.openSession();
        Transaction databaseTransaction = browsingSession.beginTransaction();

        FamiliesEntity newFamily = new FamiliesEntity();
        newFamily.setName(famName);

        browsingSession.save(newFamily);
        databaseTransaction.commit();
        browsingSession.close();

        return newFamily;
    }

    public static void newUser(String fName, String lName,
                               String email, String password,
                               int usergroup, int familyid) {
        Session browsingSession = sessionFactory.openSession();
        Transaction databaseTransaction = browsingSession.beginTransaction();
        UsersEntity user = new UsersEntity();

        user.setFname(fName);
        user.setLname(lName);
        user.setEmail(email);
        user.setUsergroup(usergroup);
        user.setPassword(password);
        user.setFamilyid(familyid);

        browsingSession.save(user);
        databaseTransaction.commit();
        browsingSession.close();
    }

    public static void updateUserCoordinates(String checkinLat,
                                             String checkinLong,
                                             String userId) {
        Session browsingSession = sessionFactory.openSession();
        Transaction myTransaction = browsingSession.beginTransaction();

        Criteria criteria = browsingSession.createCriteria(UsersEntity.class);
        UsersEntity personCheckingIn = (UsersEntity) criteria
                .add(Restrictions.eq("userid", Integer.parseInt(userId)))
                .uniqueResult();

        personCheckingIn.setLastlat(checkinLat);
        personCheckingIn.setLastlong(checkinLong);
        personCheckingIn.setLasttime(HomeController.getCurrentTime());

        browsingSession.save(personCheckingIn);
        myTransaction.commit();
        browsingSession.close();
    }

    public static boolean doesUserExist(String email) {
        // this will pass if the email exists, or fail if the user does not exist.
        boolean doesThisExist = true;
        Session browsingSession = sessionFactory.openSession();
        Criteria usersCriteria = browsingSession.createCriteria(UsersEntity.class);

        try {
            UsersEntity newUser = (UsersEntity) usersCriteria
                    .add(Restrictions.eq("email", email))
                    .uniqueResult();
            if(newUser.getEmail() == null) {
                doesThisExist = false;
            }
        } catch (Exception e) {
            doesThisExist = false;
        } finally {
            browsingSession.close();
        }

        return doesThisExist;
    }

    public static boolean doesFamilyExist(int famId) {
        boolean doesThisExist = true;
        Session browsingSession = sessionFactory.openSession();
        Criteria familyCriteria = browsingSession.createCriteria(FamiliesEntity.class);

        try {
            FamiliesEntity family = (FamiliesEntity) familyCriteria
                    .add(Restrictions.eq("familyid", famId))
                    .uniqueResult();
            if(family.getFamilyid() == 0) {
               doesThisExist = false;
            }
        } catch (NullPointerException e) {
            doesThisExist = false;
        } finally {
            browsingSession.close();
        }

        return doesThisExist;
    }

    public static UsersEntity getUserByEmail(String email) {
        Session browsingSession = sessionFactory.openSession();
        Criteria userCriteria = browsingSession.createCriteria(UsersEntity.class);

        UsersEntity user = (UsersEntity) userCriteria
                .add(Restrictions.eq("email", email))
                .uniqueResult();

        browsingSession.close();

        return user;
    }

    public static UsersEntity loadThisAccount(String userId) {
        Session browsingSession = sessionFactory.openSession();
        Criteria userCriteria = browsingSession.createCriteria(UsersEntity.class);

        UsersEntity user = (UsersEntity) userCriteria
                .add(Restrictions.eq("userid",
                        Integer.parseInt(userId)))
                .uniqueResult();

        browsingSession.close();

        return user;
    }

    public static ArrayList<UsersEntity> loadChildAccounts(int familyId) {
        Session browsingSession = sessionFactory.openSession();

        Criteria childCriteria = browsingSession.createCriteria(UsersEntity.class);

        ArrayList<UsersEntity> children = (ArrayList<UsersEntity>) childCriteria
                .add(Restrictions.eq("familyid", familyId))
                .add(Restrictions.eq("usergroup", 1))
                .list();

        browsingSession.close();

        return children;
    }

    public static FamiliesEntity loadFamily(int familyId) {
        Session browsingSession = sessionFactory.openSession();
        Criteria familyCriteria = browsingSession.createCriteria(FamiliesEntity.class);

        FamiliesEntity family = (FamiliesEntity) familyCriteria
                .add(Restrictions.eq("familyid", familyId))
                .uniqueResult();

        browsingSession.close();

        return family;
    }

    public static UsersEntity loadParentAccount(int familyId) {
        Session browsingSession = sessionFactory.openSession();
        Criteria adminCriteria = browsingSession.createCriteria(UsersEntity.class);
        UsersEntity parent = (UsersEntity) adminCriteria
                .add(Restrictions.eq("familyid", familyId))
                .add(Restrictions.eq("usergroup", 0))
                .uniqueResult();

        browsingSession.close();

        return parent;
    }
}

Hibernate.cfg.xml

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="connection.url">jdbc:mysql://localhost:3306/checkin</property>
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="show_sql">true</property>

        <property name="hibernate.connection.username">*****</property>
        <property name="hibernate.connection.password">*****</property>

        <property name="hibernate.c3p0.min_size">5</property>
        <property name="hibernate.c3p0.max_size">20</property>
        <property name="hibernate.c3p0.timeout">300</property>
        <property name="hibernate.c3p0.max_statements">50</property>
        <property name="hibernate.c3p0.idle_test_period">3000</property>

        <mapping class="com.grandcircus.spring.models.FamiliesEntity"/>
        <mapping class="com.grandcircus.spring.models.LocationsEntity"/>
        <mapping class="com.grandcircus.spring.models.UsersEntity"/>

        <mapping resource="FamiliesEntity.hbm.xml"/>
        <mapping resource="LocationsEntity.hbm.xml"/>
        <mapping resource="UsersEntity.hbm.xml"/>
    </session-factory>
</hibernate-configuration>

【问题讨论】:

  • 假设您共享数据库连接层类。您是使用 JPA 还是会话工厂来连接数据库。
  • @RajithPemabandu 我正在使用 sessionFactory,作为此类中的一个字段。你是说我的hibernate.cfg.xml吗?

标签: java mysql hibernate spring-mvc


【解决方案1】:

这里有几个问题。主要问题,我认为导致会话泄漏的原因是,在 dosUserExist 和 doFamilyExist 中,您经常收到 NullPointerException 并且永远不会关闭会话。剩下的问题在这里:

1) 你的 DAO 使用事务注解,但所有方法都是静态的。删除注释或将方法设为实例范围并将会话工厂注入 DAO。最佳实践是依赖事务注解,让 Spring 或 EJB3 等容器处理事务开始/提交调用。

2) 您没有正确关闭会话,您需要将它们包装在 try/finally 块中,并在 finally 块中关闭会话。最佳实践还是依靠 Spring 或 EJB3 来处理会话管理。

3) 永远不要捕获 NullPointerException。始终检查 object 是否为 null 并在那里添加适当的逻辑。

更新:

这里是您的一些 DAO 方法的修改版本。这对你来说是最简单的解决方法,但我建议在某个时候通过适当的 Spring、Hibernate 和 JPA 集成来改进你的 DAO:

    public static FamiliesEntity newFamily(String famName) {
        Session browsingSession = null;
        Transaction databaseTransaction = null;

        try{
            browsingSession = sessionFactory.openSession();
            databaseTransaction = browsingSession.beginTransaction();

            FamiliesEntity newFamily = new FamiliesEntity();
            newFamily.setName(famName);

            browsingSession.save(newFamily);
            databaseTransaction.commit();

            return newFamily;
        }catch(RuntimeException e){
            if (databaseTransaction != null){
                try{ databaseTransaction.rollback(); }
                catch(RuntimeException ex){throw ex;}
            }
            throw e;
        }finally{
            if (browsingSession != null){
                browsingSession.close();
            }
        }            
    }       

    public static boolean doesUserExist(String email) {
        Session browsingSession = null;

        try{
            browsingSession = sessionFactory.openSession();

            UsersEntity newUser = (UsersEntity) usersCriteria
            .add(Restrictions.eq("email", email))
            .uniqueResult();

            if(newUser.getEmail() == null) {
                return false;
            }else{
                return true;
            }                
        }finally{
            if (browsingSession != null){
                browsingSession.close();
            }
        }
    }

    public static UsersEntity getUserByEmail(String email) {
        Session browsingSession = null;

        try{
            browsingSession = sessionFactory.openSession();
            Criteria userCriteria = browsingSession.createCriteria(UsersEntity.class);

            UsersEntity user = (UsersEntity) userCriteria
                    .add(Restrictions.eq("email", email))
                    .uniqueResult();
        }finally{
            if (browsingSession != null){
                browsingSession.close();
            }
        }

        return user;
    }

以下是变化:

1) 会话在 try 块之外定义,并在 finally 块中关闭。确保在关闭会话之前始终检查会话是否已实际初始化。否则,如果 sessionFactory.openSession() 抛出异常或返回 null,您将在 finally 块中获得 NPE。

2) 事务,就像 session 是在 try 块之外定义的,在 try 内部初始化并在 try 块内部提交。但是我们仍然需要处理这样的情况,即如果提交之前的任何代码抛出异常,我们将不会保持事务打开,这就是为什么我们需要在 catch 块中回滚它。由于会话创建抛出异常,事务在 catch 块中再次可能为空。

【讨论】:

  • 我有几个问题: 1) 我需要我的 SessionFactory 才能将 Criteria 对象与 Hibernate 一起使用。同样,我的理解是我需要事务来提交到我的数据库。我如何在做这些事情的同时“让春天来处理它”? 2)试图实现这一点会导致我返回的项目出现很多范围问题。以我目前的知识,做出这些改变是不可能的或不切实际的。这是问题的严重根源吗? 3)我解决了这个问题。
【解决方案2】:

建议使用连接池 您不必自己打开它会话

【讨论】:

    【解决方案3】:

    Tsolakp 有很好的建议,它解决了我遇到的许多松散连接泄漏问题。然而,这并不是真正的答案。

    如果您的项目在 AWS 上,您还应该完全确保包含您的数据库用户名和密码的 WAR 存档没有被推送到 Git 或其他地方。这通常会导致您的连接受到非常激进的来源的攻击。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-08
      • 1970-01-01
      • 1970-01-01
      • 2011-03-13
      • 2014-07-11
      • 2018-09-30
      相关资源
      最近更新 更多