7.1 Bağlantı havuzu

Bugün veritabanıyla nasıl daha profesyonelce çalışılacağını öğreneceğiz. Ve şimdi İngilizce thread pool yani bağlantı havuzu hakkında konuşacağız .

Veritabanına bağlanmak biraz zaman alıyor. Özellikle veritabanı uzaksa. Her istek için veritabanına bir bağlantı yaparsak, uygulamamızın yanıt hızı inanılmaz derecede yavaş olacaktır. Tüketeceği kaynaklardan bahsetmiyorum bile.

Bu tür sorunlara bir çözüm olarak, tabana olan bağlantıların iş parçacığı havuzu adı verilen bir kümede saklanması önerildi.

Yeni bir bağlantı isteğinde bulunduğumuzda bunu bağlantı havuzu oluşturuyor ve kapatıldığında ise kapatmayıp bağlantı havuzuna kaydediyor. Ve tekrar bağlantı havuzundan bağlantı talep edersek yeni bir tane oluşturmak yerine bize eskilerden birini verecektir.

Aslında uygulama, normal bir JDBC sürücüsü için bir sarmalayıcı olan ve havuzla çalışmak için ek işlevlere sahip olan özel bir sürücü aracılığıyla çalışır. Bu durum aşağıdaki gibi temsil edilebilir:

bağlantı havuzu

Programcı, bağlantı havuzu ayarlarını manuel olarak yapabilir: etkin bağlantıların sayısı, zaman aşımı vb.

Özellikle aşırı durumlar için, kendi bağlantı havuzunuzu yazabilirsiniz: bir bağlantı listesi olan bir sınıf. Bağlantıyı listeye geri döndürecek olan kapatma işlevini geçersiz kılacak ve açık bağlantı zamanlayıcısı gibi birçok başka özellik olacaktır. Uzun süre bağlantı olmadığında bağlantı kapatılır.

7.2* Arayüz DataSource ve ConnectionPoolDataSource

İş parçacığı havuzu genellikle DataSource nesnesiyle birlikte çalışır. Bu nesne, uzak bir veritabanının soyutlaması olarak düşünülebilir. Veri Kaynağı adı, kelimenin tam anlamıyla Veri Kaynağı olarak tercüme edilebilir. Bu bir tür ipucu.

DataSource nesneleri, bir veritabanına fiziksel bağlantı elde etmek için kullanılır ve DriverManager'a bir alternatiftir. JDBC sürücüsünü kaydetmeye gerek yoktur. Bir bağlantı kurmak için yalnızca uygun parametreleri ayarlamanız gerekir vegetConnection() yöntemini yürütün.

Yerel olarak (doğrudan uygulamada) DataSource türünde bir nesne oluştururken, bağlantı parametreleri JDBC sürücü sağlayıcısı tarafından sağlanan uygun yöntemlerle ayarlanır. Farklı satıcılardan DBMS'ye bağlanmak için parametreler hem tür hem de sayı olarak farklı olabileceğinden (örneğin, tüm DBMS, sürücü türünün veya ağ protokolünün belirtilmesini gerektirmez) olduğundan, bu yöntemler DataSource arabirimi tarafından tanımlanmaz.

Bu nedenle, Oracle DBMS ile çalışırken, karşılık gelen set ve get yöntemlerini kullanmak için, DataSource arabirimini uygulayan aynı adlı sınıfın bir örneği olan OracleDataSource türünde bir nesne elde etmek gerekir. Bu nedenle, DataSource türünde nesneler oluşturmanın bu yolu, kodunuzu daha az taşınabilir ve sürücünün özel uygulamasına daha az bağımlı hale getirir.

Aşağıda, DataSource türündeki nesnelerin yerel kullanımını gösteren bir kod örneği yer almaktadır.

import java.sql.*;
import javax.sql.*;
import oracle.jdbc.driver.*;
import oracle.jdbc.pool.*;

public class DataSource {
    public static void main(String[] args) {
    	try {
        	OracleDataSource ods = new OracleDataSource();

        	ods.setUser("root");
        	ods.setPassword("secret");
        	ods.setDriverType("thin");
        	ods.setDatabaseName("test");
        	ods.setServerName("localhost");
        	ods.setPortNumber(1521);

        	Connection connection = ods.getConnection();
        	System.out.println("Connection successful!!!");

    	} catch (SQLException se) {
        	se.printStackTrace();
    	}
    	System.out.println("Goodbye!");
	}
}

7.3* JNDI Arayüzü

DataSource türündeki nesnelerin tüm yetenekleri, JNDI arabiriminin kullanımıyla birlikte kendini gösterir. JNDI, büyük sunucu uygulamaları için bir hizmetin diğeriyle bağlantı kurmasına izin veren özel bir hizmettir (dizin gibi bir şey).

Ad ve dizin hizmetini kullanmak, sistem yöneticisi tarafından önceden tanımlanmış bağlantı parametreleriyle önceden oluşturulmuş DataSource türündeki nesneleri depolamanıza olanak tanır. Aşağıdakiler, Sun tarafından geliştirilen bazı standart özellik (parametre) adlarıdır:

Mülkiyet adı Java veri türü Amaç
veri tabanı ismi Sicim Veri tabanı ismi
sunucu adı Sicim Sunucu adı
kullanıcı Sicim kullanıcı adı (ID)
şifre Sicim Kullanıcı şifresi
Port numarası int DBMS sunucusu bağlantı noktası numarası

DataSource ve JNDI arabirimlerinin birleşimi, J2EE bileşen teknolojisine dayalı çok katmanlı kurumsal uygulamaların geliştirilmesinde önemli bir rol oynar.

Uygulama kodunuzda DataSource ve JNDI arabirimlerinin bir kombinasyonunu kullanırsanız, yalnızca adlandırma ve dizin hizmetinden DataSource türünde bir nesne istemeniz gerekir. Bu durumda, bağlantının ayrıntıları ve sürücünün belirli bir uygulamasına bağlı program kodu, ad ve dizin hizmetinde saklanan nesnede uygulamadan gizlenir.

Bu nedenle, DataSource ve JNDI türündeki nesnelerin paylaşımı, birbirinden bağımsız olarak gerçekleştirilen iki adımı içerir:

  1. DataSource türündeki adlandırılmış nesneyi , Context.bind().javax.naming
  2. kullanarak uygulamadaki adlandırma ve dizin hizmetinden DataSource türünde bir nesne isteyin Context.lookup(). DataSource.getConnection()Bundan sonra, veritabanıyla bağlantı kurmak için yöntemini kullanabilirsiniz .

Aşağıda, JNDI arabirimi ile OracleDataSource türünde bir nesnenin birlikte kullanılmasına ilişkin bir örnek yer almaktadır.

// Create a key JNDI object
Hashtable env = new Hashtable();
env.put (Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory");
env.put (Context.PROVIDER_URL, "file:JNDI");
Context ctx = new InitialContext(env);

// Get the DataSource object by its name
DataSource ods = (DataSource) ctx.lookup("myDatabase");

// Get the Connection from the DataSource object
Connection connection = ods.getConnection();
System.out.println("Connection successful!!!");

JNDI'nin çalışmalarını analiz etmeyeceğiz. Bu, bu dersin kapsamı dışındadır. Bu yaklaşımın büyük uygulamalarda çok yaygın olduğunu bilmenizi isterim. Gelecekte buna benzer bir kod görürseniz kaybolmayın.

Nasıl çalıştığı önemli değil. Sadece bir JNDI hizmetiyle, hizmet dizininde kayıtlı herhangi bir hizmetin proxy nesnesini alabileceğinizi bilmeniz gerekir. DataSource nesnesini bu şekilde alırsınız ve veritabanıyla çalışmak için kullanırsınız.

7.4 Bağlantı Havuzu Örnekleri

Başladığımız yere, bağlantı havuzlarına geri dönelim.

Java programcıları programlarında çok sık olarak çeşitli bağlantı havuzları uygulamalarını içeren kitaplıkları kullanırlar. Bunların arasında en popüler üç tanesi var:

  • Apache Commons DBCP'si
  • C3PO
  • HikariCP

Apache projesi, iyi bir bağlantı havuzu oluşturan ilk projeydi, Tomcat web sunucusunda da kullanılıyor. Onunla çalışmanın bir örneği:

public class DBCPDataSource {

    private static BasicDataSource ds = new BasicDataSource();
    static {
    	ds.setUrl("jdbc:h2:mem:test");
    	ds.setUsername("user");
    	ds.setPassword("password");
    	ds.setMinIdle(5);
    	ds.setMaxIdle(10);
    	ds.setMaxOpenPreparedStatements(100);
    }

    public static Connection getConnection() throws SQLException {
    	return ds.getConnection();
    }

    private DBCPDataSource(){ }
}

İkinci çok popüler havuz C3PO'dur . Garip isimler, katılıyorum. C3PO adı, Star Wars'taki c3po robotuna bir göndermedir. Ayrıca CP, Bağlantı Havuzu'nun kısaltmasıdır.

public class C3p0DataSource {

    private static ComboPooledDataSource cpds = new ComboPooledDataSource();
    static {
    	try {
        	cpds.setDriverClass("org.h2.Driver");
        	cpds.setJdbcUrl("jdbc:h2:mem:test");
        	cpds.setUser("user");
        	cpds.setPassword("password");
    	} catch (PropertyVetoException e) {
            // handle the exception
    	}
    }

    public static Connection getConnection() throws SQLException {
    	return cpds.getConnection();
    }

    private C3p0DataSource(){}
}

Bununla ilgili belgeler resmi sayfada bulunabilir .

Ve son olarak, zamanımızın en popüler Bağlantı Havuzu HikariCP'dir :

public class HikariCPDataSource {

    private static HikariConfig config = new HikariConfig();
    private static HikariDataSource ds;

    static {
    	config.setJdbcUrl("jdbc:h2:mem:test");
    	config.setUsername("user");
    	config.setPassword("password");
    	config.addDataSourceProperty("cachePrepStmts", "true");
    	config.addDataSourceProperty("prepStmtCacheSize", "250");
    	config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
    	ds = new HikariDataSource(config);
    }

    public static Connection getConnection() throws SQLException {
    	return ds.getConnection();
    }

    private HikariCPDataSource(){}
}

İşte resmi GitHub sayfası .

Ve yapılandırma hakkında iyi bir makale .