java - मैं जेडीबीसी और कनेक्शन पूल का उपयोग कर डीएओ मैनेजर को कैसे कार्यान्वित करूं?




jdbc connection-pooling (2)

आपको एक डीएओ प्रबंधक को लागू करने की आवश्यकता होगी। मैंने इस वेबसाइट से मुख्य विचार लिया, हालांकि मैंने अपना खुद का कार्यान्वयन किया जो कुछ मुद्दों को हल करता है।

चरण 1: कनेक्शन पूलिंग

सबसे पहले, आपको एक कनेक्शन पूल कॉन्फ़िगर करना होगा। एक कनेक्शन पूल, ठीक है, कनेक्शन का एक पूल है। जब आपका एप्लिकेशन चलता है, कनेक्शन पूल कुछ निश्चित कनेक्शन शुरू करेगा, यह रनटाइम में कनेक्शन बनाने से बचने के लिए किया जाता है क्योंकि यह एक महंगा ऑपरेशन है। यह मार्गदर्शिका यह समझाने के लिए नहीं है कि एक को कॉन्फ़िगर कैसे करें, इसलिए इसके बारे में देखें।

रिकॉर्ड के लिए, मैं जावा को अपनी भाषा और ग्लासफ़िश के रूप में अपने सर्वर के रूप में उपयोग करूंगा।

चरण 2: डेटाबेस से कनेक्ट करें

चलो एक DAOManager वर्ग बनाकर शुरू करते हैं। आइए इसे रनटाइम में कनेक्शन खोलने और बंद करने के तरीके दें। कुछ भी फैंसी नहीं है।

public class DAOManager {

    public DAOManager() throws Exception {
        try
        {
            InitialContext ctx = new InitialContext();
            this.src = (DataSource)ctx.lookup("jndi/MYSQL"); //The string should be the same name you're giving to your JNDI in Glassfish.
        }
        catch(Exception e) { throw e; }
    }

    public void open() throws SQLException {
        try
        {
            if(this.con==null || !this.con.isOpen())
                this.con = src.getConnection();
        }
        catch(SQLException e) { throw e; }
    }

    public void close() throws SQLException {
        try
        {
            if(this.con!=null && this.con.isOpen())
                this.con.close();
        }
        catch(SQLException e) { throw e; }
    }

    //Private
    private DataSource src;
    private Connection con;

}

यह एक बहुत ही फैंसी क्लास नहीं है, लेकिन यह आधार होगा कि हम क्या करने जा रहे हैं। तो, यह कर रहा है:

DAOManager mngr = new DAOManager();
mngr.open();
mngr.close();

किसी ऑब्जेक्ट में डेटाबेस से अपना कनेक्शन खोलना और बंद करना चाहिए।

चरण 3: इसे एक बिंदु बनाओ!

क्या, अब, अगर हमने ऐसा किया?

DAOManager mngr1 = new DAOManager();
DAOManager mngr2 = new DAOManager();
mngr1.open();
mngr2.open();

कुछ लोग तर्क दे सकते हैं, "दुनिया में आप ऐसा क्यों करेंगे?" । लेकिन फिर आप कभी नहीं जानते कि एक प्रोग्रामर क्या करेगा। फिर भी, प्रोग्रामर एक नया खोलने से पहले कनेक्शन बंद करने से रोक सकता है। इसके अलावा, यह आवेदन के लिए संसाधनों का अपशिष्ट है। अगर आप वास्तव में दो या दो से अधिक खुले कनेक्शन चाहते हैं तो यहां रुकें, यह प्रति उपयोगकर्ता एक कनेक्शन के लिए एक कार्यान्वयन होगा।

इसे एक बिंदु बनाने के लिए, हमें इस कक्षा को सिंगलटन में परिवर्तित करना होगा। एक सिंगलटन एक डिज़ाइन पैटर्न है जो हमें किसी दिए गए ऑब्जेक्ट का एक और एक उदाहरण प्राप्त करने की अनुमति देता है। तो, चलो इसे एक सिंगलटन बनाओ!

  • हमें अपने public कन्स्ट्रक्टर को एक निजी रूप में परिवर्तित करना होगा। हमें केवल एक उदाहरण देना होगा जो इसे कॉल करता है। फिर DAOManager एक कारखाना बन जाता है!
  • हमें एक नई private कक्षा भी जोड़नी होगी जो वास्तव में एक सिंगलटन स्टोर करेगी।
  • इन सबके साथ, हमें getInstance() विधि की भी आवश्यकता है जो हमें एक सिंगलटन उदाहरण देगा जिसे हम कॉल कर सकते हैं।

