java - हाइबरनेट कनेक्शन पूल से कनेक्शन जारी नहीं कर रहा है
mysql hibernate (5)
मैं हाइबरनेट जेपीए के साथ एक एप्लीकेशन बना रहा हूं और मैं MySQL के साथ कनेक्शन पूलिंग के लिए c3p0 का उपयोग करता हूं। मुझे MySQL डेटाबेस से कनेक्शन की संख्या के साथ कोई समस्या है क्योंकि यह 152 खुले कनेक्शन को हिट करता है, यह वांछित नहीं है क्योंकि मैं अपनी c3p0 कॉन्फ़िगरेशन फ़ाइल को अधिकतम पूल आकार 20 में परिभाषित करता हूं, और निश्चित रूप से मैं प्रत्येक इकाई प्रबंधक को बंद करता हूं प्रत्येक लेनदेन करने के बाद EntityManagerFactory
से।
हर बार जब एक नियंत्रक निष्पादित किया जाता है, तो मुझे लगता है कि 7 से अधिक कनेक्शन खोले गए हैं, और यदि मैं रीफ्रेश करता हूं, तो पिछले निष्क्रिय कनेक्शन बंद किए बिना 7 कनेक्शन फिर से खोले जाते हैं। और प्रत्येक डीएओ समारोह में मैं कॉल करता हूं, 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;
}
और यहां मेरी डीएओ कक्षा है:
@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
बंद है। मेरे जेएसपी में, मैं यह करता हूं: मुझे पता है कि यह दृश्य पक्ष में काम करने का अच्छा तरीका नहीं है।
<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 config फ़ाइल को c3p0-config.xml में रखना होगा, लेकिन मेरे सेटअप के साथ c3p0 को दृढ़ता से गुजरने वाले मानों के साथ प्रारंभ किया गया है .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>
संपादित करें: मैं एप्लिकेशन को टोमकैट और MySQL इंस्टॉल के साथ एक लाल टोपी सर्वर पर तैनात कर रहा हूं। मैं बस सोच रहा हूं कि क्यों हाइबरनेट MySQL के लिए बहुत अधिक कनेक्शन खोल रहा है, सभी इकाई प्रबंधकों के पास कोई कनेक्शन खुला नहीं रहेगा, लेकिन ऐसा नहीं है। मैं अनुमान लगा रहा हूं और मुझे सही कर रहा हूं अगर मैं सच हूं कि जब मैं ऐसा कुछ करता हूं तो कनेक्शन खोले जाते हैं:
List<Sondage> allSondages = SondageDao.getAllSondages();
for (Sondage sondage : allSondages) {
List<Question> questions = sondage.getQuestions();
//code to display questions for example
}
यहां जब मैं sondage.getQuestions()
उपयोग करता sondage.getQuestions()
, क्या हाइबरनेट डेटाबेस से कनेक्शन खोलता है और इसे बंद नहीं करता है, क्या मुझे कॉन्फ़िगरेशन फ़ाइल में कुछ याद आ रहा है जो पूल के साथ कनेक्शन बंद या बंद कर देता है। किसी भी सहायता के लिए अग्रिम रूप से धन्यवाद।
EDIT2: चूंकि लोग संस्करणों के लिए पूछ रहे हैं, यहां वे हैं: जावा जे 1.8.0_25 अपाचे टॉमकैट v7.0 हाइबरनेट-कोर-4.3.10 हाइबरनेट सी 3 पी 0 4.3.10.फिनल हाइबरनेट-जेपीए 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;
}
तो यह मूल रूप से मैंने अपने सभी दाओ कार्यों के लिए किया है, मुझे पता है कि लेनदेन की आवश्यकता नहीं है, क्योंकि मैंने प्रश्नों को ध्यान में रखते हुए कहा कि लेनदेन बंद होने के संबंध में महत्वपूर्ण हैं। इसके अलावा, मुझे 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 बना रहा है, इसका मतलब है कि दाओ इस तरह कुछ दिखता है:
@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;
}
अब यह बुरा है और मैं इसे तब रखूंगा जब मेरे पास इस प्रश्न का उत्तर नहीं है (यह फोवर की तरह लगता है: डी)। इसलिए इस कोड के साथ मूल रूप से हाइबरनेट के बाद सभी कनेक्शन बंद हो जाते हैं। इस प्रश्न में आपके द्वारा किए गए किसी भी प्रयास के लिए अग्रिम धन्यवाद :)
आप हर समय Persistence.createEntityManagerFactory("CAOE")
कॉल करते हैं। यह गलत है। प्रत्येक कॉल createEntityManagerFactory
नया ( createEntityManagerFactory
) कनेक्शन पूल बनाता है। आपको कहीं भी EntityManagerFactory ऑब्जेक्ट को कैश करना चाहिए।
संपादित करें:
इसके अलावा आपको मैन्युअल रूप से EntityManagerFactory को बंद करना चाहिए। आप इसे @ वेब लिस्टनर में कर सकते हैं:
@WebListener
public class AppInit implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {}
public void contextDestroyed(ServletContextEvent sce) {
PersistenceManager.closeEntityMangerFactory();
}
}
अन्यथा पुनर्वितरण के प्रत्येक मामले लीक कनेक्शन का स्रोत है।
ऐसा लगता है कि समस्या हाइबरनेट बग से संबंधित है। कृपया अपने OneToMany एनोटेशन में fetch strategy EAGER निर्दिष्ट करने का प्रयास करें।
@OneToMany(mappedBy = "sondage", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
चूंकि सिबनिक ने पहले ही तकनीकी प्रश्नों का उत्तर दिया है, इसलिए मैं उन कुछ बिंदुओं को संबोधित करने की कोशिश करूंगा जिनके बारे में आप उलझन में हैं। तो मैं आपको कुछ विचार बताता हूं कि एक हाइबरनेट एप्लिकेशन और कनेक्शन-पूल कैसे काम करने का इरादा रखता है:
- डेटाबेस कनेक्शन खोलना एक "महंगा" ऑपरेशन है। प्रत्येक अनुरोध के लिए उस लागत का भुगतान करने से बचने के लिए आप कनेक्शन-पूल का उपयोग करते हैं। पूल पहले से डेटाबेस में कनेक्शन की एक निश्चित संख्या खुलता है और जब आपको एक की आवश्यकता होती है तो आप उन मौजूदा कनेक्शनों में से एक उधार ले सकते हैं। लेनदेन के अंत में इन सम्मेलनों को बंद नहीं किया जाएगा, लेकिन पूल में लौट आएंगे ताकि उन्हें अगले अनुरोध से उधार लिया जा सके। भारी भार के तहत सभी अनुरोधों को पूरा करने के लिए बहुत कम कनेक्शन हो सकते हैं ताकि पूल अतिरिक्त कनेक्शन खोल सके जो बाद में बंद हो सकता है लेकिन एक बार नहीं।
- एक
EntityManagerFactory
बनाना और भी महंगा है (यह कैश बनाएगा, एक नया कनेक्शन-पूल आदि खोल देगा), इसलिए हर अनुरोध से हर अनुरोध के लिए इसे करने से बचें। आपका प्रतिक्रिया-समय आंशिक रूप से धीमा हो जाएगा। इसके अलावा बहुत सारी EntityManagerFactories भी आपके PermGen-space को समाप्त कर सकती है। तो केवल एकEntityManagerFactory
प्रति एप्लिकेशन / दृढ़ता-संदर्भ बनाएं, इसे एप्लिकेशन स्टार्टअप पर बनाएं (अन्यथा पहला अनुरोध बहुत लंबा लगेगा) और इसे एप्लिकेशन शट डाउन पर बंद करें।
निचली पंक्ति: कनेक्शन-पूल का उपयोग करते समय आपको अपने आवेदन के जीवनकाल के लिए कुछ निश्चित डीबी-कनेक्शन खोलने की उम्मीद करनी चाहिए। ऐसा नहीं होना चाहिए कि प्रत्येक अनुरोध के साथ संख्या बढ़ जाती है। यदि आप सत्र के अंत में कनेक्शन बंद करने का आग्रह करते हैं तो पूल का उपयोग न करें और कीमत का भुगतान करने के लिए तैयार रहें।
मुझे लगता है कि हाइबरनेट और सी 3 पी 0 सही तरीके से व्यवहार कर रहे हैं। वास्तव में आपको देखना चाहिए कि आपके C3P0 कॉन्फ़िगरेशन के अनुसार डेटाबेस के कम से कम तीन कनेक्शन हमेशा खुले रहते हैं।
जब आप एक क्वेरी निष्पादित करते हैं तो हाइबरनेट पूल से कनेक्शन का उपयोग करेगा और फिर इसे पूरा होने पर वापस कर देगा। यह कनेक्शन बंद नहीं करेगा। यदि न्यूनतम आकार पार हो गया है और कुछ कनेक्शन समय समाप्त हो गए हैं तो C3P0 पूल को छोटा कर सकता है।
आपके अंतिम उदाहरण में आप कनेक्शन बंद कर देखते हैं क्योंकि आपने अपना एंट्री मैनेजर फैक्ट्री बंद कर दिया है और इसलिए आपका कनेक्शन पूल भी बंद कर दिया है।
मैं एक ही समस्या में भाग गया और EntityManagerFactory के लिए सिंगलटन रैपर क्लास बनाकर और EntityManager को बनाकर इसे ठीक करने में सक्षम था जहां इसकी आवश्यकता है। आपके पास कनेक्शन ओवरलोड समस्या हो रही है क्योंकि आप एंटिटी मैनेजर सृजन को सिंगलटन क्लास में लपेट रहे हैं, जो गलत है। EntityManager लेनदेन का दायरा प्रदान करता है (पुन: उपयोग नहीं किया जाना चाहिए), EntityManagerFactory कनेक्शन प्रदान करता है (फिर से उपयोग किया जाना चाहिए)।
से: https://cloud.google.com/appengine/docs/java/datastore/jpa/overview
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public final class EMF {
private static final EntityManagerFactory emfInstance =
Persistence.createEntityManagerFactory("CAOE");
private EMF() {}
public static EntityManagerFactory get() {
return emfInstance;
}
}
और फिर प्रत्येक अनुरोध के लिए EntityManager बनाने के लिए फ़ैक्टरी उदाहरण का उपयोग करें।
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import EMF;
// ...
EntityManager em = EMF.get().createEntityManager();