1. Введение
Технология объединения широко используется на Java. Короче говоря, он использует пул объектов для хранения экземпляра с ограниченным количеством экземпляров. Разработчики получают экземпляры из пула объектов, а затем переключаются обратно в пул объектов после использования, тем самым уменьшая накладные расходы частого создания объектов и в определенной степени уничтожая объекты. Пул потоков Java и пул соединений базы данных являются типичными приложениями, но не все объекты подходят для объединения. Объединение объектов с относительно небольшими накладными расходами повлияет на производительность, потому что поддержание пулов объектов также требует определенных накладных расходов. Для объектов с высоким накладным расходом и частым созданием и использованием использования, использование технологии объединения значительно улучшит производительность.
В отрасли есть много зрелых пулов подключений к базе данных, таких как C3P0, DBCP, Proxool и Druid's Alibaba. Есть много и с открытым исходным кодом, и вы можете найти исходный код на GitHub. Разработчики могут выбирать на основе своих собственных потребностей, их характеристик и производительности. Эта статья просто для того, чтобы понять технологию объединения обучения и внедрить простой пул соединений базы данных. Если есть какие -либо ошибки, я надеюсь критиковать и исправить их.
2. Дизайн
Основные классы и интерфейсы
.ConnectionParam - Класс пула подключений базы данных, ответственный за настройку подключений базы данных и параметров, связанных с пулом соединений. Реализация с использованием строителя.
Пароль пользователя URL -адреса драйвера - необходимо подключиться к базе данных
MinConnection - минимальное количество соединений
maxconnection - максимальное количество соединений
Минидл - минимальное количество холостовых соединений
MAXWAIT - максимальное время ожидания
частный драйвер финальной строки; частная финальная строка URL; Приватная конечная строка пользователь; Приватный пароль финальной строки; Частный финал Int Minconnection; Частный финал int maxconnection; Частный финальный Minidle; Частный финальный длинный макс -сат;
.ConnectionPool - Пул соединений базы данных
Конструктор ConnectionPool объявляется защитой, запрещает внешнее создание и управляется равномерно с помощью ConnectPoolFactory.
ConnectionPool реализует интерфейс DataSource и метод regetConnection ().
ConnectionPool содержит два контейнера - одна очередь хранит соединение холостого хода, а другой вектор (с учетом синхронизации) сохраняет используемое соединение.
Когда разработчик использует подключение к базе данных, оно извлекается из очереди, и если нет, он возвращается пустым; Когда закрытое соединение будет завершено, оно возвращается в вектор.
ConnectionPool обеспечивает простой механизм динамического расширения, основанный на Minidle и MaxConnection.
Приватный статический конечный int initial_size = 5; Частная статическая конечная строка Blose_method = "close"; частный статический регистратор регистрации; частный размер Int; Private ConnectionParam ConnectionParam; Private Arrayblockingqueue <necect> idleconnectionQueue; Частный вектор <necection> busyconnectionVector;
.ConnectionPoolFactory - класс управления пулом соединений
ConnectionPoolfactory содержит статический concurrenthashmap для хранения объектов пула соединений.
ConnectionPoolfactory позволяет создавать несколько пул соединений с различными конфигурациями различных баз данных.
Разработчик должен впервые зарегистрировать (связывать) пул соединений с определенным именем, а затем каждый раз получать соединение из указанного пула соединений.
Если пул соединений больше не используется, разработчик может выходить (раскрыть) пул соединений.
Частная статическая карта <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)); } // Пусть GC public void unregisterConnectionPool (string name) {nameCheck (name); окончательное соединение connectionPool = poolmap.get (name); poolmap.remove (имя); новый поток (new Runnable () {@Override public void run () {connectionPool.clear ();}}). start (); }Основной код
Основной код пула соединений базы данных находится в методе getConnection (). Обычно, после того, как разработчик обработал операции базы данных, будет вызван метод Close (). Соединение должно быть закрыто, а ресурсы должны быть выпущены. В пуле подключения к базе данных, когда пользователь вызывает метод Close (), соединение не должно быть закрыто напрямую, но должно быть помещено обратно в пул и повторно используется. Здесь используется динамический прокси -механизм Java. GetConnection возвращает не «реальное» соединение, а пользовательский класс прокси (здесь используется анонимный класс). Когда пользователь вызывает метод Close (), он перехватывает и помещает его обратно в бассейн. Для динамического прокси вы можете ссылаться на другой блог "Java Dynamic Proxy Simple Application"
@Override public connection getConnection () throws sqlexception {try {final connection connection = idleconnectionqueue.poll (connectionparam.getmaxwait (), timeunit.milliseconds); if (connection == null) {logger.info (umptyMsg ()); EncureCapacity (); вернуть ноль; } busyConnectionVector.Add (Connection); return (connection) proxy.newProxyInstance (this.getClass (). getClassLoader (), новый класс [] {connection.class}, new vocolationHandler () {@override public object veloke (Object Proxy, метод метода, объект [] args) throwable {if (! Method.getName (). Equall (Quall_method {atemplocke. Args); } catch (прерванное искусство e) {e.printstacktrace (); } return null; }2. Используйте
Во -первых, пользователь создает параметры пула подключений базы данных (ConnectionParam), включая драйвер, URL, пользователь, необходимые пароль. Вы можете настроить такие параметры, как MinConnection, MaxConnection и т. Д. Если не установлено, используйте значение системы по умолчанию. Это преимущество использования Builder для создания большого количества атрибутов, включая необходимые атрибуты и дополнительные атрибуты. Затем зарегистрируйте пул соединений с помощью ConnectionPoolfactory с определенным именем и, наконец, получите соединение, вызывая метод статического завода ConnectionPoolfactory.
String Driver = "com.mysql.jdbc.driver"; String url = "jdbc: mysql: // localhost: 3306/test"; String user = "root"; String password = "root"; ConnectionParam ConnectionParam = new ConnectionParam.connectionParambuilder (драйвер, URL, пользователь, пароль) .build (); ConnectionPoolfactory.RegisterConnectionPool ("test", ConnectionParam); Connection Connection = ConnectionPoolfactory.getConnection ("test");3. код
.ParamConfiguration
DASTABASE PACKES.CONFIG; Import java.io.serializable;/** * Параметры подключения базы данных * Созданы Майклом Вонгом 1/1/18. */paramconfiguration paramconfiguration of Serializable {public static infot int min_connection = 5; Public Static Final int max_connection = 50; Public Static Final int min_idle = 5; общественный статический последний длинный MAX_WAIT = 30000; private paramconfiguration () {}}.BUIDER
База данных пакетов;/** * Builder * Создан Майклом Вонгом 1/1/18. */Public Interface Builder <t> {t build ();}.ConnectionParam
База данных пакетов; Import Database.config.paramConfiguration;/** * Параметры подключения базы данных * Созданы Майклом Вонгом 1/1/18. */public Class ConnectionParam {Private Final String Driver; частная финальная строка URL; Приватная конечная строка пользователь; Приватный пароль финальной строки; Частный финал Int Minconnection; Частный финал int maxconnection; Частный финальный Minidle; Частный финальный длинный макс -сат; Private ConnectionParam (ConnectAparbuilder 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 ConnectionParumbuilder реализует Builder <NeplyParam> {// Требуемые параметры Приватный драйвер финальной строки; частная финальная строка URL; Приватная конечная строка пользователь; Приватный пароль финальной строки; // Необязательные параметры - инициализировано к значению по умолчанию private int minconnection = paramconfiguration.min_connection; private int maxconnection = paramconfiguration.max_connection; private int minidle = paramconfiguration.min_idle; // Получение времени ожидания подключения Private Long MAXWAIT = PARAMCONFIGUTURE.MAX_WAIT; public connectionParambuilder (строковый драйвер, строковый URL, строковый пользователь, String Password) {this.driver = Driver; this.url = url; this.user = 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
пакет база данных. Factory; Import Database.connectionParam; Import javax.sql.datasource; импорт java.io.printwriter; import java.lang.reflect.invocationHandler; импорт java.lang.reflect.method; импорт java.lang.reflect.proxy; импорт. java.sql.drivermanager; import java.sql.sqlexception; импорт java.sql.sqlfeaturenotsupportedException; импорт java.util.vector; импорт java.util.concurrent.rayblockqueue; импорт java.util.concurrent.timeunit; * Пул соединений * Создан Майклом Вонгом 1/1/18. */public Class ConnectionPool реализует DataSource {Private Static Final int initial_size = 5; Частная статическая конечная строка Blose_method = "close"; частный статический регистратор регистрации; частный размер Int; Private ConnectionParam ConnectionParam; Private Arrayblockingqueue <necect> idleconnectionQueue; Частный вектор <necection> busyconnectionVector; Protected ConnectionPool (ConnectParam ConnectionParam) {this.ConnectionParam = ConnectionParam; int maxconnection = connectionParam.getMaxConnection (); idleconnectionqueue = new Arrayblockingqueue <> (maxconnection); BusyConnectionVector = новый вектор <> (); 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 (Exception e) {бросить новый ExceptionInitializerError (e); }} @Override public Connection getConnection () Throws SQLexception {try {final Connection Connection = idleconnection.poll (connectionParam.getMaxWait (), TimeUnit.milliseconds); if (connection == null) {logger.info (umptyMsg ()); EncureCapacity (); вернуть ноль; } busyConnectionVector.Add (Connection); return (connection) proxy.newProxyInstance (this.getClass (). getClassLoader (), новый класс [] {connection.class}, new vocolationHandler () {@override public object veloke (Object Proxy, метод метода, объект [] args) throwable {if (! Method.getName (). Equall (Quall_method {atemplocke. Args); } catch (прерванное искусство e) {e.printstacktrace (); } return null; } частное соединение NewConnection () Throws SQLexception {String url = connectionParam.getUrl (); String user = connectionParam.getUser (); String password = connectionParam.getPassword (); return Drivermanager.getConnection (URL, пользователь, пароль); } защищенный int size () {return size; } защищенный int idleconnectionquantity () {return idleconnectionqueue.size (); } защищенный 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 grovcount = 0; if (size <newcapacity) {try {for (int i = 0; i <newcapacity - size; i ++) {idleconnectionqueue.put (newConnection ()); GrowCount ++; }} catch (прерывание Exception e) {e.printStackTrace (); }} size = size + growCount; } защищенный void clear () {try {while (size--> 0) {connection connection = idleconnectionqueue.take (); connection.close (); }} catch (прерванное искусство | SQLEXCEPTION E) {e.printStackTrace (); }} private string emptymsg () {return »база данных занята, подождите ...»; } @Override public connection getConnection (String username, String password) Throws sqlexception {return null; } @Override public printWriter getLogWriter () бросает sqlexception {return null; } @Override public void setLogWriter (printWriter Out) Throws SQLexception {} @Override public void setlogintimeout (int seconds) throws sqlexception {} @override public int getLogintimeout () throws sqlexception {return 0; } @Override public logger getParentLogger () бросает sqlFeatUrenotSupportedException {return null; } @Override public <t> t unwrap (class <t> iface) бросает sqlexception {return null; } @Override public boolean iswrapperfor (class <?> Iface) бросает sqlexception {return false; }}.ConnectionPoolFactory
База данных пакетов. Factory; Import Database.connectionParam; Import java.sql.connection; импорт java.sql.sqlexception; import java.util.map; import java.util.concurrent.concurrenthashmap;/** * Подключаемые фабрики пула *, созданная Michael Wong на 2016/18/18. */public class connectionpoolfactory {private connectionpoolfactory () {} частная статическая карта <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)); } // Пусть GC public void unregisterConnectionPool (string name) {nameCheck (name); окончательное соединение connectionPool = poolmap.get (name); 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 (String name) {if (name == null) {throw new allogalargumentException (nullname ()); }} private static void nameCheck (string name) {if (name == null) {бросить new allogalargumentException (nullname ()); } if (! poolmap.containskey (name)) {бросить новый allosalargumentException (notexists (name)); }} частная статическая строка nullname () {return "Имя пула не должно быть null"; } частная статическая строка notexists (string name) {return "Pool Connection Pool" + name + "не существует"; }} 4. Тест
Юнит -блок -тестирование
База данных пакетов. Factory; Import Database.connectionParam; Import org.junit.test; импорт java.sql.connection; import java.sql.sqlexception; импорт java.util.arraylist; import java.util.list; импорт Static Org.shray.assert.*************** */public class connectionpoolfactorytest {@test public void testgetConnection () throws sqlexception {string driver = "com.mysql.jdbc.driver"; String url = "jdbc: mysql: // localhost: 3306/test"; String user = "root"; String password = "root"; ConnectionParam ConnectionParam = new ConnectionParam.connectionParambuilder (драйвер, URL, пользователь, пароль) .build (); ConnectionPoolfactory.RegisterConnectionPool ("test", ConnectionParam); List <Neply <Neply> connectist = new ArrayList <> (); for (int i = 0; i <12; i ++) {connectist.add (connectionPoolfactory.getConnection ("test")); } print (); Close (список соединения); print (); connectist.clear (); for (int i = 0; i <12; i ++) {connectist.add (connectionPoolfactory.getConnection ("test")); } print (); Close (список соединения); ConnectionPoolfactory.unregisterConnectionPool ("test"); } @Test (weder = allogalargumentException.class) public void testexception () {try {connectionPoolfactory.getConnection ("test"); } catch (sqlexception e) {e.printstacktrace (); / }}} private void print () {System.out.println ("idle:" + connectionPoolfactory.getIdleConnectionQuantity ("test")); System.out.println ("Brassion:" + connectionPoolfactory.getBusyConnectionQuanty ("test")); System.out.println ("size:" + connectionpoolfactory.size ("test")); }}Выше приведено в этой статье, я надеюсь, что это будет полезно для каждого обучения.