चलो देखते हैं कि यह कैसे कार्यान्वित किया गया है।

public class DAOManager {

    public static DAOManager getInstance() {
        return DAOManagerSingleton.INSTANCE;
    }  

    public void open() throws SQLException {
        try
        {
            if(this.con==null || !this.con.isOpen())
                this.con = src.getConnection();
        }
        catch(SQLException e) { throw e; }
    }

    public void close() throws SQLException {
        try
        {
            if(this.con!=null && this.con.isOpen())
                this.con.close();
        }
        catch(SQLException e) { throw e; }
    }

    //Private
    private DataSource src;
    private Connection con;

    private DAOManager() throws Exception {
        try
        {
            InitialContext ctx = new InitialContext();
            this.src = (DataSource)ctx.lookup("jndi/MYSQL");
        }
        catch(Exception e) { throw e; }
    }

    private static class DAOManagerSingleton {

        public static final DAOManager INSTANCE;
        static
        {
            DAOManager dm;
            try
            {
                dm = new DAOManager();
            }
            catch(Exception e)
                dm = null;
            INSTANCE = dm;
        }        

    }

}

जब एप्लिकेशन शुरू होता है, जब भी किसी को सिंगलटन की आवश्यकता होती है तो सिस्टम एक DAOManager को चालू करेगा। काफी साफ, हमने एक एकल पहुंच बिंदु बनाया है!

लेकिन सिंगलटन एक antipattern है क्योंकि कारण! मुझे पता है कि कुछ लोग सिंगलटन पसंद नहीं करेंगे। हालांकि यह समस्या को हल करता है (और मेरा हल हो गया है) काफी हद तक। यह इस समाधान को लागू करने का एक तरीका है, यदि आपके पास अन्य तरीकों के बारे में सुझाव देने के लिए आपका स्वागत है।

चरण 4: लेकिन कुछ गड़बड़ है ...

हाँ, वास्तव में वहाँ है। एक सिंगलटन पूरे एप्लिकेशन के लिए केवल एक उदाहरण देगा! और यह कई स्तरों में गलत है, खासकर अगर हमारे पास एक वेब सिस्टम है जहां हमारा आवेदन बहुप्रचारित होगा! हम इसे कैसे हल कर सकते हैं?

जावा ThreadLocal नाम की एक कक्षा प्रदान करता है। एक ThreadLocal वैरिएबल में प्रति थ्रेड एक उदाहरण होगा। अरे, यह हमारी समस्या हल करता है! यह कैसे काम करता है इसके बारे में और देखें , आपको इसके उद्देश्य को समझने की आवश्यकता होगी ताकि हम जारी रख सकें।

चलो फिर हमारे INSTANCE ThreadLocal बनाते हैं। कक्षा को इस तरह संशोधित करें:

public class DAOManager {

    public static DAOManager getInstance() {
        return DAOManagerSingleton.INSTANCE.get();
    }  

    public void open() throws SQLException {
        try
        {
            if(this.con==null || !this.con.isOpen())
                this.con = src.getConnection();
        }
        catch(SQLException e) { throw e; }
    }

    public void close() throws SQLException {
        try
        {
            if(this.con!=null && this.con.isOpen())
                this.con.close();
        }
        catch(SQLException e) { throw e; }
    }

    //Private
    private DataSource src;
    private Connection con;

    private DAOManager() throws Exception {
        try
        {
            InitialContext ctx = new InitialContext();
            this.src = (DataSource)ctx.lookup("jndi/MYSQL");
        }
        catch(Exception e) { throw e; }
    }

    private static class DAOManagerSingleton {

        public static final ThreadLocal<DAOManager> INSTANCE;
        static
        {
            ThreadLocal<DAOManager> dm;
            try
            {
                dm = new ThreadLocal<DAOManager>(){
                    @Override
                    protected DAOManager initialValue() {
                        try
                        {
                            return new DAOManager();
                        }
                        catch(Exception e)
                        {
                            return null;
                        }
                    }
                };
            }
            catch(Exception e)
                dm = null;
            INSTANCE = dm;
        }        

    }

}

मैं गंभीरता से ऐसा नहीं करना चाहूंगा

catch(Exception e)
{
    return null;
}

लेकिन initialValue() एक अपवाद फेंक नहीं सकता है। ओह, initialValue() आपका मतलब है? यह विधि हमें बताएगी कि ThreadLocal चर पकड़ क्या होगा। असल में हम इसे शुरू कर रहे हैं। तो, इसके लिए धन्यवाद, अब हमारे पास प्रति थ्रेड एक उदाहरण हो सकता है।

चरण 5: एक डीएओ बनाएँ

एक DAOManager डीएओ के बिना कुछ भी नहीं है। तो हमें कम से कम उनमें से कुछ बनाना चाहिए।

"डेटा एक्सेस ऑब्जेक्ट" के लिए छोटा एक डीएओ एक डिज़ाइन पैटर्न है जो किसी निश्चित तालिका का प्रतिनिधित्व करने वाले वर्ग में डेटाबेस संचालन को प्रबंधित करने की उत्तरदायित्व देता है।

हमारे DAOManager अधिक कुशलता से उपयोग करने के लिए, हम GenericDAO को परिभाषित करेंगे, जो एक सार डीएओ है जो सभी डीएओ के बीच सामान्य परिचालन को बनाए रखेगा।

public abstract class GenericDAO<T> {

    public abstract int count() throws SQLException; 

    //Protected
    protected final String tableName;
    protected Connection con;

    protected GenericDAO(Connection con, String tableName) {
        this.tableName = tableName;
        this.con = con;
    }

}

अभी के लिए, वह पर्याप्त होगा। आइए कुछ डीएओ बनाएं। आइए मान लीजिए कि हमारे पास दो पीओजेओ हैं: First और Second , दोनों data और उसके गेटर्स और सेटर्स नामक एक String फ़ील्ड के साथ।

public class FirstDAO extends GenericDAO<First> {

    public FirstDAO(Connection con) {
        super(con, TABLENAME);
    }

    @Override
    public int count() throws SQLException {
        String query = "SELECT COUNT(*) AS count FROM "+this.tableName;
        PreparedStatement counter;
        try
        {
        counter = this.con.PrepareStatement(query);
        ResultSet res = counter.executeQuery();
        res.next();
        return res.getInt("count");
        }
        catch(SQLException e){ throw e; }
    }

   //Private
   private final static String TABLENAME = "FIRST";

}

SecondDAO में समान संरचना कम होगी, बस TABLENAME को "SECOND" बदलना TABLENAME

चरण 6: प्रबंधक को एक कारखाना बनाना

DAOManager न केवल एक कनेक्शन बिंदु के रूप में सेवा करने के उद्देश्य को पूरा करना चाहिए। दरअसल, DAOManager को इस प्रश्न का उत्तर देना चाहिए:

डेटाबेस के कनेक्शन के प्रबंधन के लिए जिम्मेदार कौन है?

व्यक्तिगत डीएओ उन्हें प्रबंधित नहीं करना चाहिए, लेकिन DAOManager । हमने आंशिक रूप से सवाल का जवाब दिया है, लेकिन अब हमें डेटाबेस को अन्य कनेक्शन प्रबंधित करने नहीं देना चाहिए, यहां तक ​​कि डीएओ भी नहीं। लेकिन, डीएओ को डेटाबेस से कनेक्शन की आवश्यकता है! इसे कौन प्रदान करना चाहिए? वास्तव में DAOManager ! हमें क्या करना चाहिए DAOManager अंदर एक कारखाना विधि DAOManager । इतना ही नहीं, लेकिन DAOManager उन्हें वर्तमान कनेक्शन भी सौंप देगा!

फैक्ट्री एक डिज़ाइन पैटर्न है जो हमें एक निश्चित सुपरक्लास के उदाहरण बनाने की अनुमति देगा, यह जानने के बिना कि वास्तव में कौन सी बाल कक्षा वापस की जाएगी।

सबसे पहले, आइए हमारे टेबल को सूचीबद्ध करने वाले enum बनाएं।

public enum Table { FIRST, SECOND }

और अब, DAOManager अंदर कारखाना विधि:

public GenericDAO getDAO(Table t) throws SQLException 
{

    try
    {
        if(this.con == null || this.con.isClosed()) //Let's ensure our connection is open   
            this.open();
    }
    catch(SQLException e){ throw e; }

    switch(t)
    {
    case FIRST:
        return new FirstDAO(this.con);
    case SECOND:
        return new SecondDAO(this.con);
    default:
        throw new SQLException("Trying to link to an unexistant table.");
    }

}

चरण 7: सब कुछ एक साथ रखो

