BAEL-1818 - A Guide to Connection Pools in Java (#4735)
* Strange git issue with README.MD, wouldn't revert the file * Initial Commit * Initial Commit * Update pom.xml * Update pom.xml * Initial Commit * Update pom.xml * Update source files * Update source files * Update source files * Update source files * Update Application.java * Update pom.xml * Update HikariCPDataSourceUnitTest class * Update HikariCPDataSourceUnitTest.java * Update pom.xml * Update unit test classes * Update BasicConnectionPoolUnitTest.java * Fix indentation in DBCDDataSource class * Update DBCPDataSource.java * Update BasicConnectionPool class * Update BasicConnectionPool class * Update BasicConnectionPool.java * Update BasicConnectionPool.java * Update pom.xml * Update pom.xml * BAEL-1818 Refactored getConnection(), added shutdown(), cleaned up pom.xml * BAEL-1818 Removed getConnectionPool(), upgraded c3po version * BAEL-1818 Deleted obsolete connectionpool module * BAEL-1818 Deleted obsolete connectionpool module
This commit is contained in:
parent
86daa854d2
commit
ac801b4319
@ -1,5 +1,5 @@
|
|||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>com.baeldung</groupId>
|
<groupId>com.baeldung</groupId>
|
||||||
<artifactId>core-java</artifactId>
|
<artifactId>core-java</artifactId>
|
||||||
@ -73,9 +73,10 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.assertj</groupId>
|
<groupId>org.assertj</groupId>
|
||||||
<artifactId>assertj-core</artifactId>
|
<artifactId>assertj-core</artifactId>
|
||||||
<version>${assertj.version}</version>
|
<version>${assertj-core.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>commons-codec</groupId>
|
<groupId>commons-codec</groupId>
|
||||||
<artifactId>commons-codec</artifactId>
|
<artifactId>commons-codec</artifactId>
|
||||||
@ -146,6 +147,21 @@
|
|||||||
<artifactId>icu4j</artifactId>
|
<artifactId>icu4j</artifactId>
|
||||||
<version>${icu4j.version}</version>
|
<version>${icu4j.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-dbcp2</artifactId>
|
||||||
|
<version>${commons-dbcp2.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.zaxxer</groupId>
|
||||||
|
<artifactId>HikariCP</artifactId>
|
||||||
|
<version>${HikariCP.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.mchange</groupId>
|
||||||
|
<artifactId>c3p0</artifactId>
|
||||||
|
<version>${c3p0.version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
@ -301,7 +317,7 @@
|
|||||||
</arguments>
|
</arguments>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
@ -348,6 +364,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
<artifactId>exec-maven-plugin</artifactId>
|
<artifactId>exec-maven-plugin</artifactId>
|
||||||
|
<version>${exec-maven-plugin.version}</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<id>run-benchmarks</id>
|
<id>run-benchmarks</id>
|
||||||
@ -375,6 +392,7 @@
|
|||||||
</profiles>
|
</profiles>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
|
||||||
<!-- marshalling -->
|
<!-- marshalling -->
|
||||||
<jackson.version>2.8.5</jackson.version>
|
<jackson.version>2.8.5</jackson.version>
|
||||||
<gson.version>2.8.2</gson.version>
|
<gson.version>2.8.2</gson.version>
|
||||||
@ -395,16 +413,23 @@
|
|||||||
<vavr.version>0.9.0</vavr.version>
|
<vavr.version>0.9.0</vavr.version>
|
||||||
|
|
||||||
<!-- testing -->
|
<!-- testing -->
|
||||||
<assertj.version>3.6.1</assertj.version>
|
<assertj-core.version>3.10.0</assertj-core.version>
|
||||||
|
|
||||||
|
<!-- JDBC pooling frameworks -->
|
||||||
|
<commons-dbcp2.version>2.4.0</commons-dbcp2.version>
|
||||||
|
<HikariCP.version>3.2.0</HikariCP.version>
|
||||||
|
<c3p0.version>0.9.5.2</c3p0.version>
|
||||||
|
|
||||||
<!-- maven plugins -->
|
<!-- maven plugins -->
|
||||||
<maven-surefire-plugin.version>2.19.1</maven-surefire-plugin.version>
|
<maven-surefire-plugin.version>2.19.1</maven-surefire-plugin.version>
|
||||||
<springframework.spring-web.version>4.3.4.RELEASE</springframework.spring-web.version>
|
<springframework.spring-web.version>4.3.4.RELEASE</springframework.spring-web.version>
|
||||||
<springframework.boot.spring-boot-starter.version>1.5.8.RELEASE</springframework.boot.spring-boot-starter.version>
|
<springframework.boot.spring-boot-starter.version>1.5.8.RELEASE</springframework.boot.spring-boot-starter.version>
|
||||||
|
|
||||||
<javamoney.moneta.version>1.1</javamoney.moneta.version>
|
<javamoney.moneta.version>1.1</javamoney.moneta.version>
|
||||||
<h2database.version>1.4.197</h2database.version>
|
<h2database.version>1.4.197</h2database.version>
|
||||||
<esapi.version>2.1.0.1</esapi.version>
|
<esapi.version>2.1.0.1</esapi.version>
|
||||||
<jmh-core.version>1.19</jmh-core.version>
|
<jmh-core.version>1.19</jmh-core.version>
|
||||||
|
|
||||||
<jmh-generator-annprocess.version>1.19</jmh-generator-annprocess.version>
|
<jmh-generator-annprocess.version>1.19</jmh-generator-annprocess.version>
|
||||||
<maven-javadoc-plugin.version>3.0.0-M1</maven-javadoc-plugin.version>
|
<maven-javadoc-plugin.version>3.0.0-M1</maven-javadoc-plugin.version>
|
||||||
<javax.mail.version>1.5.0-b01</javax.mail.version>
|
<javax.mail.version>1.5.0-b01</javax.mail.version>
|
||||||
@ -412,7 +437,8 @@
|
|||||||
<onejar-maven-plugin.version>1.4.4</onejar-maven-plugin.version>
|
<onejar-maven-plugin.version>1.4.4</onejar-maven-plugin.version>
|
||||||
<maven-shade-plugin.version>3.1.1</maven-shade-plugin.version>
|
<maven-shade-plugin.version>3.1.1</maven-shade-plugin.version>
|
||||||
<spring-boot-maven-plugin.version>2.0.3.RELEASE</spring-boot-maven-plugin.version>
|
<spring-boot-maven-plugin.version>2.0.3.RELEASE</spring-boot-maven-plugin.version>
|
||||||
|
<exec-maven-plugin.version>1.6.0</exec-maven-plugin.version>
|
||||||
<icu4j.version>61.1</icu4j.version>
|
<icu4j.version>61.1</icu4j.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
@ -0,0 +1,87 @@
|
|||||||
|
package com.baeldung.connectionpool.connectionpools;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.DriverManager;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class BasicConnectionPool implements ConnectionPool {
|
||||||
|
|
||||||
|
private final String url;
|
||||||
|
private final String user;
|
||||||
|
private final String password;
|
||||||
|
private final List<Connection> connectionPool;
|
||||||
|
private final List<Connection> usedConnections = new ArrayList<>();
|
||||||
|
private static final int INITIAL_POOL_SIZE = 10;
|
||||||
|
private final int MAX_POOL_SIZE = 20;
|
||||||
|
|
||||||
|
public static BasicConnectionPool create(String url, String user, String password) throws SQLException {
|
||||||
|
List<Connection> pool = new ArrayList<>(INITIAL_POOL_SIZE);
|
||||||
|
for (int i = 0; i < INITIAL_POOL_SIZE; i++) {
|
||||||
|
pool.add(createConnection(url, user, password));
|
||||||
|
}
|
||||||
|
return new BasicConnectionPool(url, user, password, pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BasicConnectionPool(String url, String user, String password, List<Connection> connectionPool) {
|
||||||
|
this.url = url;
|
||||||
|
this.user = user;
|
||||||
|
this.password = password;
|
||||||
|
this.connectionPool = connectionPool;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Connection getConnection() throws SQLException {
|
||||||
|
if (connectionPool.size() == 0) {
|
||||||
|
if (usedConnections.size() < MAX_POOL_SIZE) {
|
||||||
|
connectionPool.add(createConnection(url, user, password));
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Maximum pool size reached, no available connections!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connection connection = connectionPool.remove(connectionPool.size() - 1);
|
||||||
|
usedConnections.add(connection);
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean releaseConnection(Connection connection) {
|
||||||
|
connectionPool.add(connection);
|
||||||
|
return usedConnections.remove(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Connection createConnection(String url, String user, String password) throws SQLException {
|
||||||
|
return DriverManager.getConnection(url, user, password);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSize() {
|
||||||
|
return connectionPool.size() + usedConnections.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdown() throws SQLException {
|
||||||
|
for (Connection c : usedConnections) {
|
||||||
|
this.releaseConnection(c);
|
||||||
|
}
|
||||||
|
for (Connection c : connectionPool) {
|
||||||
|
c.close();
|
||||||
|
}
|
||||||
|
connectionPool.clear();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package com.baeldung.connectionpool.connectionpools;
|
||||||
|
|
||||||
|
import com.mchange.v2.c3p0.ComboPooledDataSource;
|
||||||
|
import java.beans.PropertyVetoException;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
public class C3poDataSource {
|
||||||
|
|
||||||
|
private static final 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) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Connection getConnection() throws SQLException {
|
||||||
|
return cpds.getConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
private C3poDataSource(){}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.baeldung.connectionpool.connectionpools;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface ConnectionPool {
|
||||||
|
|
||||||
|
Connection getConnection() throws SQLException;
|
||||||
|
|
||||||
|
boolean releaseConnection(Connection connection);
|
||||||
|
|
||||||
|
String getUrl();
|
||||||
|
|
||||||
|
String getUser();
|
||||||
|
|
||||||
|
String getPassword();
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package com.baeldung.connectionpool.connectionpools;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import org.apache.commons.dbcp2.BasicDataSource;
|
||||||
|
|
||||||
|
public class DBCPDataSource {
|
||||||
|
|
||||||
|
private static final 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(){}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package com.baeldung.connectionpool.connectionpools;
|
||||||
|
|
||||||
|
import com.zaxxer.hikari.HikariConfig;
|
||||||
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
public class HikariCPDataSource {
|
||||||
|
|
||||||
|
private static final HikariConfig config = new HikariConfig();
|
||||||
|
private static final 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(){}
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
package com.baeldung.connectionpool;
|
||||||
|
|
||||||
|
import com.baeldung.connectionpool.connectionpools.BasicConnectionPool;
|
||||||
|
import com.baeldung.connectionpool.connectionpools.ConnectionPool;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.List;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class BasicConnectionPoolUnitTest {
|
||||||
|
|
||||||
|
private static ConnectionPool connectionPool;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUpBasicConnectionPoolInstance() throws SQLException {
|
||||||
|
connectionPool = BasicConnectionPool.create("jdbc:h2:mem:test", "user", "password");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenBasicConnectionPoolInstance_whenCalledgetConnection_thenCorrect() throws Exception {
|
||||||
|
assertTrue(connectionPool.getConnection().isValid(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenBasicConnectionPoolInstance_whenCalledreleaseConnection_thenCorrect() throws Exception {
|
||||||
|
Connection connection = connectionPool.getConnection();
|
||||||
|
assertThat(connectionPool.releaseConnection(connection)).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenBasicConnectionPoolInstance_whenCalledgetUrl_thenCorrect() {
|
||||||
|
assertThat(connectionPool.getUrl()).isEqualTo("jdbc:h2:mem:test");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenBasicConnectionPoolInstance_whenCalledgetUser_thenCorrect() {
|
||||||
|
assertThat(connectionPool.getUser()).isEqualTo("user");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenBasicConnectionPoolInstance_whenCalledgetPassword_thenCorrect() {
|
||||||
|
assertThat(connectionPool.getPassword()).isEqualTo("password");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = RuntimeException.class)
|
||||||
|
public void givenBasicConnectionPoolInstance_whenAskedForMoreThanMax_thenError() throws Exception {
|
||||||
|
// this test needs to be independent so it doesn't share the same connection pool as other tests
|
||||||
|
ConnectionPool cp = BasicConnectionPool.create("jdbc:h2:mem:test", "user", "password");
|
||||||
|
final int MAX_POOL_SIZE = 20;
|
||||||
|
for (int i = 0; i < MAX_POOL_SIZE + 1; i++) {
|
||||||
|
cp.getConnection();
|
||||||
|
}
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenBasicConnectionPoolInstance_whenSutdown_thenEmpty() throws Exception {
|
||||||
|
ConnectionPool cp = BasicConnectionPool.create("jdbc:h2:mem:test", "user", "password");
|
||||||
|
assertThat(((BasicConnectionPool)cp).getSize()).isEqualTo(10);
|
||||||
|
|
||||||
|
((BasicConnectionPool) cp).shutdown();
|
||||||
|
assertThat(((BasicConnectionPool)cp).getSize()).isEqualTo(0);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package com.baeldung.connectionpool;
|
||||||
|
|
||||||
|
import com.baeldung.connectionpool.connectionpools.C3poDataSource;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class C3poDataSourceUnitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenC3poDataSourceClass_whenCalledgetConnection_thenCorrect() throws SQLException {
|
||||||
|
assertTrue(C3poDataSource.getConnection().isValid(1));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package com.baeldung.connectionpool;
|
||||||
|
|
||||||
|
import com.baeldung.connectionpool.connectionpools.DBCPDataSource;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class DBCPDataSourceUnitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenDBCPDataSourceClass_whenCalledgetConnection_thenCorrect() throws SQLException {
|
||||||
|
assertTrue(DBCPDataSource.getConnection().isValid(1));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package com.baeldung.connectionpool;
|
||||||
|
|
||||||
|
import com.baeldung.connectionpool.connectionpools.HikariCPDataSource;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class HikariCPDataSourceUnitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenHikariDataSourceClass_whenCalledgetConnection_thenCorrect() throws SQLException {
|
||||||
|
assertTrue(HikariCPDataSource.getConnection().isValid(1));
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user