
com.github.hypfvieh.db.SimpleDatabaseConnector Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of java-utils Show documentation
Show all versions of java-utils Show documentation
A collection of utils commonly used in my projects.
Feel free to use it (or parts of it) in your own projects.
The newest version!
package com.github.hypfvieh.db;
import java.io.InvalidClassException;
import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLRecoverableException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.hypfvieh.util.StringUtil;
import com.github.hypfvieh.util.TypeUtil;
/**
* Simple class to allow connection to any JDBC compatible database.
* Allows to send any SQL statement to the database as well as retrieving data (SELECT) from a database in a List-of-Map format.
*
* All columns selected will be accessible by iterating through the list of maps.
* Each item of the list represents one row as HashMap where each key is one column.
* Column names are case insensitive!
*
* It allows caching of retrieved DB results in JSON format. If caching is enabled it will automatically use the offline cache if
* database is unreachable.
*
* One instance of {@link SimpleDatabaseConnector} can store multiple select queries in offline cache (map of SQL-Query(key) and Result (value)).
*
* Sample Usage:
*
*
* {@code
IDatabaseConnector sdc = newSqlConnectorInstance(getDatabaseConnectionParameters("EnxMasterdata"), true); // use false to disable cache
if (sdc.openDatabase() || sdc.isOffline()) { // if cache is disabled you should stop if isOffline() == true
List<Map<String, String>> selectedRows = sdc.executeSelectQuery(true, sqlGattungString);
for (Map<String, String> tableEntry : selectedRows) {
isin2enx.put(tableEntry.get("isin"), tableEntry.get("enx_code"));
}
}
}
*
*
* @author hypfvieh
* @since 1.0.1
*/
public class SimpleDatabaseConnector {
private final Logger logger;
private final AtomicInteger connectionRetries;
private boolean dbOpen = false;
private boolean supportsBatch = false;
private DbConnParms connectionParams = null;
private Connection dbConnection = null;
public SimpleDatabaseConnector(DbConnParms _connectionParams) {
if (_connectionParams == null) {
throw new IllegalArgumentException("Database connection parameters cannot be null.");
}
logger = LoggerFactory.getLogger(getClass());
dbOpen = false;
connectionParams = _connectionParams;
connectionRetries = new AtomicInteger(0);
}
/**
* Trys to open a connection to the given database parameters.
* Returns true if connection could be established, false otherwise.
*
* Throws InvalidClassException if given SQL-Driver is not JDBC compatible.
* Throws ClassNotFoundException if given SQL-Driver class could not be found.
* Throws SQLException on any connection error.
*
* @return true if connected, false otherwise
* @throws InvalidClassException if class is not a java.sql.Driver derivative
* @throws ClassNotFoundException if class could not be found
*/
public final synchronized boolean openDatabase() throws InvalidClassException, ClassNotFoundException {
if (dbOpen) {
logger.warn("Connection to database already opened.");
return dbOpen;
}
Class> driverClazz;
try {
driverClazz = Class.forName(connectionParams.getDriverClassName());
Object driverInstance = driverClazz.getDeclaredConstructor().newInstance();
if (!(driverInstance instanceof Driver)) {
logger.error("{} does not implement java.sql.Driver interface!", connectionParams.getDriverClassName());
throw new InvalidClassException(connectionParams.getDriverClassName() + " does not implement java.sql.Driver interface!");
}
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException | NoSuchMethodException | SecurityException _ex) {
logger.error("Cannot instanciate database driver: " + connectionParams.getDriverClassName(), _ex);
}
// open the connection or switch to offline mode if connection fails
openConnection();
if (dbOpen && dbConnection != null) {
// if database could be opened, check if we can use batch processing, as it is much faster
try {
if (dbConnection.getMetaData().supportsBatchUpdates()) {
supportsBatch = true;
}
} catch (SQLException _ex) {
logger.info("Could not determine if database supports batch update feature.", _ex);
}
}
return dbOpen;
}
/**
* This method opens the DB connection.
* If this fails and file caching is allowed, {@link #offline} mode will be enabled and null is returned.
* @return Connection or null
*/
private void openConnection() {
try {
dbConnection = DriverManager.getConnection(connectionParams.getUrl(), connectionParams.getUser(), connectionParams.getPassword());
dbOpen = true;
logger.debug("Connection to database at: {} established", connectionParams.getUrl());
} catch (SQLRecoverableException _ex) { // is thrown if connection could not be established, so we may retry connection
if (connectionRetries.incrementAndGet() > connectionParams.getMaxRetries()) {
logger.error("Connection could not be established within {} attempts, url={}", connectionParams.getMaxRetries(), connectionParams.getUrl());
} else {
logger.error("Connection could not be established. Reconnection attempt #{} of {}, url={}, exception={}", connectionRetries.get(), connectionParams.getMaxRetries(), connectionParams.getUrl(), _ex.getMessage());
openConnection();
}
} catch (SQLException _ex) {
logger.error("Database at [{}] could not be opened and offline cache was disabled.", connectionParams.getUrl());
// if debug logging is enabled, print exception as well (may help analyzing issues)
logger.debug("Exception was: ", _ex);
}
}
public Connection getDbConnection() {
return dbConnection;
}
/**
* Closes the database connection if it was previously connected.
* @throws SQLException if closing fails
*/
public synchronized void closeDatabase() throws SQLException {
if (dbConnection != null) {
dbConnection.close();
}
dbOpen = false;
}
/**
* Returns true if database has been opened.
* @return true if open, false otherwise
*/
public synchronized boolean isDbOpen() {
return dbOpen;
}
/**
* Run update/inserts as batch update.
* Will fallback to sequential insert/update if database implemenation does not support batch.
*
* Attention: Do not use batch when calling stored procedures in oracle databases, as this is not supported by oracle and will not work.
*
* @param _sqlQuery sql query to use (with '?' placeholders)
* @param _sqlParameters an array of values for replacing '?' placeholders in query
* @param _batchSize batch size to use
* @return true on successful execution, false if any error occurred
*/
public synchronized boolean executeBatchQuery(String _sqlQuery, List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy