Java Bağlantıları için Singleton Desenini Nasıl Uygulatın
Table of Contents
Singleton modeli, Java'daki en yaygın kullanılan yaratım tasarım modellerinden biridir. Bir sınıfın tam bir örneği olduğunu ve veri tabanı bağlantıları için tekton desenini uygulamanın, bu modelin yaygın olarak veritabanı bağlantılarını yönetmek için kullanılır - bağlantıya yol açan kritik bir kaynak, eğer yanlış bir şekilde, performans bozulmasına yol açabilir, kaynak sızıntılarına yol açabilir ve öngörülemeyen davranışlar.Bu makale, çoklu thread güvenli yaklaşımları, en iyi uygulamaları, ortak pitfallsları kapsar.
Neden Verin Bağlantılar için Singleton Deseni Kullanın?
Veritabanı bağlantıları oluşturmak için pahalıdır. Her bağlantı hafıza, ağ soketleri ve veritabanı sunucu kaynakları. Dikkatli yönetim olmadan, bir uygulama zaman aralıkları ve başarısızlıkları için hızla izleyebilirsiniz. Singleton deseni bunu yalnızca bir bağlantı örneği uygulama yaşam döngüsü boyunca var olmasını sağlayarak kullanır:
- [FONT:0)Kaynak Yönetimi: [Dönetici:0) Aktif bağlantıların sayısını sınırlar, hem müşteri hem de veritabanı sunucusuna yük.
- [FONT:0]Consistency:[[Dönetici:[Dönetici: 0) Tüm bileşenler aynı bağlantıyı paylaşıyor, birden fazla bağlantı örneği tarafından neden olan devlet ayrımını kaçınıyor.
- [FONT:0]Ease of Care:[Dönetici:[Dönetici:)) Orta sınıf, konfigürasyon ve tek bir sınıfta yırtılma, güncelleştirmeleri ve testleri basitleştirmek.
- [FONT:0) Tahmin edilebilir Yaşam döngüsü:[Dönemli:[Dönemli Yaşam döngüsü:[Dönlenebilirlik:0) Bağlantı bir kez ve yeniden oluşturulur, tekrarlanan doğrulama ve elhake yükü için gerekli ihtiyacı ortadan kaldırır.
Ancak, tek bir tekFLT:0'ın varsayılan olarak güvenli olmadığını belirtmek önemlidir. Birden fazla konu aynı bağlantıyı eş zamanlı olarak kullanıyorsa, bu nüansları daha sonra ele alacağız.
Java'daki Singleton Deseninin Temelleri
Tekton sınıfı üç temel özelliği vardır:
- AİLM:0) Özel yapı ([Dönetici: 1) sınıf dışında anlıklaştırmayı önlemek için.
- AAHFLT:0) Özel statik değişken[[Dönetici: 1 ) tek örneği tutan.
- AAHFLT:0) Devletli statik yöntem[[Dönemli: 1), örneğin, gerekirse onu yaratır.
Veritabanı bağlantılarına uygulandığında, tekton sınıfı da bağlantı nesnesini yönetir ve onu almak için bir yöntem sunar (örneğin, 03:2). En basit uygulama ile başlayalım ve sonra iş parçacığı güvenliği için geliştirelim.
Temel (Non-Thread-Safe) Singleton
En basit uygulama, sınıf yüklendiği zaman örnek oluşturulmaktadır. Bu tamamen senkronize etmekten kaçınır, ancak bağlantı asla kullanılmadığı takdirde kaynakları boşayabilir.
public class DatabaseConnection {
private static final DatabaseConnection INSTANCE = new DatabaseConnection();
private final Connection connection;
private DatabaseConnection() {
this.connection = createConnection();
}
public static DatabaseConnection getInstance() {
return INSTANCE;
}
public Connection getConnection() {
return connection;
}
private Connection createConnection() {
// JDBC connection logic (simplified)
try {
Class.forName("com.mysql.cj.jdbc.Driver");
return DriverManager.getConnection(
"jdbc:mysql://localhost:3306/mydb", "user", "password");
} catch (ClassNotFoundException | SQLException e) {
throw new RuntimeException("Failed to create database connection", e);
}
}
}
Bu tembel yaklaşım, bir şekilde düşünülemez çünkü iki iplik aynı anda GÜNDÜ:4'ü görebilir ve her biri yeni bir örnek oluşturabilir. Üretim sistemleri için, üç sağlam uygulamayı inceleyeceğiz.
Thread-Safe Singleton Uygulamaları
1. Synchronized Method
Bu, bir kez daha imzalayabileceği bir veritabanı bağlantısına sahip olmak için anahtar kelimeye ek olarak, bu ekin bir performans cezasına çarptırılır, çünkü her çağrıyı ESFLT:7'ye alır.
public class DatabaseConnection {
private static DatabaseConnection instance;
private Connection connection;
private DatabaseConnection() {
connection = createConnection();
}
public static synchronized DatabaseConnection getInstance() {
if (instance == null) {
instance = new DatabaseConnection();
}
return instance;
}
public synchronized Connection getConnection() {
return connection;
}
private Connection createConnection() { /* ... */ }
}
Not that even after initialization, every call tourFLT:9) eşitleme gerektirir. Bu yöntem sadece tekton çok nadiren yaratılırsa kabul edilebilir, ancak veritabanı bağlantıları için aşağıdaki yaklaşımlardan birini kullanmak daha iyidir.
2. Çifte Kontrollü Kilit (DCL)
DCL, örneğin senkronizasyon olmadan örnek değişkeni kontrol ederek senkronizasyonu azaltır ve örneğin aslında GÜNCÜŞÜNÜŞÜNCÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNCÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜNÜŞÜN
public class DatabaseConnection {
private static volatile DatabaseConnection instance;
private Connection connection;
private DatabaseConnection() {
connection = createConnection();
}
public static DatabaseConnection getInstance() {
if (instance == null) {
synchronized (DatabaseConnection.class) {
if (instance == null) {
instance = new DatabaseConnection();
}
}
}
return instance;
}
public Connection getConnection() {
return connection;
}
private Connection createConnection() { /* ... */ }
}
Bu model yaygın olarak kullanılıyor ve iyi performans sunuyor çünkü senkronizasyon sadece bir kez gerçekleşir. ancak, [[ŞUYUÇLARUÇLAR İÇİNDEŞİYLEŞİ: 13) anahtar kelime, çoğu uygulama için uygun olan bir hafıza bariyeri vardır.
3. Bill Pugh Singleton (İnisalizasyon-on-Demand Sahibi Idiom)
Bu teknik, tekton örneği tutan özel bir statik iç sınıf kullanır. İç sınıf, ilkleşme tembelliğini yapana kadar yüklenemez. çünkü JVM bu sınıf başlangıçını garanti eder.
public class DatabaseConnection {
private Connection connection;
private DatabaseConnection() {
connection = createConnection();
}
private static class Holder {
static final DatabaseConnection INSTANCE = new DatabaseConnection();
}
public static DatabaseConnection getInstance() {
return Holder.INSTANCE;
}
public Connection getConnection() {
return connection;
}
private Connection createConnection() {
// JDBC setup
try {
Class.forName("com.mysql.cj.jdbc.Driver");
return DriverManager.getConnection(
"jdbc:mysql://localhost:3306/mydb", "user", "password");
} catch (ClassNotFoundException | SQLException e) {
throw new RuntimeException("Failed to create database connection", e);
}
}
}
Bu model çoğu senaryo için önerilir, çünkü garanti edilen thread güvenliği ve sıfır senkronizasyonu ile yeniden bir araya gelir. Aynı zamanda serileştirme ile doğru çalışırsanız, bunu doğru şekilde çalışırsınız. ”
4. Enum Singleton
Joshua Bloch, kitabınındaki arsa temelli tekton için savunuyor.(0)Effective Java) Enums'ın doğal olarak serilenebilir ve yansıma saldırılarına karşı koruma sağlar. Ayrıca bağlantı kurulumu ağır ve daha da kapalıdır.
public enum DatabaseConnection {
INSTANCE;
private Connection connection;
DatabaseConnection() {
connection = createConnection();
}
public Connection getConnection() {
return connection;
}
private Connection createConnection() {
// JDBC setup
try {
Class.forName("com.mysql.cj.jdbc.Driver");
return DriverManager.getConnection(
"jdbc:mysql://localhost:3306/mydb", "user", "password");
} catch (ClassNotFoundException | SQLException e) {
throw new RuntimeException("Failed to create database connection", e);
}
}
}
Kullanım:FLT:20. Enum yaklaşımı koncise ve sağlamdır, ancak bağlantıyı herhangi bir referans olarak kısa sürede yapılabilir.Birçok uygulama için bu kabul edilebilir.
Bağlantı Havuz: Daha İyi Bir Alternatif?
Singleton modeli tek bir bağlantıya sınırlamak için uygun olsa da, çoğu gerçek dünya uygulamaları havuzun kendisini yönetmek için kullanılabilir - genellikle tekton olarak - ancak bireysel bağlantılar havuzun satın alınabilmesi için kullanılır.
Popüler bağlantı havuzu uygulamaları da vardır: 0.HikariCP), [[Dört:2|Apache DBCP[D:3) ve )Vibur DBCP) bir havuz tarafından desteklenen bir tekton kullanarak ortak bir modeldir.
public class DataSourceSingleton {
private static final HikariConfig config = new HikariConfig();
private static final HikariDataSource dataSource;
static {
config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
config.setUsername("user");
config.setPassword("password");
config.setMaximumPoolSize(10);
config.setConnectionTimeout(30000);
dataSource = new HikariDataSource(config);
}
private DataSourceSingleton() {}
public static DataSource getDataSource() {
return dataSource;
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
}
Bu singleton, bağlantıya ihtiyacınız olduğunda, havuzdan ödünç aldığınız ve bağlantıya geri döndüğünüzde, bağlantıyı kapatıyorsunuz (bu da havuza geri döner).Bu, merkezi yönetimden çok daha ölçeklenebilir.
Singleton vs. Havuzlama
- [[Dönetici:0) Tek bağlantı:[Döneticileri için kabul edilebilir (örneğin, H2 in-memory), çok düşük boyutlu uygulamalar veya veritabanı basit bir anahtar değerli mağaza ve işlemler eş zamanlı değildir.
- [FONT:0) Bir havuza Tekton örneği:[Dönetici:0) Çok hazır uygulamalar için önerilen yaklaşım. Havuz tekton, ancak bağlantılar Singleton desenini kullanımk için çok fazla kullanılır.
En İyi Uygulamalar ve Tahminler
- [FONT:0]Gücretsizlik:[Dönetici:[Dönetici:[Dönetici:0)Her zaman tekton ipliklerinizi güvenli hale getirin. Çoğu durumda Bill Pugh sahibi deyim veya en fazla durumdaki bağlantıların basit senkronize yönteminden kaçının. Sık sık sık alınan bağlantılar için basit senkronize edilen bağlantı yönteminden kaçının.
- [[Dönetici:0)Connection Build:[Dönetici Bilgilerini Dışlama.Çevre değişkenlerini, yapılandırma dosyalarını veya sırları yönetimi kullanın. kaynak kodunda asla şifreli bilgi şifresi.
- [FONT:0)Kaynak Temizleme:[Dönetici:0) Tek bir bağlantıda tekton, uygulamanın kapatıldığı zaman bağlantının kapalı olmasını sağlamalıdır.Bir konteyner yönetilen bir yaşam döngüsü kullanın. Yakın bağlantı noktalarına yol açmaz.
- [FONT:0)Error Recovery:[[Dönetici:[Döneticileri) Veritabanı bağlantıları bırakılabilir. Tekton onları yeniden kurmak ve yeniden kurmak gerekir. Havuz yaklaşımı bu otomatik olarak çalışır; tek bir bağlantı ile, yeniden deneme mekanizması uygulamanız gerekebilir.
- [FONT=0)Serializasyon:[Dönetici:[Dönetici:0) Uygulamanız, tekton (örneğin, dağıtılmış bir ortamda), mevcut örnek geri dönmek için [[Gönetici:0)
- [FONT:0]Reflection Attack:[Dönetici:[Dönetici:0)Reflection Attack:[Dönetici:[Dönetici:0))Reflection Attack:[Döneticileri aramayı engelleyebilir.Bunu önlemek için, örneğin zaten var olup olmadığınız bir istisna atlayabilirsiniz.
Ortak Pitfalls
- [FONT:0] Çok hazır bir web uygulamasında tek bir bağlantı kurmak: Bu, içerik ve kötü performans çekmeye yol açar.
- [FONT:0) Yakın bağlantıya geçmeyin:[Dönetici: 1 ) Tekton bağlantısı ile, başvuru durduğunda her zaman onu mükemmel bir şekilde kapatma yöntemi sağlayabilirsiniz.
- [FONT:0)Improper çift kontrolli kilitleme olmadan kilitlenir:[Dönerli Java versiyonlarında, bu, tutucu bir deyim veya karmaşıklıktan kaçınmak için ince böceklere neden olabilir.
- [FONT=0]Statik ilkleme emri:[Dönetici:0)[Dönetici:0)Statik ilkleme emri:[Dönetici olmayan diğer statik alanlara referanslar varsa, dairesel bağımlılıklarla karşı çıkabilirsiniz. Basitleşmeye devam edin.
- [FONT:0)Testing zorlukları:[Döneticiler, küresel devlet taşırlar, bağlantı veya veri kaynağına bağımlılık uygularlar ve test için tektonu alay eder. Alternatif olarak, enjeksiyon bağımlılığı ile birlikte bir test dostu modeli kullanmayı düşünün.
Bağlantı Havuzları ile Gerçek Dünya Örneği
Bir üretim hazırlığını göstermek için, burada Bill Pugh sahibi deyim kullanarak bir HikariCP bağlantı havuzunu yöneten tekton:
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import java.sql.Connection;
import java.sql.SQLException;
public class ConnectionPoolManager {
private final HikariDataSource dataSource;
private ConnectionPoolManager() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl(System.getenv("DB_URL"));
config.setUsername(System.getenv("DB_USER"));
config.setPassword(System.getenv("DB_PASS"));
config.setMaximumPoolSize(10);
config.setMinimumIdle(2);
config.setConnectionTimeout(5000);
config.setIdleTimeout(300000);
config.setMaxLifetime(600000);
config.setPoolName("MyAppPool");
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
dataSource = new HikariDataSource(config);
}
private static class Holder {
static final ConnectionPoolManager INSTANCE = new ConnectionPoolManager();
}
public static ConnectionPoolManager getInstance() {
return Holder.INSTANCE;
}
public Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
public void shutdown() {
if (dataSource != null && !dataSource.isClosed()) {
dataSource.close();
}
}
// Optional: shutdown hook
public void registerShutdownHook() {
Runtime.getRuntime().addShutdownHook(new Thread(this::shutdown));
}
}
Kullanım:
try (Connection conn = ConnectionPoolManager.getInstance().getConnection()) {
// use connection
} catch (SQLException e) {
// handle
}
Bu model sağlam, iplik güvenli ve üretim test edilir. Kodtan ayrıdır ve bağlantıların verimli bir şekilde yeniden kullanılması sağlar.
Test Singleton Database Connections
Tekton'a bağlı olan test kodu zor olabilir çünkü tekton bunu aşmak için devlet tutar, aşağıdaki stratejileri göz önünde bulundurun:
- [[DÜSÜ:0) Bir arayüz kullanın:[DÜDÜT:1) Bağlantı sağlayıcınız için bir arayüz tanımlayın, sonra tekton bunu uygular. Testlerde, bir alay uygulama yerine getirebilirsiniz.
- [FONT:0)Tektonu baştan çıkar:[Dönetici:[Dönetici:0)Bir paket-özel veya koruma yöntemi ekleyelim (yalnızca test için). Gerekirse yansıma kullanın, ancak iş güvenliğinden haberdar olun.
- [FONT:0) Bağımlılığı enjeksiyonu kullanın:[Dönemli: 0,15) Doğrudan arama yapmak yerine, örnek bir yapı veya setter ile enjekte edin. Bu de kodu birleştirir ve testleri basitleştirir.
public class UserService {
private final Connection connection;
public UserService(Connection connection) {
this.connection = connection;
}
// business methods
}
Üretimde, siz derizFLT:32 olarak adlandırılırsınız. Testlerde, alaylı bir bağlantı geçebilirsiniz.
Sonuç Sonuç Sonuç Sonuç Sonuç Sonuç Sonuç Sonuç
Singleton modeli Java'daki veritabanı bağlantılarını yönetmek için değerli bir araçtır, ancak bir bağlantının çok yoğun sistemler için nadiren uygun olduğunu unutmayın.Bu makalede belirtilen uygulamaları takip ederek, uygulamanızla ölçeklendirme yapan sağlam bir veritabanı bağlantı katmanını seçebilirsiniz.
Daha fazla okuma için, resmi olarak [[DÜye:0)Oracle JDBC öğreticisi[DÜye: 1) ve [DÜyetim:2)HikariCP belgeleri[DÜye Olmayanlar İçin 3 ). daha derin bir şekilde, Java koncurrency ve Singleton desenine bakın, [[Baeldung'un kapsamlı kılavuzu).