package com.j256.db; import java.io.PrintWriter; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties; import java.util.logging.Logger; import javax.sql.DataSource; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; /** * A connection pool factory that creates pools that wraps a DataSource using two HikariCP connection pools -- one for * read-only connections and one for read-write connections. Really any connection pool should be improved with * something like this code. * *
* The whole point of this is to detect if a connection is read-only or read-write and allocate the connection from the * correct pool to lower JDBC overhead related to setting read status on the connection each time. *
* * @see http://256.com/gray/docs/misc/performance_optimizing_spring_hibernate_transactions/ * * @author graywatson */ public class ReadOnlyDetectingPooledDataSource implements DataSource { private static final long DEFAULT_CONNECTION_TIMEOUT_MILLIS = 5000; private static final int MINIMUM_READ_ONLY_POOL_SIZE = 1; private static final int MINIMUM_READ_WRITE_POOL_SIZE = 1; private String url; private String user; private String password; private Properties dataSourceProperties; private boolean defaultAutoCommit; private DataSource dataSource; private String dataSourceClassName; private HikariDataSource readOnlyPooledDataSource; private HikariDataSource readWritePooledDataSource; public void initialize() { HikariConfig readOnlyConf = buildConfig(MINIMUM_READ_ONLY_POOL_SIZE, true); readOnlyPooledDataSource = new HikariDataSource(readOnlyConf); HikariConfig readWriteConf = buildConfig(MINIMUM_READ_WRITE_POOL_SIZE, false); readWritePooledDataSource = new HikariDataSource(readWriteConf); } @Override public Connection getConnection() { return new ReadOnlyDetectingConnection(readOnlyPooledDataSource, readWritePooledDataSource, null, null); } @Override public Connection getConnection(String username, String password) { return new ReadOnlyDetectingConnection(readOnlyPooledDataSource, readWritePooledDataSource, username, password); } @Override public int getLoginTimeout() throws SQLException { // both pools have the same settings so we just get from the read-only one return readOnlyPooledDataSource.getLoginTimeout(); } @Override public void setLoginTimeout(int seconds) throws SQLException { readOnlyPooledDataSource.setLoginTimeout(seconds); readWritePooledDataSource.setLoginTimeout(seconds); } @Override public PrintWriter getLogWriter() throws SQLException { // both pools have the same settings so we just get from the read-only one return readOnlyPooledDataSource.getLogWriter(); } @Override public void setLogWriter(PrintWriter out) throws SQLException { readOnlyPooledDataSource.setLogWriter(out); readWritePooledDataSource.setLogWriter(out); } @Override public boolean isWrapperFor(Class> iface) throws SQLException { // both pools have the same settings so we just get from the read-only one return readOnlyPooledDataSource.isWrapperFor(iface); } @Override public