हम अभी जाने के लिए अच्छे हैं। निम्नलिखित कोड आज़माएं:

DAOManager dao = DAOManager.getInstance();
FirstDAO fDao = (FirstDAO)dao.getDAO(Table.FIRST);
SecondDAO sDao = (SecondDAO)dao.getDAO(Table.SECOND);
System.out.println(fDao.count());
System.out.println(sDao.count());
dao.close();

क्या यह कल्पना और पढ़ने में आसान नहीं है? इतना ही नहीं, लेकिन जब आप close() , तो आप डीएओ का उपयोग कर रहे प्रत्येक कनेक्शन को बंद कर देते हैं। पर कैसे?! खैर, वे एक ही कनेक्शन साझा कर रहे हैं, इसलिए यह सिर्फ प्राकृतिक है।

चरण 8: हमारी कक्षा को ठीक-ठीक करना

हम यहां से कई चीजें कर सकते हैं। यह सुनिश्चित करने के लिए कि कनेक्शन बंद हैं और पूल में लौट आए हैं, DAOManager में निम्न DAOManager :

@Override
protected void finalize()
{

    try{ this.close(); }
    finally{ super.finalize(); }

}

आप Connection से setAutoCommit() , commit() और rollback() को setAutoCommit() करने के तरीकों को भी कार्यान्वित कर सकते हैं ताकि आप अपने लेनदेन का बेहतर संचालन कर सकें। मैंने जो भी किया है, केवल Connection रखने के बजाय, DAOManager में एक DAOManager और एक DAOManager भी है। तो, जब close() कॉल करना close() यह दोनों को भी बंद कर देता है। समापन बयान और परिणाम सेट का एक तेज़ तरीका!

मुझे आशा है कि यह मार्गदर्शिका आपके अगले प्रोजेक्ट में आपके लिए किसी भी तरह का उपयोग हो सकती है!

मेरी समस्या इस प्रकार है। मुझे एक कक्षा की आवश्यकता है जो एक वेब सिस्टम में डेटाबेस कनेक्शन के लिए एक बिंदु के रूप में काम करता है, ताकि एक उपयोगकर्ता को दो खुले कनेक्शन वाले से बचने के लिए। मुझे इसे यथासंभव इष्टतम होने की आवश्यकता है और इसे सिस्टम में हर लेनदेन का प्रबंधन करना चाहिए। दूसरे शब्दों में केवल वह वर्ग डीएओ को तुरंत चालू करने में सक्षम होना चाहिए। और इसे बेहतर बनाने के लिए, इसे कनेक्शन पूलिंग का भी उपयोग करना चाहिए! मुझे क्या करना चाहिए?


मुझे लगता है कि यदि आप सादे जेडीबीसी में एक साधारण डीएओ पैटर्न करना चाहते हैं तो आपको इसे सरल रखना चाहिए:

      public List<Customer> listCustomers() {
            List<Customer> list = new ArrayList<>();
            try (Connection conn = getConnection();
                 Statement s = conn.createStatement();
                 ResultSet rs = s.executeQuery("select * from customers")) { 
                while (rs.next()) {
                    list.add(processRow(rs));
                }
                return list;
            } catch (SQLException e) {
                throw new RuntimeException(e.getMessage(), e); //or your exceptions
            }
        }

आप क्लाइंटडाओ या कस्टमर मैनेजर नामक कक्षा में इस पैटर्न का अनुसरण कर सकते हैं, और आप इसे सरल के साथ कॉल कर सकते हैं

CustomersDao dao = new CustomersDao();
List<Customers> customers = dao.listCustomers();

ध्यान दें कि मैं संसाधनों के साथ प्रयास कर रहा हूं और यह कोड कनेक्शन लीक, साफ और सीधा करने के लिए सुरक्षित है, आप शायद फैक्ट्री, इंटरफेस और प्लंबिंग के साथ पूर्ण डीएओ पैटर्न का पालन नहीं करना चाहते हैं जो कई मामलों में नहीं है असली मूल्य जोड़ें।

मुझे नहीं लगता कि थ्रेडलोकल्स का उपयोग करना एक अच्छा विचार है, स्वीकृत उत्तर में इस्तेमाल किया जाने वाला बुरा क्लासलोडर रिसाव का स्रोत है

याद रखें कि अंत में ब्लॉक या संसाधनों के साथ प्रयास करने के प्रयास में अपने संसाधन (स्टेटमेंट्स, परिणामसेट्स, कनेक्शन) को बंद करें





genericdao