【发布时间】:2015-12-04 06:54:00
【问题描述】:
我正在使用 Hibernate JPA 创建一个应用程序,并使用 c3p0 与 MySQL 进行连接池。我对 MySQL 数据库的连接数有疑问,因为它达到了 152 个打开的连接,这是不想要的,因为我在我的 c3p0 配置文件中将最大池大小定义为 20,当然我关闭了我得到的每个实体管理器提交每个事务后来自EntityManagerFactory。
每次执行控制器时,我注意到打开了超过 7 个连接,如果我刷新,则再次打开 7 个连接,而不会关闭过去的空闲连接。在我调用的每个 DAO 函数中,都会执行 em.close()。我在这里承认问题出在我的代码中,但我不知道我在这里做错了什么。
这是 Sondage.java 实体:
@Entity
@NamedQuery(name="Sondage.findAll", query="SELECT s FROM Sondage s")
public class Sondage implements Serializable {
private static final long serialVersionUID = 1L;
public Sondage() {}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private byte needLocation;
//bi-directional many-to-one association to ResultatSondage
@OneToMany(mappedBy = "sondage", cascade = CascadeType.ALL)
@OrderBy("sondage ASC")
private List<ResultatSondage> resultatSondages;
//bi-directional many-to-one association to SondageSection
@OneToMany(mappedBy = "sondage", cascade = CascadeType.ALL)
private List<SondageSection> sondageSections;
}
这是我的 DAO 类:
@SuppressWarnings("unchecked")
public static List<Sondage> GetAllSondage() {
EntityManager em = PersistenceManager.getEntityManager();
List<Sondage> allSondages = new ArrayList<>();
try {
em.getTransaction().begin();
Query query = em.createQuery("SELECT s FROM Sondage s");
allSondages = query.getResultList();
em.getTransaction().commit();
} catch (Exception ex) {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
allSondages = null;
} finally {
em.close();
}
return allSondages;
}
如您所见,em 已关闭。在我的 JSP 中,我这样做:我知道这不是在视图方面做事的好方法。
<body>
<div class="header">
<%@include file="../../../Includes/header.jsp" %>
</div>
<h2 style="color: green; text-align: center;">الاستمارات</h2>
<div id="allsurveys" class="pure-menu custom-restricted-width">
<%
List<Sondage> allSondages = (List<Sondage>) request.getAttribute("sondages");
for (int i = 0; i < allSondages.size(); i++) {
%>
<a href="${pageContext.request.contextPath }/auth/dosurvey?id=<%= allSondages.get(i).getId()%>"><%= allSondages.get(i).getName()%></a>
<%
if (request.getSession().getAttribute("user") != null) {
Utilisateur user = (Utilisateur) request.getSession().getAttribute("user");
if (user.getType().equals("admin")) {
%>
<a href="${pageContext.request.contextPath }/aauth/editsurvey?id=<%= allSondages.get(i).getId()%>">تعديل</a>
<%
}
}
%>
<br />
<%
}
%>
</div>
</body>
我猜每次我打电话给user.getType(),都会建立一个请求?如果是这样,我该如何防止这种情况发生?
对于 c4p0 配置文件,我将其包含在 persistence.xml 中,我看到一些帖子说我需要将 c3p0 配置文件放在 c3p0-config.xml 中,但是通过我的设置,c3p0 使用我传递的值初始化在 persistence.xml 文件中,mysql 连接数也达到 152 个,但 maxpoolsize 为 20,这是 persistence.xml 文件
<persistence version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="CAOE" transaction-type="RESOURCE_LOCAL">
<class>com.caoe.Models.ChoixQuestion</class>
<class>com.caoe.Models.Question</class>
<class>com.caoe.Models.Reponse</class>
<class>com.caoe.Models.ResultatSondage</class>
<class>com.caoe.Models.Section</class>
<class>com.caoe.Models.Sondage</class>
<class>com.caoe.Models.SondageSection</class>
<class>com.caoe.Models.SousQuestion</class>
<class>com.caoe.Models.Utilisateur</class>
<properties>
<property name="hibernate.connection.provider_class"
value=" org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider" />
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.connection.password" value=""/>
<property name="hibernate.connection.url"
value="jdbc:mysql://localhost:3306/caoe?useUnicode=yes&characterEncoding=UTF-8"/>
<property name="hibernate.connection.username" value="root"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.c3p0.max_size" value="50" />
<property name="hibernate.c3p0.min_size" value="3" />
<property name="hibernate.c3p0.max_statements" value="20" />
<property name="hibernate.c3p0.acquire_increment" value="1" />
<property name="hibernate.c3p0.idle_test_period" value="30" />
<property name="hibernate.c3p0.timeout" value="35" />
<property name="hibernate.c3p0.checkoutTimeout" value="60000" />
<property name="hibernate.connection.release_mode" value="after_statement" />
<property name="debugUnreturnedConnectionStackTraces"
value="true" />
</properties>
</persistence-unit>
</persistence>
编辑:我正在将应用程序部署到安装了 Tomcat 和 MySQL 的红帽服务器。我只是想知道为什么 Hibernate 打开太多与 MySQL 的连接,所有实体管理器都关闭,没有连接将保持打开状态,但事实并非如此。如果我确实在执行以下操作时打开了连接,我正在猜测并纠正我:
List<Sondage> allSondages = SondageDao.getAllSondages();
for (Sondage sondage : allSondages) {
List<Question> questions = sondage.getQuestions();
//code to display questions for example
}
在这里,当我使用sondage.getQuestions() 时,Hibernate 是否打开与数据库的连接并且之后不关闭它,我是否在配置文件中遗漏了一些在完成后关闭或返回与池的连接的内容。提前感谢您的帮助。
编辑2: 由于人们要求版本,因此它们是: JAVA jre 1.8.0_25 Apache Tomcat v7.0 休眠核心4.3.10 休眠 c3p0 4.3.10.final 休眠-jpa 2.1 提前致谢
如果有帮助的话,mysql版本是Mysql 5.6.17...
编辑 4:由于人们对我发布的代码的女巫版本感到困惑,所以让我编辑它,以便您知道究竟发生了什么:
首先,我将首先展示什么是错误代码,因为你们并不关心什么是有效的:
@SuppressWarnings("unchecked")
public static List<Sondage> GetAllSondage() {
EntityManager em = PersistenceManager.getEntityManager();
List<Sondage> allSondages = new ArrayList<>();
try {
em.getTransaction().begin();
Query query = em.createQuery("SELECT s FROM Sondage s");
allSondages = query.getResultList();
em.getTransaction().commit();
} catch (Exception ex) {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
allSondages = null;
} finally {
em.close();
}
return allSondages;
}
所以这基本上是我为所有 dao 函数所做的,我知道这里不需要事务,因为我看到问题指出事务对于关闭连接很重要。除此之外,我从具有 EntityManagerFactory 单例对象的 PersistenceManager 类中获取实体管理器,因此 getEntityManager 从 EntityManagerFactory 单例对象创建一个实体管理器:=> 代码优于 1000 字: PesistenceManager.java:
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class PersistenceManager
{
private static EntityManagerFactory emf = null;
public static EntityManager getEntityManager()
{
return getEntityManagerFactory().createEntityManager();
}
public static EntityManagerFactory getEntityManagerFactory()
{
if(emf == null) {
emf = Persistence.createEntityManagerFactory("CAOE");
return emf;
}
else
return emf;
}
}
是的,这很酷,一切都很好,但问题出在哪里?
这里的问题是这个版本打开连接并且从不关闭它们,em.close()没有效果,它保持连接到数据库。
菜鸟修复:
我为解决这个问题所做的是为每个请求创建一个 EntityManagerFactory,这意味着 dao 看起来像这样:
@SuppressWarnings("unchecked")
public static List<Sondage> GetAllSondage() {
//this is the method that return the EntityManagerFactory Singleton Object
EntityManagerFactory emf = PersistenceManager.getEntitManagerFactory();
EntityManager em = emf.createEntityManager();
List<Sondage> allSondages = new ArrayList<>();
try {
em.getTransaction().begin();
Query query = em.createQuery("SELECT s FROM Sondage s");
allSondages = query.getResultList();
em.getTransaction().commit();
} catch (Exception ex) {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
allSondages = null;
} finally {
em.close();
emf.close();
}
return allSondages;
}
现在这很糟糕,我会在我没有回答这个问题的时候保留它(看起来永远是 :D)。因此,使用此代码基本上所有连接都会在休眠后关闭不需要它们。提前感谢您在这个问题上所做的任何努力:)
【问题讨论】:
-
注意到您在 persistence.xml 文件中指定了发布模式。根据这个文档:docs.jboss.org/hibernate/stable/core.old/reference/en/html/… 这样做通常是个坏主意。可能从文件中删除该配置行即可。这更多是通过观察和 SWAG 而不是答案,所以这就是为什么我提供它是评论而不是答案。
-
嗨@MattCampbell,非常感谢您的回答,我没有在配置文件中这样做,但是当我看到属性时,我认为这可以释放一些与池的连接,但这并没有,所以回答你的猜测,这不是问题。
-
hibernate、JPA、tomcat 和 JAVA 使用哪些版本?你用 JPA 生成你的类吗?
-
能否请您分享 PersistenceManager 类的详细信息?
-
@rogerdpack 谢谢你,那是 6 年前的事了 :D 是的,问题出在 lib 版本中
标签: java mysql hibernate jpa c3p0