1. 소개
풀링 기술은 Java에서 널리 사용됩니다. 요컨대, 객체 풀을 사용하여 인스턴스가 제한된 인스턴스를 저장합니다. 개발자는 객체 풀에서 인스턴스를 얻은 다음 사용 후 객체 풀로 다시 전환하여 시스템의 자주 발생하는 객체 생성과 개체를 어느 정도 파괴하는 오버 헤드를 줄입니다. Java 스레드 풀 및 데이터베이스 연결 풀은 일반적인 응용 프로그램이지만 모든 객체가 풀링에 적합한 것은 아닙니다. 오버 헤드가 상대적으로 작은 풀링 객체는 성능에 영향을 미칩니다. 객체 풀을 유지 관리하려면 특정 자원 오버 헤드가 필요하기 때문입니다. 오버 헤드가 높고 빈번한 생성 및 사용 사용이있는 물체의 경우 풀링 기술을 사용하면 성능이 크게 향상됩니다.
C3P0, DBCP, Proxool 및 Alibaba 's Druid와 같은 업계에는 많은 성숙한 데이터베이스 연결 풀이 있습니다. 많은 오픈 소스가 있으며 Github에서 소스 코드를 찾을 수 있습니다. 개발자는 자신의 요구와 특성과 성능에 따라 선택할 수 있습니다. 이 기사는 학습 풀링 기술을 이해하고 간단한 데이터베이스 연결 풀을 구현하는 것입니다. 오류가 있으면 오류를 비판하고 수정하고 싶습니다.
2. 디자인
주요 클래스 및 인터페이스
.ConnectionParam- 데이터베이스 연결 풀 매개 변수 클래스, 데이터베이스 연결 및 연결 풀 관련 매개 변수를 담당합니다. 빌더를 사용한 구현.
드라이버 URL 사용자 암호 - 데이터베이스에 연결하는 데 필요합니다.
MinConnection- 최소 연결 수
MaxConnection- 최대 연결 수
Minidle- 최소 유휴 연결 수
Maxwait- 최대 대기 시간
개인 최종 문자열 드라이버; 개인 최종 문자열 URL; 개인 최종 문자열 사용자; 개인 최종 문자열 비밀번호; 개인 최종 INT Minconnection; 개인 최종 INT MaxConnection; 개인 최종 정보; 개인 최종 최종 긴 맥스웨이;
.connectionpool- 데이터베이스 연결 풀
ConnectionPool 생성자는 보호로 선언되고 외부 생성을 금지하며 ConnectionPoolFactory에 의해 균일하게 관리됩니다.
ConnectionPool은 DataSource 인터페이스 및 ReggetConnection () 메소드를 구현합니다.
ConnectionPool은 두 개의 컨테이너를 보유합니다. 하나의 큐가 유휴 연결을 저장하고 다른 벡터 (동기화 고려)는 사용중인 연결을 저장합니다.
개발자가 데이터베이스 연결을 사용하면 대기열에서 검색되며 아니오가 있으면 비어 있습니다. 밀접한 연결이 완료되면 벡터로 돌아갑니다.
ConnectionPool은 Minidle 및 MaxConnection을 기반으로 간단한 동적 확장 메커니즘을 제공합니다.
개인 정적 최종 최종 int initial_size = 5; 비공개 정적 최종 문자열 close_method = "Close"; 개인 정적 로거 로거; 개인 INT 크기; 개인 ConnectionParam ConnectionParam; 개인 ArrayBlockingqueue <conn Private Vector <connection> BusyConnectionVector;
.connectionPoolFactory- 연결 풀 관리 클래스
ConnectionPoolFactory는 연결 풀 객체를 저장하기위한 정적 동의어를 보유합니다.
ConnectionPoolFactory를 사용하면 다른 데이터베이스의 다른 구성으로 여러 연결 풀을 생성 할 수 있습니다.
개발자는 처음으로 특정 이름이있는 연결 풀을 등록 (BING) 한 다음 매번 지정된 연결 풀에서 연결을 얻어야합니다.
연결 풀이 더 이상 사용되지 않으면 개발자는 연결 풀을 로그 아웃 할 수 있습니다.
비공개 정적 맵 <문자열, ConnectionPool> PoolMap = New ConcurrenThashMap <> (); public static connection getConnection (String poolname)은 sqlexception {namecheck (poolname); ConnectionPool ConnectionPool = poolmap.get (poolname); return connectionPool.getConnection (); } public static void registerConnectionPool (문자열 이름, ConnectionParam ConnectionParam) {registerCheck (이름); poolmap.put (이름, 새 ConnectionPool (ConnectionParam)); } // gc public static void unregisterConnectionPool (문자열 이름) {namecheck (name); 최종 ConnectionPool ConnectionPool = PoolMap.get (이름); poolmap.remove (이름); 새 스레드 (new Runnable () {@override public void Run () {ConnectionPool.Clear ();}}). start (); }핵심 코드
데이터베이스 연결 풀의 핵심 코드는 getConnection () 메소드입니다. 일반적으로 개발자가 데이터베이스 작업을 처리 한 후 Close () 메소드가 호출됩니다. 연결이 닫히고 리소스를 해제해야합니다. 데이터베이스 연결 풀에서 사용자가 Close () 메소드를 호출하면 연결을 직접 닫지 않아야하지만 풀에 다시 넣고 재사용해야합니다. 여기서는 Java Dynamic Proxy 메커니즘이 사용됩니다. GetConnection은 "실제"연결이 아니라 사용자 정의 프록시 클래스 (익명 클래스가 여기에서 사용됩니다)를 반환합니다. 사용자가 Close () 메소드를 호출하면 가로 채고 다시 풀에 넣습니다. Dynamic Proxy의 경우 다른 블로그 "Java Dynamic Proxy Simple Application"을 참조하십시오.
@override public connection getConnection ()은 sqlexception을 던지려고 {try {최종 연결 연결 = idleconnectionqueue.poll (connectionParam.getMaxwait (), timeUnit.milliseconds); if (connection == null) {logger.info (emplemsg ()); ensurecapacity (); 널 리턴; } busyConnectionVector.Add (Connection); return (connection) proxy.newproxyInstance (this.getClass (). getClassLoader (), new Class [] {Connection.Class}, new invoctionHandler () {@Override public object (개체 프록시, 메소드 메소드, 개체 [] args) 던질 가능 {if (! method.getname ()). args) {idleconnectionqueue.offer (connection); } catch (InterruptedException e) {e.printstacktrace (); } return null; }2. 사용
먼저 사용자는 드라이버, URL, 사용자, 비밀번호 필수 항목을 포함하여 데이터베이스 연결 풀 매개 변수 (ConnectionParam)를 빌드합니다. MinConnection, MaxConnection 등과 같은 옵션을 사용자 정의 할 수 있습니다. 설정하지 않은 경우 시스템 기본값을 사용하십시오. 이것은 Builder를 사용하여 필요한 속성 및 선택적 속성을 포함하여 많은 수의 속성을 구축하는 이점입니다. 그런 다음 특정 이름으로 ConnectionPoolFactory로 연결 풀을 등록하고 마지막으로 ConnectionPoolFoolFactory 정적 공장 메소드를 호출하여 연결을 얻습니다.
문자열 드라이버 = "com.mysql.jdbc.driver"; 문자열 URL = "jdbc : mysql : // localhost : 3306/test"; 문자열 사용자 = "루트"; 문자열 암호 = "루트"; ConnectionParam ConnectionParam = new ConnectionParam.connectionparamBuilder (드라이버, URL, 사용자, 비밀번호) .Build (); ConnectionPoolFactory.registerConnectionPool ( "테스트", ConnectionParam); 연결 연결 = ConnectionPoolFactory.GetConnection ( "테스트");
3. 코드
.paramconfiguration
패키지 database.config; import java.io.serializable;/** * Database Connection 매개 변수 * 2016/1/18에 Michael Wong이 생성했습니다. */public class paramconfiguration을 구현할 수 있습니다 {public static final int min_connection = 5; 공개 정적 최종 int max_connection = 50; 공개 정적 최종 int min_idle = 5; 공개 정적 최종 최종 Long Max_wait = 30000; private paramconfiguration () {}}빌더
패키지 데이터베이스;/** * Builder * 2016/1/18에 Michael Wong이 작성했습니다. */public interface builder <t> {t build ();}.connectionParam
패키지 데이터베이스; import database.config.paramconfiguration;/** * Database Connection 매개 변수 * 2016/1/18에 Michael Wong이 생성했습니다. */public class ConnectionParam {개인 최종 문자열 드라이버; 개인 최종 문자열 URL; 개인 최종 문자열 사용자; 개인 최종 문자열 비밀번호; 개인 최종 INT Minconnection; 개인 최종 INT MaxConnection; 개인 최종 정보; 개인 최종 최종 긴 맥스웨이; Private ConnectionParam (ConnectionParamBuilder Builder) {this.driver = builder.driver; this.url = builder.url; this.user = builder.user; this.password = builder.password; this.minconnection = builder.minconnection; this.maxConnection = Builder.MaxConnection; this.minidle = builder.minidle; this.maxwait = builder.maxwait; } public String getDriver () {return this.driver; } public String getUrl () {return this.url; } public String getUser () {return this.user; } public String getPassword () {return this.Password; } public int getMinconnection () {return this.minconnection; } public int getMaxConnection () {return this.MaxConnection; } public int getMinidle () {return this.minidle; } public long getmaxwait () {return this.maxwait; } public static class connectionparambuilder는 builder <connectionparam> {// 필수 매개 변수 개인 최종 문자열 드라이버를 구현합니다. 개인 최종 문자열 URL; 개인 최종 문자열 사용자; 개인 최종 문자열 비밀번호; // 선택적 매개 변수 - 기본값으로 초기화 된 개인 int minconnection = paramconfiguration.min_connection; 개인 int maxConnection = paramconfiguration.max_connection; 개인 int minidle = paramconfiguration.min_idle; // 연결 대기 시간 대기 시간 비공개 MaxWait = ParamConfiguration.Max_Wait; Public ConnectionParamBuilder (문자열 드라이버, 문자열 URL, 문자열 사용자, 문자열 암호) {this.driver = 드라이버; this.url = url; this.user = 사용자; this.password = 비밀번호; } public ConnectionParamBuilder minconnection (int minconnection) {this.minconnection = minconnection; 이것을 반환하십시오; } public ConnectionParamBuilder maxConnection (int maxConnection) {this.MaxConnection = maxConnection; 이것을 반환하십시오; } public ConnectionParamBuilder Minidle (int minidle) {this.minidle = minidle; 이것을 반환하십시오; } public ConnectionParamBuilder MaxWait (int maxwait) {this.maxwait = maxwait; 이것을 반환하십시오; } @override public connectionparam build () {return new ConnectionParam (this); }}}.connectionpool
package database.fackasory; import database.connectionparam; import javax.sql.datasource; import java.io.printwriter; import java.lang.reflect.invocationhandler; import java.lang.reflect.method; import java.lang.refrox.proxy; import Java.sql.connection; java.sql.drivermanager; import java.sql.sqlexception; import java.sql.sqlfeaturenotsupportedException; import java.util.vector; import java.util.concurrent.arrayblockingqueue; import java.util.concurrent.timeunit; java.logging.logger; import java.util.concurrent; * Connection Pool * Michael Wong이 2016/1/18에 작성했습니다. */public class ConnectionPool은 DataSource {private static final int initial_size = 5; 비공개 정적 최종 문자열 close_method = "Close"; 개인 정적 로거 로거; 개인 INT 크기; 개인 ConnectionParam ConnectionParam; 개인 ArrayBlockingqueue <conn Private Vector <connection> BusyConnectionVector; Protected ConnectionPool (ConnectionParam ConnectionParam) {this.connectionParam = ConnectionParam; int maxConnection = ConnectionParam.getMaxConnection (); idleconnectionqueue = 새로운 ArrayBlockingqueue <> (maxConnection); BusyConnectionVector = New Vector <> (); logger = logger.getLogger (this.getClass (). getName ()); initConnection (); } private void initConnection () {int minconnection = connectionParam.getMinConnection (); int initialsize = initial_size <minconnection? MinConnection : Initial_Size; try {class.forname (ConnectionParam.getDriver ()); for (int i = 0; i <initialsize+connectionParam.getMincOnnection (); i ++) {idleconnectionqueue.put (newConnection ()); 크기 ++; }} catch (예외 e) {새로운 예외를 던지십시오. }} @override public connection getConnection ()는 sqlexception {try {final connection = idleconnectionqueue.poll (connectionParam.getMaxwait (), timeUnit.milliseconds); if (connection == null) {logger.info (emplemsg ()); ensurecapacity (); 널 리턴; } busyConnectionVector.Add (Connection); return (connection) proxy.newproxyInstance (this.getClass (). getClassLoader (), new Class [] {Connection.Class}, new invoctionHandler () {@Override public object (개체 프록시, 메소드 메소드, 개체 [] args) 던질 가능 {if (! method.getname ()). args) {idleconnectionqueue.offer (connection); } catch (InterruptedException e) {e.printstacktrace (); } return null; } private connection newConnection ()는 sqlexception {string url = connectionParam.getUrl (); 문자열 사용자 = ConnectionParam.getUser (); 문자열 암호 = ConnectionParam.getPassword (); return drivermanager.getConnection (URL, 사용자, 암호); } 보호 된 int size () {반환 크기; } 보호 된 int idleconnectionQuantity () {return idleconnectionqueue.size (); } 보호 된 int busyConnectionQuantity () {return busyConnectionVector.size (); } private void ensurecApicacity ()는 sqlexception {int minidle = connectionParam.getMinidle (); int maxConnection = ConnectionParam.getMaxConnection (); int newcapacity = size + minidle; newCapacity = newCapacity> maxConnection? MaxConnection : NewCapacity; int growCount = 0; if (size <newCapacity) {try {for (int i = 0; i <newCapacity -Size; i ++) {IdleConnectionQueue.put (newConnection ()); GrowCount ++; }} catch (InterruptedException e) {e.printstacktrace (); }} size = size + growCount; } protected void clear () {try {while (size--> 0) {Connection Connection = idleConnectionQueue.take (); connection.close (); }} catch (InterruptedException | sqlexception e) {e.printstacktrace (); }} private String emptymsg () {return "데이터베이스가 바쁘다. 기다려주세요 ..."; } @override public connection getConnection (문자열 사용자 이름, 문자열 비밀번호)은 sqlexception {return null; } @override public printwriter getLogwriter ()는 sqlexception {return null; } @Override public void setLogwriter (printwriter out)는 sqlexception을 던지려고 {} @override public void setlogintimeout (int seconds) 던지기 sqlexception {} @override public int getLogintimeout () sqlexception {return 0; } @override public logger getParentLogger ()는 sqlfeaturenotsupportedException {return null; } @override public <t> t Unfrap (class <t> iface) sqlexception {return null; } @override public boolean iswrapperfor (class <?> iface)는 sqlexception {return false; }}.connectionpoolfactory
Package Database.Fackasor; import Database.connectionParam; import java.sql.connection; import java.sql.sqlexception; import java.util.map; import java.util.concurrent.concurrenthashmap;/** * 연결 풀 공장 * 2016/1/18에 의해 만든 Connection Pool Factory *. */public class connectionPoolFactory {private ConnectionPoolFactory () {} private static map <string, connectionPool> poolMap = new ConcurrEthashMap <> (); public static connection getConnection (String poolname)은 sqlexception {namecheck (poolname); ConnectionPool ConnectionPool = poolmap.get (poolname); return connectionPool.getConnection (); } public static void registerConnectionPool (문자열 이름, ConnectionParam ConnectionParam) {registerCheck (이름); poolmap.put (이름, 새 ConnectionPool (ConnectionParam)); } // gc public static void unregisterConnectionPool (문자열 이름) {namecheck (name); 최종 ConnectionPool ConnectionPool = PoolMap.get (이름); poolmap.remove (이름); 새 스레드 (new Runnable () {@override public void Run () {ConnectionPool.Clear ();}}). start (); } public static int size (String poolname) {namecheck (poolname); return poolmap.get (poolname) .size (); } public static int getIdleConnectionQuantity (String PoolName) {namecheck (poolname); return poolmap.get (poolname) .idleconnectionQuantity (); } public static int getBusyConnectionQuantity (String poolname) {namecheck (poolname); return poolmap.get (poolname) .BusyConnectionQuantity (); } private static void registerCheck (문자열 이름) {if (name == null) {새로운 불법 불법 행정 exception (nullname ()); }} private static void namecheck (문자열 이름) {if (name == null) {throw new new OregalArgumentException (nullname ()); } if (! poolmap.containskey (name)) {새로운 불법 불법 행위 (NotExists (name)); }} private static string nullname () {return "풀 이름은 null이어야합니다"; } private static string notExists (문자열 이름) {return "Connection Pool이 이름" + name + "가 존재하지 않습니다."; }} 4. 테스트
주니트 장치 테스트
package database.facksory; import database.connectionparam; import org.junit.test; import java.sql.connection; import java.sql.sqlexception; import java.util.arraylist; import java.util.list; import static org.junit.assert. 2016/1/20. */public class connectionPoolFactoryTest {@test public void testGetConnection () 던지기 sqlexception {string driver = "com.mysql.jdbc.driver"; 문자열 URL = "jdbc : mysql : // localhost : 3306/test"; 문자열 사용자 = "루트"; 문자열 암호 = "루트"; ConnectionParam ConnectionParam = new ConnectionParam.connectionparamBuilder (드라이버, URL, 사용자, 비밀번호) .Build (); ConnectionPoolFactory.registerConnectionPool ( "테스트", ConnectionParam); List <connection> ConnectionList = New ArrayList <> (); for (int i = 0; i <12; i ++) {connectionList.Add (ConnectionPoolFactory.getConnection ( "Test")); } print (); 닫기 (ConnectionList); 인쇄(); ConnectionList.Clear (); for (int i = 0; i <12; i ++) {connectionList.Add (ConnectionPoolFactory.getConnection ( "Test")); } print (); 닫기 (ConnectionList); ConnectionPoolFactory.unregisterConnectionPool ( "테스트"); } @test (예상 = 불법적 인 경우, 불법 행위 exception.class) public void testException () {try {ConnectionPoolFactory.getConnection ( "test"); } catch (sqlexception e) {e.printstacktrace (); }} private void close (list <conn }}} private void print () {system.out.println ( "idle :" + connectionPoolFactory.getIdleConnectionQuantity ( "Test")); System.out.println ( "Busy :" + ConnectionPoolFactory.getBusyConnectionQuantity ( "Test")); System.out.println ( "size :" + ConnectionPoolFactory.Size ( "Test")); }}위의 내용은이 기사에 관한 모든 것입니다. 모든 사람의 학습에 도움이되기를 바랍니다.