First, the introduction
Pooling technology is widely used in Java, in the case of Jane, the object pool is used to store an instance with a limited number of instances, the developer takes an instance from the object pool, and then changes back to the object pool, thereby reducing the overhead of the system frequently creating object destruction objects. Java thread pools and database connection pools are typical applications, but not all objects are suitable for pooling, and for creating less expensive objects, pooling can affect performance, because maintaining object pooling also requires a certain amount of resource overhead, creating expensive and frequently used objects. The use of pooling technology can greatly improve performance.
The industry has many mature database connection pools, such as C3p0,dbcp,proxool and Ali's Druid. Many and open source, in GitHub can find the source code, developers can according to their own needs combined with a variety of connection pool characteristics and performance to choose. This article is only to understand the learning pool technology, the realization of a simple database connection pool, if there are errors, but also hope to criticize correct.
Second, the design
Main classes and Interfaces
. Connectionparam- database Connection pool parameter class, which is responsible for configuring database connections and connection pool-related parameters. Use the builder implementation.
Driver URL user password-required to connect to the database
Minconnection-Minimum number of connections
Maxconnection-Maximum number of connections
Minidle-Minimum number of idle connections
Maxwait-Maximum wait time
Private final String driver;
Private final String URL;
Private final String user;
Private final String password;
private final int minconnection;
private final int maxconnection;
private final int minidle;
Private final long maxwait;
. ConnectionPool- Database connection pool
The ConnectionPool construction method is declared as protection and is not externally created and handed to connectionpoolfactory for unified management.
ConnectionPool implements the DataSource interface and Getconnection () method again.
ConnectionPool holds two containers-one queue stores idle connection, and the other vector (taking into account synchronization) stores the connection in use.
When the developer uses a database connection, it is fetched from the queue, not returned empty, and the vector is put back when the close connection is completed.
ConnectionPool provides a simple dynamic expansion mechanism based on minidle and maxconnection.
private static final int initial_size = 5;
private static final String Close_method = "close";
private static Logger Logger;
private int size;
Private Connectionparam Connectionparam;
Private arrayblockingqueue<connection> Idleconnectionqueue;
Private vector<connection> Busyconnectionvector;
. Connectionpoolfactory- Connection Pool management class
Connectionpoolfactory holds a static concurrenthashmap used to store connection pool objects.
Connectionpoolfactory allows you to create multiple connection pools with different configurations of different databases.
For the first time, the developer needs to register (BIND) the pool with a specific name, and then fetch connection from the specified connection pool each time.
If the connection pool is no longer in use, the developer can unregister (BIND) the connection pool.
private static map<string, connectionpool> Poolmap = new concurrenthashmap<> ();
public static Connection getconnection (String poolname) throws SQLException {namecheck
(poolname);
ConnectionPool ConnectionPool = Poolmap.get (poolname);
return connectionpool.getconnection ();
}
public static void Registerconnectionpool (String name, Connectionparam connectionparam) {
registercheck (name);
Poolmap.put (name, new ConnectionPool (Connectionparam));
Let-GC public
static void Unregisterconnectionpool (String name) {
namecheck (name);
Final ConnectionPool ConnectionPool = poolmap.get (name);
Poolmap.remove (name);
New Thread (New Runnable () {
@Override public
void Run () {
connectionpool.clear ();
}
}). Start ();
}
Core code
The
database connection pool Core code is the Getconnection () method, which typically calls the close () method after the developer has finished processing the database, connection should be shut down and released at this time. In the database connection pool, the user calls the close () method, should not directly shut down the connection, but to put back in the pool, re-use, where the use of Java Dynamic proxy mechanism, getconnection return is not "real" connection, Instead, the custom proxy class (where anonymous classes are used) is blocked and put back in the pool when the user calls the close () method. For dynamic proxies, see another blog, "Java Dynamic proxy simple application"
@Override public Connection getconnection () throws SQLException {try {final Con
Nection connection = Idleconnectionqueue.poll (Connectionparam.getmaxwait (), timeunit.milliseconds);
if (connection = = null) {Logger.info (emptymsg ());
Ensurecapacity ();
return null;
} busyconnectionvector.add (connection); Return (Connection) proxy.newproxyinstance (This.getclass (). getClassLoader (), New Class[]{connection.class}, new Invo Cationhandler () {@Override public object Invoke (Object Proxy, Method method, object[] args) throws Throwable
{if (!method.getname (). Equals (Close_method)) {return Method.invoke (connection, args);
else {idleconnectionqueue.offer (connection);
Busyconnectionvector.remove (connection);
return null;
}
}
});
catch (Interruptedexception e) {e.printstacktrace ();
return null; }
Second, the use
First, the user constructs the database connection pool parameter (connectionparam), including driver, url, user, password must, you can customize Minconnection, maxconnection, and other options, if not set, The system defaults are used, which is the benefit of using builder to build a large number of properties, including the required properties and optional attributes. The connection pool is then registered to the connectionpoolfactory using a specific name, and finally the connection is obtained by calling the Connectionpoolfactory static factory method.
String Driver = "Com.mysql.jdbc.Driver";
String url = "Jdbc:mysql://localhost:3306/test";
String user = "root";
String password = "root";
Connectionparam Connectionparam = new Connectionparam.connectionparambuilder (driver, url, user, password). build ();
Connectionpoolfactory.registerconnectionpool ("Test", Connectionparam);
Connection Connection = connectionpoolfactory.getconnection ("test");
Third, the Code
. Paramconfiguration
Package database.config;
Import java.io.Serializable;
/**
* DataBase Connection Parameters
* Created by Michael Wong on 2016/1/18.
* * Public
class Paramconfiguration implements Serializable {public
static final int min_connection = 5;
public static final int max_connection = m;
public static final int min_idle = 5;
public static final long max_wait = 30000;
Private Paramconfiguration () {}
}
. Builder
Package database;
/**
* Builder
* Created by Michael Wong on 2016/1/18.
*
/public interface builder<t> {
T build ();
}
. Connectionparam
Package database;
Import database.config.ParamConfiguration;
/** * DataBase Connection Parameters * Created by Michael Wong on 2016/1/18.
* * Public class Connectionparam {private final String driver;
Private final String URL;
Private final String user;
Private final String password;
private final int minconnection;
private final int maxconnection;
private final int minidle;
Private final long maxwait;
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 intGetminconnection () {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 implements Builder<connectionparam> {//Required parameters pri
Vate final String driver;
Private final String URL;
Private final String user;
Private final String password;
Optional parameters-initialized to default value private int minconnection = paramconfiguration.min_connection;
private int maxconnection = paramconfiguration.max_connection;
private int minidle = Paramconfiguration.min_idle;
Getting Connection wait time private long maxwait = paramconfiguration.max_wait;
Public Connectionparambuilder (string driver, string URL, string user, string password) {this.driver = driver;
This.url = URL;
This.user = user;
This.password = password; } public CoNnectionparambuilder minconnection (int minconnection) {this.minconnection = minconnection;
return this;
Public Connectionparambuilder maxconnection (int maxconnection) {this.maxconnection = maxconnection;
return this;
Public Connectionparambuilder minidle (int minidle) {this.minidle = Minidle;
return this;
Public Connectionparambuilder maxwait (int maxwait) {this.maxwait = maxwait;
return this;
@Override public Connectionparam Build () {return new Connectionparam (this);
}
}
}
. ConnectionPool
Package database.factory; Import Database.
Connectionparam;
Import Javax.sql.DataSource;
Import Java.io.PrintWriter;
Import Java.lang.reflect.InvocationHandler;
Import Java.lang.reflect.Method;
Import Java.lang.reflect.Proxy;
Import java.sql.Connection;
Import 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;
Import Java.util.logging.Logger;
/** * Connection Pool * Created by Michael Wong on 2016/1/18.
* * Public class ConnectionPool implements DataSource {private static final int initial_size = 5;
private static final String Close_method = "Close";
private static Logger Logger;
private int size;
Private Connectionparam Connectionparam;
Private arrayblockingqueue<connection> Idleconnectionqueue;
Private vector<connection> Busyconnectionvector; Protected ConnectionPool (Connectionparam ConnectIonparam) {this.connectionparam = Connectionparam;
int maxconnection = Connectionparam.getmaxconnection ();
Idleconnectionqueue = new 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 (
));
size++;
The catch (Exception e) {throw new Exceptionininitializererror (e); @Override public Connection getconnection () throws SQLException {try {final Connection Connection = Idlecon
Nectionqueue.poll (Connectionparam.getmaxwait (), timeunit.milliseconds); if (connection = = null) {Logger.info (emPtymsg ());
Ensurecapacity ();
return null;
} busyconnectionvector.add (connection); Return (Connection) proxy.newproxyinstance (This.getclass (). getClassLoader (), New Class[]{connection.class}, new Invo Cationhandler () {@Override public object Invoke (Object Proxy, Method method, object[] args) throws Throwable
{if (!method.getname (). Equals (Close_method)) {return Method.invoke (connection, args);
else {idleconnectionqueue.offer (connection);
Busyconnectionvector.remove (connection);
return null;
}
}
});
catch (Interruptedexception e) {e.printstacktrace ();
return null;
Private Connection Newconnection () throws SQLException {String url = connectionparam.geturl ();
String user = Connectionparam.getuser ();
String password = Connectionparam.getpassword ();
Return drivermanager.getconnection (URL, user, password);
protected int size () {return size; } protected inT idleconnectionquantity () {return idleconnectionqueue.size ();
} protected int busyconnectionquantity () {return busyconnectionvector.size ();
private void Ensurecapacity () throws 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 (n
Ewconnection ());
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 "The Database is busy, Please wait ... ";
@Override Public Connection getconnection (string Username, string password) throws SQLException {return null;
@Override public PrintWriter Getlogwriter () throws SQLException {return null; @Override public void Setlogwriter (PrintWriter out) throws SQLException {} @Override public void Setlogintimeou
T (int seconds) throws SQLException {} @Override public int getlogintimeout () throws SQLException {return 0;
@Override public Logger Getparentlogger () throws sqlfeaturenotsupportedexception {return null;
@Override public <T> T Unwrap (class<t> iface) throws SQLException {return null;
@Override public boolean iswrapperfor (Class<?> iface) throws SQLException {return false;
}
}
. Connectionpoolfactory
Package database.factory; Import Database.
Connectionparam;
Import java.sql.Connection;
Import java.sql.SQLException;
Import Java.util.Map;
Import Java.util.concurrent.ConcurrentHashMap;
/** * Connection Pool Factory * Created by Michael Wong on 2016/1/18. * * Public class Connectionpoolfactory {private Connectionpoolfactory () {} private static map<string, Connectionpoo
l> Poolmap = new concurrenthashmap<> ();
public static Connection getconnection (String poolname) throws SQLException {namecheck (poolname);
ConnectionPool ConnectionPool = Poolmap.get (poolname);
return Connectionpool.getconnection ();
public static void Registerconnectionpool (String name, Connectionparam connectionparam) {registercheck (name);
Poolmap.put (name, new ConnectionPool (Connectionparam));
}//Let GC public static void Unregisterconnectionpool (String name) {namecheck (name);
Final ConnectionPool ConnectionPool = poolmap.get (name);
Poolmap.remove (name); New Thread(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 (); The private static void Registercheck (String name) {if (name = = null) {throw new IllegalArgumentException (
)); } private static void Namecheck (String name) {if (name = = null) {throw new IllegalArgumentException (Nullname ()
);
} if (!poolmap.containskey (name)) {throw new IllegalArgumentException (notexists (name));
' Private static String Nullname () {return ' Pool name must ' not ' null '; private static String notexists (string name) {return"Connection pool named" + name + "does not exists";
}
}
Four, test
junit Unit test
Package database.factory; 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.*;
/** * Connectionpoolfactory Test * Created by Michael Wong on 2016/1/20. */public class Connectionpoolfactorytest {@Test public void testgetconnection () throws SQLException {String Drive
r = "Com.mysql.jdbc.Driver";
String url = "Jdbc:mysql://localhost:3306/test";
String user = "root";
String password = "root";
Connectionparam Connectionparam = new Connectionparam.connectionparambuilder (driver, url, user, password). build ();
Connectionpoolfactory.registerconnectionpool ("Test", Connectionparam);
list<connection> connectionlist = new arraylist<> ();
for (int i = 0; i < i++) {Connectionlist.add connectionpoolfactory.getconnection ("test");
} print ();
Close (connectionlist);
Print (); Connectionlist.clear();
for (int i = 0; i < i++) {Connectionlist.add connectionpoolfactory.getconnection ("test");
} print ();
Close (connectionlist);
Connectionpoolfactory.unregisterconnectionpool ("test"); @Test (expected = illegalargumentexception.class) public void TestException () {try {Connectionpoolfactory.getco
Nnection ("test");
catch (SQLException e) {e.printstacktrace (); } private void Close (List<connection> connectionlist) throws SQLException {for (Connection conn:connectionl
IST) {if (conn!= null) {conn.close (); }} private void Print () {SYSTEM.OUT.PRINTLN ("idle:" + connectionpoolfactory.getidleconnectionquantity ("test"))
;
System.out.println ("Busy:" + connectionpoolfactory.getbusyconnectionquantity ("test"));
SYSTEM.OUT.PRINTLN ("Size:" + connectionpoolfactory.size ("test"));
}
}
The above is the entire content of this article, I hope to help you learn.