My DBCP configuration keeps creating new connections, so much that my MySQL server blocks it because of too many connections:
public class SQL {
private final static String DRIVER_CLASS_NAME = "com.mysql.jdbc.Driver";
private final static String USERNAME = "secret";
private final static String PASSWORD = "secret";
private final static String URL = "secret";
public static Connection getConnection() {
BasicDataSource basicDataSource = new BasicDataSource();
basicDataSource.setDriverClassName(DRIVER_CLASS_NAME);
basicDataSource.setUrl(URL);
basicDataSource.setUsername(USERNAME);
basicDataSource.setPassword(PASSWORD);
try {
return basicDataSource.getConnection();
} catch (SQLException ex) {
Logger.getLogger(SQL.class.getName()).log(Level.SEVERE, null, ex);
throw new IllegalStateException("bf4.sql.SQL.getConnection: No connection could be made: " + ex.getMessage());
}
}
}
My xxxManager.java:
public class PlayerkillManager extends Manager<PlayerkillBean, PlayerkillConstraint> {
public PlayerkillManager() {
super(SQL.getConnection());
}
#Override
protected PreparedStatement insertPS(final PlayerkillBean playerkill) throws SQLException {
PreparedStatement ps = connection.prepareStatement("INSERT INTO playerkills (`date`, `playerId`, `targetId`, `weaponId`, `headshot`) VALUES(?, ?, ?, ?, ?)", PreparedStatement.RETURN_GENERATED_KEYS);
ps.setObject(1, playerkill.getDate());
ps.setObject(2, playerkill.getPlayerId());
ps.setObject(3, playerkill.getTargetId());
ps.setObject(4, playerkill.getWeaponId());
ps.setObject(5, playerkill.getHeadshot());
return ps;
}
#Override
protected PreparedStatement updatePS(final PlayerkillBean playerkill) throws SQLException {
throw new UnsupportedOperationException("There are no non-key columns in this table.");
}
#Override
protected PreparedStatement deletePS(final PlayerkillBean playerkill) throws SQLException {
PreparedStatement ps = connection.prepareStatement("DELETE FROM playerkills WHERE `id` = ? AND `date` = ? AND `playerId` = ? AND `targetId` = ? AND `weaponId` = ? AND `headshot` = ?");
ps.setObject(1, playerkill.getId());
ps.setObject(2, playerkill.getDate());
ps.setObject(3, playerkill.getPlayerId());
ps.setObject(4, playerkill.getTargetId());
ps.setObject(5, playerkill.getWeaponId());
ps.setObject(6, playerkill.getHeadshot());
return ps;
}
#Override
protected String searchQuery() {
return "SELECT `playerkills`.`id`, `playerkills`.`date`, `playerkills`.`playerId`, `playerkills`.`targetId`, `playerkills`.`weaponId`, `playerkills`.`headshot` FROM playerkills";
}
#Override
protected String tableName() {
return "playerkills";
}
#Override
protected String[] columnNames() {
return new String[] {
"id",
"date",
"playerId",
"targetId",
"weaponId",
"headshot",
};
}
#Override
protected Map<TableField, List<List<TableField>>> getPaths() {
//Function not interesting and too much code
}
#Override
protected PlayerkillBean createBean(final ResultSet rs) throws SQLException {
return new PlayerkillBean(rs);
}
}
Manager.java class:
public abstract class Manager<B extends Bean, C extends AbstractConstraint> implements Closeable {
protected final Connection connection;
public Manager(final Connection con) {
this.connection = con;
}
public final int insert(final B b) throws InsertException {
try {
try (PreparedStatement ps = insertPS(b)) {
ps.executeUpdate();
try (ResultSet rs = ps.getGeneratedKeys()) {
rs.last();
if (rs.getRow() != 0) {
rs.beforeFirst();
rs.next();
return rs.getInt(1);
}
else {
return -1;
}
}
}
} catch (SQLException ex) {
Logger.getLogger(Manager.class.getName()).log(Level.SEVERE, null, ex);
throw new InsertException(ex);
}
}
public final boolean update(final B b) throws UpdateException {
try {
try (PreparedStatement ps = updatePS(b)) {
return ps.execute();
}
} catch (SQLException ex) {
Logger.getLogger(Manager.class.getName()).log(Level.SEVERE, null, ex);
throw new UpdateException(ex);
}
}
public final boolean delete(final B b) throws DeleteException {
try {
try (PreparedStatement ps = deletePS(b)) {
return ps.execute();
}
} catch (SQLException ex) {
Logger.getLogger(Manager.class.getName()).log(Level.SEVERE, null, ex);
throw new DeleteException(ex);
}
}
public final B get(final AbstractConstraint... c) throws SearchException {
List<B> beans = search(c);
if (beans.size() == 1) {
return beans.get(0);
}
throw new IllegalArgumentException("orm.Manager.get: beans.size() != 1: beans.size() = " + beans.size());
}
public final List<B> search(final AbstractConstraint... c) throws SearchException {
if (c.length == 0) {
throw new IllegalArgumentException("orm.Manager.search: c.length == 0");
}
try {
List<B> beans = new ArrayList<>();
for (AbstractConstraint constraint : c) {
try (PreparedStatement ps = new QueryBuilder(connection, tableName(), getPaths(), searchQuery()).add(constraint).build();
ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
beans.add(createBean(rs));
}
}
}
if (c.length > 1) {
boolean sorting = true;
Field field = c[0].getField();
Order order = c[0].getOrder();
for (int i = 1; i < c.length; i++) {
Field currentField = c[i].getField();
Order currentOrder = c[i].getOrder();
if (!field.equals(currentField) || !order.equals(currentOrder)) {
sorting = false;
break;
}
}
if (sorting) {
//sort on field with comparator of supertype
}
}
return beans;
} catch (SQLException ex) {
Logger.getLogger(Manager.class.getName()).log(Level.SEVERE, null, ex);
throw new SearchException(ex);
}
}
public final List<B> getAll() throws SearchException {
return getAll(Order.NONE, null);
}
public final List<B> getAll(final Order order, final Field field) throws SearchException {
try {
List<B> beans = new ArrayList<>();
try (
PreparedStatement ps = connection.prepareStatement(searchQuery() + " " + orderQuery(order, field));
ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
beans.add(createBean(rs));
}
}
return beans;
} catch (SQLException ex) {
Logger.getLogger(Manager.class.getName()).log(Level.SEVERE, null, ex);
throw new SearchException(ex);
}
}
public final int getRowCount(final AbstractConstraint... c) throws SearchException {
return search(c).size();
}
#Override
public void close() {
//was uncommented?
try {
connection.close();
} catch (SQLException ex) {
Logger.getLogger(Manager.class.getName()).log(Level.SEVERE, null, ex);
}
}
private String orderQuery(final Order order, final Field field) {
if (order == Order.NONE) {
return "";
}
return "ORDER BY " + field.getFieldName() + " " + order.getOrdername();
}
abstract protected PreparedStatement insertPS(B b) throws SQLException;
abstract protected PreparedStatement updatePS(B b) throws SQLException;
abstract protected PreparedStatement deletePS(B b) throws SQLException;
abstract protected String searchQuery();
abstract protected String tableName();
abstract protected String[] columnNames();
abstract protected Map<TableField, List<List<TableField>>> getPaths();
abstract protected B createBean(ResultSet rs) throws SQLException;
}
Some statistics I have gathered:
Max concurrent connections: 152
Failed connections: 12
Aborted connections: 375
Total connections: 844
Number of insert queries: 373
I would have expected that 1 connection would have been used though, what is going wrong?
EDIT: To clarify, my code calls the xxxManager for example like this: playerkillManager.insert(new PlayerkillBean(...));
You are creating a new connection pool every time you call SQL.getConnection() which is not how connection pools should be used.
You should share a single javax.sql.DataSource (doc) around your application, not individual connections.
So, maybe you could change your code to:
public class SQL {
private final static String DRIVER_CLASS_NAME = "com.mysql.jdbc.Driver";
private final static String USERNAME = "secret";
private final static String PASSWORD = "secret";
private final static String URL = "secret";
private final static DataSource dataSource;
static {
BasicDataSource basicDataSource = new BasicDataSource();
basicDataSource.setDriverClassName(DRIVER_CLASS_NAME);
basicDataSource.setUrl(URL);
basicDataSource.setUsername(USERNAME);
basicDataSource.setPassword(PASSWORD);
dataSource = basicDataSource;
}
public static DataSource getDataSource() {
return dataSource;
}
}
Then in the rest of your classes, you can use that data source. Important things to remember are that DataSource.getConnection() borrows a connection from the pool and Connection.close() does not actually close the connection; calling close() returns the connection to the pool. If you fail to call Connection.close() on a borrowed connection you have a connection leak.
Your current code will need editing to use try-with-resources when borrowing the connection e.g.
public void foo() {
try (Connection conn = datasource.getConnection()) {
//your code here
} catch (SQLException e) {
e.printStackTrace();
}
}
Related
There are two methods in which the PreparedStatement is used.
The first method is called in the second method.
First method:
protected List<String> findResultsByMandantId(Long mandantId) {
List<String> resultIds = new ArrayList<>();
ResultSet rs;
String sql = "SELECT result_id FROM results WHERE mandant_id = ?";
PreparedStatement statement = getPreparedStatement(sql, false);
try {
statement.setLong(1, mandantId);
statement.execute();
rs = statement.getResultSet();
while (rs.next()) {
resultIds.add(rs.getString(1));
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
return resultIds;
}
Second method:
protected void findResultLineEntityToDelete(Long mandantId, String title, String context) {
List<String> resultIds = findResultsByMandantId(mandantId);
String [] resultIdsArr = resultIds.toArray(String[]::new);
ResultSet rs;
//String sql = "SELECT * FROM resultline WHERE result_id in (SELECT result_id FROM results WHERE mandant_id =" + mandantId + ")";
String sql = "SELECT * FROM resultline WHERE result_id in (" + String.join(", ", resultIdsArr)+ ")";
PreparedStatement statement = getPreparedStatement(sql, false);
try {
statement.execute();
rs = statement.getResultSet();
while (rs.next()) {
if (rs.getString(3).equals(title) && rs.getString(4).equals(context)) {
System.out.println("Titel: " + rs.getString(3) + " " + "Context: " + rs.getString(4));
}
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
The class in which both methods are located extends the JDBCBaseManager.
JDBCBaseManager:
private final String url = "jdbc:mysql://localhost:3306/database";
private final String userName = "root";
private final String password = "";
private Connection connection = null;
private PreparedStatement preparedStatement = null;
private int batchSize = 0;
public JDBCBaseManager() {
// Dotenv env = Dotenv.configure().directory("./serverless").load();
// url = env.get("DB_PROD_URL");
// userName = env.get("DB_USER");
// password = env.get("DB_PW");
}
public void getConnection() {
try {
if (connection == null) {
connection = DriverManager.getConnection(url, userName, password);
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public PreparedStatement getPreparedStatement(String sql, boolean returnGeneratedKeys) {
try {
if (connection == null) {
getConnection();
}
if (preparedStatement == null) {
if (!returnGeneratedKeys) {
preparedStatement = connection.prepareStatement(sql);
} else {
preparedStatement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
connection.setAutoCommit(false);
}
}
return preparedStatement;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public void closeConnection() {
try {
if (connection != null && !connection.isClosed()) {
System.out.println("Closing Database Connection");
connection.close();
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public void startBatch(int batchSize) throws SQLException {
connection.setAutoCommit(false);
setBatchSize(batchSize);
}
public void commit() {
try {
if (connection != null && !connection.isClosed()) {
connection.commit();
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
public int getBatchSize() {
return batchSize;
}
public void setBatchSize(int batchSize) {
this.batchSize = batchSize;
}
The ResultSet in the second method still contains the results from the first method.
I already tried to close the connection and open it again before the second method is executed, but then I get the errors:
java.sql.SQLException: No operations allowed after statement closed.
java.sql.SQLNonTransientConnectionException: No operations allowed
after connection closed.
Can you tell me how to deal with the statement correctly in this case? Is my BaseManager incorrectly structured?
Here lies the error
public JDBCBaseManager() {
private PreparedStatement preparedStatement = null;
public PreparedStatement getPreparedStatement(String sql, boolean returnGeneratedKeys) {
try {
......
if (preparedStatement == null) {
if (!returnGeneratedKeys) {
preparedStatement = connection.prepareStatement(sql);
} else {
preparedStatement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
connection.setAutoCommit(false);
}
}
return preparedStatement;
You build the prepare statement only the first time the method getPreparedStatement is called because only the first time the field preparedStatement is null. Every next time you call the method getPreparedStatement you receive the previous preparedStatement from the previous SQL and not the new one.
Remove the check for if (preparedStatement == null) {
You need to build a new preparedStatement every time you want to execute a new SQL.
I connect to Hive and get id's of my data from row of table. Problems does not happens, when I connect to hive, send request and get response. But when i get id's from ResultSet i get an exception: org.apache.thrift.transport.TTransportException: SASL authentication not complete. Why does this exception arise and what needs to be done to avoid it? Sorry for my bad english.
It's my subsidiary class to create hive connection and send requests:
public class HiveDataSearcher implements AutoCloseable {
private static final String hiveDriverName = "org.apache.hive.jdbc.HiveDriver";
static {
try {
Class.forName(hiveDriverName);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
private Connection hiveConnection;
private String tableName;
private String whereBody;
public HiveDataSearcher(String url, String login, String password) {
try {
hiveConnection = DriverManager.getConnection(url, login, password);
} catch (SQLException e) {
throw new RuntimeException(e);
}
this.tableName = "";
this.whereBody = "";
}
public HiveDataSearcher(Connection hiveConnection) {
Objects.requireNonNull(hiveConnection, "hiveConnection");
this.hiveConnection = hiveConnection;
this.tableName = "";
this.whereBody = "";
}
public String getTableName() {
return tableName;
}
public HiveDataSearcher setTableName(String tableName) {
Objects.requireNonNull(tableName, "tableName");
this.tableName = tableName;
return this;
}
public String getWhereBody() {
return whereBody;
}
public HiveDataSearcher setWhereBody(String whereBody) {
Objects.requireNonNull(whereBody, "whereBody");
this.whereBody = whereBody;
return this;
}
public ResultSet select(String ... selectParams) {
return select(Arrays.asList(selectParams));
}
public ResultSet select(Iterable<String> selectParams) {
String request = prepareRequest(selectParams);
ResultSet response;
try {
response = hiveConnection
.createStatement()
.executeQuery(request);
} catch (SQLException e) {
throw new RuntimeException(e);
}
return response;
}
private String prepareRequest(Iterable<String> selectParams) {
return new StringBuilder()
.append("select").append(' ').append(selectParamsToHiveFormat(selectParams)).append(' ')
.append("from").append(' ').append(tableName).append(' ')
.append("where").append(' ').append(whereBody)
.toString();
}
private String selectParamsToHiveFormat(Iterable<String> selectParams) {
StringBuilder formattedSelectParams = new StringBuilder();
for (String selectedParam : selectParams) {
formattedSelectParams.append('\'').append(selectedParam).append('\'').append(',');
}
if (formattedSelectParams.length() == 0) {
formattedSelectParams.append('*');
} else {
formattedSelectParams.deleteCharAt(formattedSelectParams.length() - 1);
}
return formattedSelectParams.toString();
}
public void close() {
if (hiveConnection != null) {
try {
hiveConnection.close();
} catch (SQLException e) {
//nothing to do, just close connection
} finally {
hiveConnection = null;
}
}
}
}
This is the code in which i connect to hive:
private static final String HIVE_URL = <hive url>;
private static final String HIVE_LOGIN = <hive login>;
private static final String HIVE_PASSWORD = <hive password>;
private static final String[] SEARCH_FIELDS = new String[] {"rowkey"};
private List<String> getIdsFromHive(String tableName, String whereBody) {
ResultSet hiveResponse;
try (HiveDataSearcher searcher = new HiveDataSearcher(HIVE_URL, HIVE_LOGIN, HIVE_PASSWORD)) {
hiveResponse = searcher
.setTableName(tableName)
.setWhereBody(whereBody)
.select(SEARCH_FIELDS);
}
List<String> ids = new ArrayList<>();
try {
while (hiveResponse.next()) { // in this place throw TTransportException
ids.add(hiveResponse.getString(SEARCH_FIELDS[0]));
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
return ids;
}
In my case, the reason for this exception is closed the connection before closed the statement. So I suggest you to check whether you has maintain the connection correctly.
Here is my code, wish it will inspire you something:
Wrong code, close connection before closing the statement:
Connection connection = null;
Statement statement = null;
try {
connection = HIVEUTILS.getConnection();
statement = connection.createStatement();
statement.execute("DROP TABLE IF EXISTS tbl1");
statement.execute("CREATE TABLE `tbl1` (`id` int)");
statement.execute("INSERT INTO tbl1 VALUES(1)");
}finally {
if (connection != null){
connection.close();
}
if (statement != null){
statement.close(); // exception occur here.
}
}
The correct order of closing is: close resultSet(if any) -> close statement -> close connection.
Connection connection = null;
Statement statement = null;
try {
connection = HIVEUTILS.getConnection();
statement = connection.createStatement();
statement.execute("DROP TABLE IF EXISTS tbl1");
statement.execute("CREATE TABLE `tbl1` (`id` int)");
statement.execute("INSERT INTO tbl1 VALUES(1)");
}finally {
if (statement != null){
statement.close(); // change the order
}
if (connection != null){
connection.close();
}
}
I been trying to develop a Minecraft server plugin where a player enters a command with some data, data is sent to database, or, a command that requests some data from database.
It's working, until a user starts using it more then a few times. I get a leakdetection error:
[HikariPool-2 housekeeper] WARN com.zaxxer.hikari.pool.ProxyLeakTask - Connection leak detection triggered for com.mysql.jdbc.JDBC4Connection#abc6eb, stack trace follows
[23:36:11 WARN]: java.lang.Exception: Apparent connection leak detected
Or I get an error that tells me that I have too many connections. (Sorry, I don't have that error at this moment)
This is the gist of my code. What am I doing improperly?
public class MochaModel {
private Latte instance = Latte.getInstance();
private Connection connection;
public MochaModel() {
}
public void createTable() {
BukkitRunnable r = new BukkitRunnable() {
#Override
public void run() {
try {
connection = Database.getConnection();
if (connection != null) {
String sql = "CREATE TABLE IF NOT EXISTS `mocha` ( " +
" `id` INT NOT NULL AUTO_INCREMENT ," +
"`uuid` VARCHAR(255) NOT NULL ," +
" `join_message` VARCHAR(255) NOT NULL ," +
" `quit_message` VARCHAR(255) NOT NULL ," +
" `change_points` INT NOT NULL," +
" `last_modified` TIMESTAMP NOT NULL," +
" PRIMARY KEY (`id`)" +
")";
PreparedStatement q = connection.prepareStatement(sql);
q.executeUpdate();
}
} catch(SQLException e) {
e.printStackTrace();
} finally {
try {
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
};
r.runTaskAsynchronously(instance);
}
public void setJoinMessage(String uuid, String message) {
ResultSet rs = getDataWithUUID(uuid);
String[] sqlValues = new String[2];
try {
if (!rs.isBeforeFirst()) {
String insertSql = "INSERT INTO `mocha` (`uuid`, `join_message`,`quit_message`, `change_points`, `last_modified`) VALUES (?, ?, '', 0, CURRENT_TIMESTAMP)";
sqlValues[0] = uuid;
sqlValues[1] = message;
insertData(insertSql, sqlValues);
} else {
while (rs.next()) {
String updateSql = "UPDATE `mocha` SET `join_message`=? WHERE `uuid`=?";
sqlValues[0] = message;
sqlValues[1] = uuid;
updateData(updateSql, sqlValues);
}
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public void setQuitMessage(String uuid, String message) {
ResultSet rs = getDataWithUUID(uuid);
String[] sqlValues = new String[2];
try {
if (!rs.isBeforeFirst()) {
String insertSql = "INSERT INTO `mocha` (`uuid`, `join_message`,`quit_message`, `change_points`, `last_modified`) VALUES (?, '', ?, 0, CURRENT_TIMESTAMP)";
sqlValues[0] = uuid;
sqlValues[1] = message;
insertData(insertSql, sqlValues);
} else {
while (rs.next()) {
String updateSql = "UPDATE `mocha` SET `quit_message`=? WHERE `uuid`=?";
sqlValues[0] = message;
sqlValues[1] = uuid;
updateData(updateSql, sqlValues);
}
}
} catch (SQLException e) {
e.printStackTrace();
}
}
private void updateData(String sql, String[] sqlValues) {
BukkitRunnable r = new BukkitRunnable() {
#Override
public void run() {
try {
connection = Database.getConnection();
if (connection != null) {
PreparedStatement q = connection.prepareStatement(sql);
q.setString(1, sqlValues[0]);
q.setString(2, sqlValues[1]);
System.out.println(q);
q.executeUpdate();
}
} catch(SQLException e) {
e.printStackTrace();
} finally {
try {
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
};
r.runTaskAsynchronously(instance);
}
private void updateChangePointsData(String sql, String[] sqlValues) {
BukkitRunnable r = new BukkitRunnable() {
#Override
public void run() {
try {
connection = Database.getConnection();
if (connection != null) {
PreparedStatement q = connection.prepareStatement(sql);
q.setInt(1, Integer.parseInt(sqlValues[0]));
q.setString(2, sqlValues[1]);
System.out.println(q);
q.executeUpdate();
}
} catch(SQLException e) {
e.printStackTrace();
} finally {
try {
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
};
r.runTaskAsynchronously(instance);
}
private void insertData(String sql, String[] sqlValues) {
BukkitRunnable r = new BukkitRunnable() {
#Override
public void run() {
try {
connection = Database.getConnection();
if (connection != null) {
PreparedStatement q = connection.prepareStatement(sql);
q.setString(1, sqlValues[0]);
q.setString(2, sqlValues[1]);
System.out.println(q);
q.executeUpdate();
}
} catch(SQLException e) {
e.printStackTrace();
} finally {
try {
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
};
r.runTaskAsynchronously(instance);
}
private ResultSet getDataWithUUID(String uuid) {
ResultSet result = null;
String sqlPlayer = "SELECT * FROM `mocha` WHERE `uuid` = ?";
try {
connection = Database.getConnection();
if (connection != null) {
PreparedStatement q = connection.prepareStatement(sqlPlayer);
q.setString(1, uuid);
result = q.executeQuery();
}
} catch(SQLException e) {
e.printStackTrace();
}
return result;
}
public String getMessage(String uuid, String messageType) {
ResultSet rs = getDataWithUUID(uuid);
String message = null;
try {
if (!rs.isBeforeFirst()) {
message = null;
} else {
while (rs.next()) {
if (messageType.equalsIgnoreCase("getjoin")) {
message = rs.getString("join_message");
} else if (messageType.equalsIgnoreCase("getquit")) {
message = rs.getString("quit_message");
}
}
}
} catch (SQLException e) {
e.printStackTrace();
}
return message;
}
public int getChangePoints(String uuid) {
ResultSet rs = getDataWithUUID(uuid);
int changePoints = 0;
try {
if (!rs.isBeforeFirst()) {
changePoints = 0;
} else {
while (rs.next()) {
changePoints = rs.getInt("change_points");
}
}
} catch (SQLException e) {
e.printStackTrace();
}
return changePoints;
}
public void removeChangePoints(String uuid, int amount) {
int changePoints = getChangePoints(uuid);
String[] sqlValues = new String[2];
if (changePoints >= amount) {
String updateSql = "UPDATE `mocha` SET `change_points`=? WHERE `uuid`=?";
sqlValues[0] = String.valueOf((changePoints-amount));
sqlValues[1] = uuid;
updateData(updateSql, sqlValues);
}
}
public void addChangePoints(String uuid, int amount) {
int changePoints = getChangePoints(uuid);
String[] sqlValues = new String[2];
String updateSql = "UPDATE `mocha` SET `change_points`=? WHERE `uuid`=?";
sqlValues[0] = String.valueOf((changePoints+amount));
sqlValues[1] = uuid;
updateChangePointsData(updateSql, sqlValues);
}
}
My DB Class:
public class Database {
private static Latte instance = Latte.getInstance();
private static Config config = new Config();
private static HikariConfig dbConfig;
static {
dbConfig = new HikariConfig();
dbConfig.setJdbcUrl("jdbc:mysql://localhost:3306/" + config.get("database.database"));
dbConfig.setUsername(config.get("database.username"));
dbConfig.setPassword(config.get("database.password"));
dbConfig.setDriverClassName("com.mysql.jdbc.Driver");
dbConfig.addDataSourceProperty("cachePrepStmts", "true");
dbConfig.addDataSourceProperty("prepStmtCacheSize", "250");
dbConfig.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
}
private static HikariDataSource ds = new HikariDataSource(dbConfig);
public static Connection getConnection() {
try {
ds.setIdleTimeout(60000);
ds.setConnectionTimeout(60000);
ds.setValidationTimeout(3000);
ds.setLoginTimeout(5);
ds.setMaxLifetime(60000);
ds.setMaximumPoolSize(20);
ds.setLeakDetectionThreshold(5000);
return ds.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
}
When opening a Connection you also need to close it. However you are storing the Connection in a instance variable. Which, for certain paths in your code, might result in multiple Connection instances being used. Due the the storage in the instance variable only the last one used will get closed, all the others are leaked.
Instead you want to make it local or hide parts of the complexity. You could rewrite your Database class to something like this.
Note: Assuming Java 8 here!
public class Database {
private static Latte instance = Latte.getInstance();
private static Config config = new Config();
private static HikariConfig dbConfig;
static {
dbConfig = new HikariConfig();
dbConfig.setJdbcUrl("jdbc:mysql://localhost:3306/" + config.get("database.database"));
dbConfig.setUsername(config.get("database.username"));
dbConfig.setPassword(config.get("database.password"));
dbConfig.setDriverClassName("com.mysql.jdbc.Driver");
dbConfig.addDataSourceProperty("cachePrepStmts", "true");
dbConfig.addDataSourceProperty("prepStmtCacheSize", "250");
dbConfig.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
}
private static HikariDataSource ds = new HikariDataSource(dbConfig);
public static <T> T execute(ConnectionCallback<T> callback) {
try (Connection conn = ds.getConnection()) {
return callback.doInConnection(conn);
} catch (SQLException e) {
throw new IllegalStateException("Error during execution.", e);
}
}
public static interface ConnectionCallback<T> {
public T doInConnection(Connection conn) throws SQLException;
}
}
Notice no more getConnection and due to the try-with-resources the connection will get closed automatically.
You can now call this method with instances of ConnectionCallback instead of getting the Connection and manage it yourself.
Now the code that uses the Connection can be refactored, to something like this. (Notice no more catches, closes etc. all that is handled in the Database.execute method.
private void updateData(String sql, String[] sqlValues) {
BukkitRunnable r = new BukkitRunnable() {
#Override
public void run() {
Database.execute( (conn) -> {
PreparedStatement q = conn.prepareStatement(sql);
q.setString(1, sqlValues[0]);
q.setString(2, sqlValues[1]);
System.out.println(q);
q.executeUpdate();
return null;
}} );
};
r.runTaskAsynchronously(instance);
}
This code will close the Connection after each use (and you cannot forget to close it).
I am new to Glassfish and Java EE, and I try to develop a project using glassfish as the server. The problem I have is that sometiems glassfish takes too long to deploy the project because it is closing JDBC Connections, and that takes too long.
SEVERE: Closing JDBC Connection 0
SEVERE: Closing JDBC Connection 1
SEVERE: Closing JDBC Connection 2
SEVERE: Closing JDBC Connection 3
SEVERE: Closing JDBC Connection 4
...........
SEVERE: Closing JDBC Connection 19
I don't know if the problem is from the glassfish server or from my code.. I am closing the connections after using them..
Can you please help me with figuring out where the problem comes from and how can I solve it?
I will add some more info.
I am using GlassFish Server 4.1 and Java EE 7 Web.
For connections, I have the following classes:
public class PooledConnection {
private Connection connection = null;
private boolean inuse = false;
// Constructor that takes the passed in JDBC Connection
// and stores it in the connection attribute.
public PooledConnection(Connection value) {
if (value != null) {
this.connection = value;
}
}
// Returns a reference to the JDBC Connection
public Connection getConnection() {
// get the JDBC Connection
return this.connection;
}
// Set the status of the PooledConnection.
public void setInUse(boolean value) {
inuse = value;
}
//Returns the current status of the PooledConnection.
public boolean inUse() {
return inuse;
}
// Close the real JDBC Connection
public void close() {
try {
connection.close();
} catch (SQLException sqle) {
System.err.println(sqle.getMessage());
}
}
}
The ConnectionPool class
public class ConnectionPool {
// JDBC Driver Name
private String driver = null;
// URL of database
private String url = null;
// Initial number of connections.
private int size = 0;
// Username
private String username = null;
// Password
private String password = null;
// Vector of JDBC Connections
private ArrayList<PooledConnection> pool = null;
private ArrayList<PooledConnection> poolInUse = null;
private ArrayList<PooledConnection> poolNotInUse = null;
public ConnectionPool() {
}
// Set the value of the JDBC Driver
public void setDriver(String value) {
if (value != null) {
driver = value;
}
}
// Get the value of the JDBC Driver
public String getDriver() {
return driver;
}
// Set the URL Pointing to the Datasource
public void setURL(String value) {
if (value != null) {
url = value;
}
}
// Get the URL Pointing to the Datasource
public String getURL() {
return url;
}
// Set the initial number of connections
public void setSize(int value) {
if (value > 1) {
size = value;
}
}
// Get the initial number of connections
public int getSize() {
return size;
}
// Set the username
public void setUsername(String value) {
if (value != null) {
username = value;
}
}
// Get the username
public String getUserName() {
return username;
}
// Set the password
public void setPassword(String value) {
if (value != null) {
password = value;
}
}
// Get the password
public String getPassword() {
return password;
}
// Creates and returns a connection
private Connection createConnection() throws Exception {
Connection con = null;
// Create a Connection
con = DriverManager.getConnection(url, username, password);
return con;
}
// Initialize the pool
public synchronized void initializePool() throws Exception {
// Check our initial values
if (driver == null) {
throw new Exception("No Driver Name Specified!");
}
if (url == null) {
throw new Exception("No URL Specified!");
}
if (size < 1) {
throw new Exception("Pool size is less than 1!");
}
// Create the Connections
try {
// Load the Driver class file
Class.forName(driver);
// Create Connections based on the size member
for (int x = 0; x < size; x++) {
System.err.println("Opening JDBC Connection " + x);
Connection con = createConnection();
if (con != null) {
// Create a PooledConnection to encapsulate the real JDBC Connection
PooledConnection pcon = new PooledConnection(con);
// Add the Connection to the pool
addConnection(pcon);
}
}
} catch (SQLException sqle) {
System.err.println(sqle.getMessage());
} catch (ClassNotFoundException cnfe) {
System.err.println(cnfe.getMessage());
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
// Adds the PooledConnection to the pool
private void addConnection(PooledConnection value) {
// If the pool is null, create a new vector with the initial size of
if(pool == null)
{
pool = new ArrayList<PooledConnection>(size);
}
pool.add(value);
}
public synchronized void releaseConnection(Connection con)
{
if(con != null)
{
// find the PooledConnection Object
for (int x = 0; x < pool.size(); x++) {
PooledConnection pcon = pool.get(x);
// Check for correct Connection
if (pcon.getConnection() == con) {
System.err.println("Releasing Connection " + x);
// Set its inuse attribute to false, which
// releases it for use
pcon.setInUse(false);
break;
}
}
}
}
// Find an available connection
public synchronized Connection getConnection() throws Exception {
PooledConnection pcon = null;
// find a connection not in use
for (int x = 0; x < pool.size(); x++) {
pcon = pool.get(x);
// Check to see if the Connection is in use
if (pcon.inUse() == false) {
// Mark it as in use
pcon.setInUse(true);
// return the JDBC Connection stored in the
// PooledConnection object
return pcon.getConnection();
}
}
// Could not find a free connection, create and add a new one
try {
// Create a new JDBC Connection
Connection con = createConnection();
// Create a new PooledConnection, passing it the JDBC Connection
pcon = new PooledConnection(con);
// Mark the connection as in use
pcon.setInUse(true);
// Add the new PooledConnection object to the pool
pool.add(pcon);
} catch (Exception e) {
System.err.println(e.getMessage());
}
// return the new Connection
return pcon.getConnection();
}
// When shutting down the pool, you need to first empty it.
public synchronized void emptyPool() {
// Iterate over the entire pool closing the JDBC Connections.
for (int x = 0; x < pool.size(); x++) {
System.err.println("Closing JDBC Connection " + x);
PooledConnection pcon = pool.get(x);
// If the PooledConnection is not in use, close it
if (pcon.inUse() == false) {
pcon.close();
} else {
// If it is still in use, sleep for 30 seconds and force close.
try {
java.lang.Thread.sleep(30000);
pcon.close();
} catch (InterruptedException ie) {
System.err.println(ie.getMessage());
}
}
}
}
}
And the DBAccessController
public final class DBAccessController {
private Connection connection = null;
public DBAccessController(String url, String userId, String password, boolean typereadonly) {
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver").newInstance();
connection = DriverManager.getConnection(url, userId, password);
connection.setReadOnly(typereadonly);
} catch (java.lang.ClassNotFoundException exceptionClassNotFound) {
} catch (java.lang.InstantiationException instantException) {
} catch (java.lang.IllegalAccessException illegalAccess) {
} catch (java.sql.SQLException sqle) {
}
}
public DBAccessController(Connection con) {
if (con != null) {
this.connection = con;
}
}
public final synchronized ArrayList runSQL(String queryString, List<String> parametrii) {
try {
PreparedStatement prepStmt = connection.prepareStatement(queryString, PreparedStatement.RETURN_GENERATED_KEYS);
connection.setAutoCommit(true);
for (int i = 0; i < parametrii.size(); i++) {
prepStmt.setString((i + 1), parametrii.get(i));
}
ResultSet rs = prepStmt.executeQuery();
boolean flag = prepStmt.execute();
ArrayList<HashMap<String, String>> rezultate = new ArrayList<>();
ResultSet keyset = prepStmt.getGeneratedKeys();
while (keyset != null && keyset.next()) {
HashMap<String, String> keysHM = new HashMap<>();
// Retrieve the auto generated key(s).
int key = keyset.getInt(1);
keysHM.put("cheia", Integer.toString(key));
rezultate.add(keysHM);
}
if (flag) {
ResultSet res = prepStmt.getResultSet();
ResultSetMetaData rsmd = res.getMetaData();
int numberOfColumns = rsmd.getColumnCount();
while (res.next()) {
HashMap<String, String> hm = new HashMap<>();
Object o = res.getObject(i);
if (o != null) {
hm.put(rsmd.getColumnName(i), o.toString());
}
}
rezultate.add(hm);
}
res.close();
prepStmt.close();
return rezultate;
} else {
prepStmt.close();
if (keyset != null) {
return rezultate;
} else {
return null;
}
}
} catch (java.sql.SQLException sqle) {
return null;
}
}
public final synchronized ArrayList runSQL(String queryString) {
try {
PreparedStatement statement = connection.prepareStatement(queryString, PreparedStatement.RETURN_GENERATED_KEYS);
connection.setAutoCommit(true);
boolean flag = statement.execute();
System.out.println("Statement: " + statement + " flag: " + flag);
ArrayList<HashMap<String, String>> rezultate = new ArrayList<>();
ResultSet keyset = statement.getGeneratedKeys();
while (keyset != null && keyset.next()) {
HashMap<String, String> keysHM = new HashMap<>();
// Retrieve the auto generated key(s).
int key = keyset.getInt(1);
keysHM.put("cheia", Integer.toString(key));
rezultate.add(keysHM);
System.out.println("Cheile " + keyset.toString());
}
System.out.println("Cheile " + keyset.toString());
if (flag) {
ResultSet res = statement.getResultSet();
ResultSetMetaData rsmd = res.getMetaData();
int numberOfColumns = rsmd.getColumnCount();
System.out.println("res: " + res + " rsmd: " + rsmd + " numberOfColumns: " + numberOfColumns);
while (res.next()) {
HashMap<String, String> hm = new HashMap<>();
System.out.println("Res to string " + res.toString());
for (int i = 1; i <= numberOfColumns; i++) {
System.out.println("obiectul " + i + " res.getObject(i) " + res.getObject(i));
Object o = res.getObject(i);
System.out.println("rsmd.getColumnName(i) " + rsmd.getColumnName(i));
if (o != null) {
hm.put(rsmd.getColumnName(i), o.toString());
}
}
rezultate.add(hm);
}
res.close();
statement.close();
System.out.println("Return rezultate");
return rezultate;
} else {
System.out.println("Return null 1");
statement.close();
if (keyset != null) {
return rezultate;
} else {
return null;
}
}
} catch (java.sql.SQLException sqle) {
System.out.println("Return null 2" + sqle.getMessage());
return null;
}
}
public final void stop() {
try {
connection.close();
} catch (java.sql.SQLException e) {
}
}
}
When I need to use a connection I do the following (for example):
Connection con;
try {
con = cp.getConnection();
udao = new UtilizatorDAO(con);
con.close();
}
} catch (Exception ex) {
Logger.getLogger(RegisterController.class.getName()).log(Level.SEVERE, null, ex);
}
out.close();
I am trying to insert some rows in to a table... I am using postgressql-7.2.jar.
I get the following exception
org.postgresql.util.PSQLException: No results were returned by the query.
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeQuery(AbstractJdbc2Statement.java:255)
I have already Googled and the possible reasons suggested are
Use executeUpdate() method or execute() method instead of executeQuery() method.
This could possibly be because of jar problem; try other versions of postgres jars.
In some places they save it could be because of heap space error.
I have tried all the three solutions but none of them work...
I am not pasting the code since I have just used statement.executeUpdate(queryString).
The insert statements load the data in to the table but still I get this error.
Can some one help me out in this?
What type of SQL statement are you trying to run with executeQuery()? It should not be an INSERT or UPDATE - these are not queries.
Without posting the actual SQL statement, code samples, or what the table looks like - it's pretty hard to actually help you with your problem. Without specifics all we can do is guess.
This code works perfectly for me running PostgreSQL 8.1 and its driver. Perhaps it can be a template for finding what's wrong with yours.
You need a single table named PERSON with columns PERSON_ID, FIRST_NAME, LAST_NAME. I made PERSON_ID the auto incremented primary key.
package persistence;
import java.sql.*;
import java.util.*;
public class DatabaseUtils
{
private static final String DEFAULT_DRIVER = "org.postgresql.Driver";
private static final String DEFAULT_URL = "jdbc:postgresql://localhost:5432/party";
private static final String DEFAULT_USERNAME = "pgsuper";
private static final String DEFAULT_PASSWORD = "pgsuper";
public static void main(String[] args)
{
String driver = ((args.length > 0) ? args[0] : DEFAULT_DRIVER);
String url = ((args.length > 1) ? args[1] : DEFAULT_URL);
String username = ((args.length > 2) ? args[2] : DEFAULT_USERNAME);
String password = ((args.length > 3) ? args[3] : DEFAULT_PASSWORD);
Connection connection = null;
try
{
connection = createConnection(driver, url, username, password);
DatabaseMetaData meta = connection.getMetaData();
System.out.println(meta.getDatabaseProductName());
System.out.println(meta.getDatabaseProductVersion());
String sqlQuery = "SELECT PERSON_ID, FIRST_NAME, LAST_NAME FROM PERSON ORDER BY LAST_NAME";
System.out.println("before insert: " + query(connection, sqlQuery, Collections.EMPTY_LIST));
connection.setAutoCommit(false);
String sqlUpdate = "INSERT INTO PERSON(FIRST_NAME, LAST_NAME) VALUES(?,?)";
List parameters = Arrays.asList( "Foo", "Bar" );
int numRowsUpdated = update(connection, sqlUpdate, parameters);
connection.commit();
System.out.println("# rows inserted: " + numRowsUpdated);
System.out.println("after insert: " + query(connection, sqlQuery, Collections.EMPTY_LIST));
}
catch (Exception e)
{
rollback(connection);
e.printStackTrace();
}
finally
{
close(connection);
}
}
public static Connection createConnection(String driver, String url, String username, String password) throws ClassNotFoundException, SQLException
{
Class.forName(driver);
if ((username == null) || (password == null) || (username.trim().length() == 0) || (password.trim().length() == 0))
{
return DriverManager.getConnection(url);
}
else
{
return DriverManager.getConnection(url, username, password);
}
}
public static void close(Connection connection)
{
try
{
if (connection != null)
{
connection.close();
}
}
catch (SQLException e)
{
e.printStackTrace();
}
}
public static void close(Statement st)
{
try
{
if (st != null)
{
st.close();
}
}
catch (SQLException e)
{
e.printStackTrace();
}
}
public static void close(ResultSet rs)
{
try
{
if (rs != null)
{
rs.close();
}
}
catch (SQLException e)
{
e.printStackTrace();
}
}
public static void rollback(Connection connection)
{
try
{
if (connection != null)
{
connection.rollback();
}
}
catch (SQLException e)
{
e.printStackTrace();
}
}
public static List<Map<String, Object>> map(ResultSet rs) throws SQLException
{
List<Map<String, Object>> results = new ArrayList<Map<String, Object>>();
try
{
if (rs != null)
{
ResultSetMetaData meta = rs.getMetaData();
int numColumns = meta.getColumnCount();
while (rs.next())
{
Map<String, Object> row = new HashMap<String, Object>();
for (int i = 1; i <= numColumns; ++i)
{
String name = meta.getColumnName(i);
Object value = rs.getObject(i);
row.put(name, value);
}
results.add(row);
}
}
}
finally
{
close(rs);
}
return results;
}
public static List<Map<String, Object>> query(Connection connection, String sql, List<Object> parameters) throws SQLException
{
List<Map<String, Object>> results = null;
PreparedStatement ps = null;
ResultSet rs = null;
try
{
ps = connection.prepareStatement(sql);
int i = 0;
for (Object parameter : parameters)
{
ps.setObject(++i, parameter);
}
rs = ps.executeQuery();
results = map(rs);
}
finally
{
close(rs);
close(ps);
}
return results;
}
public static int update(Connection connection, String sql, List<Object> parameters) throws SQLException
{
int numRowsUpdated = 0;
PreparedStatement ps = null;
try
{
ps = connection.prepareStatement(sql);
int i = 0;
for (Object parameter : parameters)
{
ps.setObject(++i, parameter);
}
numRowsUpdated = ps.executeUpdate();
}
finally
{
close(ps);
}
return numRowsUpdated;
}
}
A statement inserting rows does not return any rows back as a result, as opposed to a SELECT.