简体   繁体   English

Hibernate与MySQL建立了一堆连接

[英]Hibernate opening a bunch of connections with MySQL

I've got another weird Hibernate issue. 我还有另一个奇怪的休眠问题。 I've googled and searched on SO for an answer, but couldn't find anything that I understood. 我已经在Google上搜索并搜索了答案,但是找不到我能理解的任何东西。

When one person navigates to our home page, it opens anywhere from 1 to 59 connections/sessions. 当一个人导航到我们的主页时,它将打开1到59个连接/会话。 It is never consistent. 这永远是不一致的。 They usually don't close, but sometimes do. 它们通常不关闭,但有时会关闭。 It's not noticeably consistent in that respect either. 在这方面也没有明显的一致性。 My attempt to use getStatistics returns nothing but zeroes. 我尝试使用getStatistics返回零。

DAO.java 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 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>

You have a couple of issues here. 您在这里有几个问题。 The main issue and I think what is causing you session leaks is that in doesUserExist and doesFamilyExist you are getting NullPointerException quite often and never closing session. 我认为主要的问题是导致会话泄漏的原因是,在dosUserExist和dosFamilyExist中,您经常会收到NullPointerException且从不关闭会话。 Here the rest of issues: 这里剩下的问题:

1) Your DAO uses Transactional annotation but all of methods are static. 1)您的DAO使用事务注释,但是所有方法都是静态的。 Either remove the annotation or make methods instance scope and inject session factory to the DAO. 删除注释或使方法实例作用域并将会话工厂注入DAO。 The best practice is to rely on transactional annotation and let container like Spring or EJB3 to handle transaction begin/commit calls. 最佳实践是依靠事务注释,并让诸如Spring或EJB3之类的容器来处理事务开始/提交调用。

2) You are not closing sessions properly, you need to wrap them in try/finally blocks and close the session in finally block. 2)您没有正确关闭会话,需要将它们包装在try / finally块中,并在finally块中关闭会话。 The best practice again is to rely on Spring or EJB3 to handle session management. 最佳实践再次是依靠Spring或EJB3来处理会话管理。

3) Never ever catch NullPointerException. 3)从不捕获NullPointerException。 Always check if object is null and add appropriate logic there. 始终检查object是否为null并在其中添加适当的逻辑。

Update: 更新:

Here is modified version of some of your DAO methods. 这是您的某些DAO方法的修改版本。 This will be the easiest fix for you but I suggest to improve your DAO at some point with proper Spring, Hibernate and JPA integration: 对于您来说,这将是最简单的修复程序,但我建议通过适当的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;
    }

Here is what has changed: 这是发生了什么变化:

1) Session is defined outside of try block and is closed in finally block. 1)会话在try块之外定义,并在finally块中关闭。 Make sure to always check if session has actually been initialized before closing it. 确保在关闭会话之前始终检查会话是否已实际初始化。 Otherwise in case sessionFactory.openSession() throwing exception or returning null you will get NPE in your finally block. 否则,如果sessionFactory.openSession()抛出异常或返回null,您将在您的finally块中获得NPE。

2) Transaction, just like session is defined outside of try block, initialized inside try and is committed inside try block. 2)事务,就像会话在try块外定义,在try内初始化并在try块内提交一样。 But we still need to handle the case that if any code before commit throws exception we wont keep the transaction open and that's why we need to roll it back inside catch block. 但是我们仍然需要处理以下情况:如果在提交之前有任何代码引发异常,我们将不会保持事务打开,这就是为什么我们需要将其回滚到catch块中。 Again transaction can be null in catch block due to session creation throwing exception. 同样,由于会话创建抛出异常,事务在catch块中可以为null。

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

Tsolakp has great advice, and it resolved a lot of the loose connection leaks I was having. Tsolakp提供了很好的建议,它解决了我遇到的许多松动的连接泄漏问题。 However, this was not the actual answer. 但是,这不是实际的答案。

If your project is on AWS, you should also totally make sure that your WAR archive containing your database username and password weren't pushed to Git or elsewhere. 如果您的项目在AWS上,则还应完全确保包含数据库用户名和密码的WAR存档未推送到Git或其他地方。 This usually results in your connections getting attacked by a pretty aggressive source. 这通常会导致您的连接受到相当积极的攻击。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM