Answer the question
In order to leave comments, you need to log in
How to properly work with MySQL in Java?
Good afternoon everyone!
Essence of the question: I want to understand whether I have correctly built a scheme for working with MySQL and how to close connections correctly?
To communicate with the database with each request, I open a new connection with the method:
private Connection con;
private Statement stmt;
private void openConnection()
{
try {
con = DriverManager.getConnection(url, user, password);
stmt = con.createStatement();
} catch (Exception e) {
e.printStackTrace();
}
}
private int executeQuery(String query)
{
ResultSet rs = null;
try {
rs = stmt.executeQuery(query);
return rs.getInt(1);
} catch (Exception e) {
e.printStackTrace();
} finally {
closeConnection(rs);
}
return 0;
}
private void closeConnection(ResultSet rs)
{
if (rs != null) try {rs.close();} catch (Exception e){}
//
try { if (stmt != null) stmt.close();}
catch (Exception e) {}
finally {stmt = null;}
//
try { if (con != null) con.close();}
catch (Exception e) {}
finally {con = null;}
}
mysql> show processlist;
+-------+------+-----------------+------+---------+------+----------+------------------+
| 23055 | root | localhost:60396 | fmdb | Sleep | 5 | | NULL |
| 23056 | root | localhost:60397 | fmdb | Sleep | 5 | | NULL |
| 23058 | root | localhost:60399 | fmdb | Sleep | 5 | | NULL |
| 23060 | root | localhost:60401 | fmdb | Sleep | 5 | | NULL |
com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Data source rejected establishment of connection, message from server: "Too many connections"
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
Answer the question
In order to leave comments, you need to log in
The first question: please tell me if I built the scheme to work with the base correctly?
The second question: after each request, I have a bunch of Sleep connections in the terminal
package hello.world;
import java.sql.*;
public class Main {
// один коннект на всё приложение
private static Connection conn;
// в данном случае так же можно использовать и единственный Statement
private static Statement stmt;
public static void main(String[] args) throws SQLException {
conn = DriverManager.getConnection("jdbc:mysql://localhost/hello", "user", "password");
stmt = conn.createStatement();
doTheJob();
}
private static void doTheJob() throws SQLException {
// здесь используется фишка Java7 под названием try-with-resources,
// которая освобождает нас от необходимости закрывать ResultSet руками
// он будет закрыт автоматически в конце try блока
try ( ResultSet rs = stmt.executeQuery("SHOW TABLES") ) {
while ( rs.next() ) {
System.out.println(rs.getString(1));
}
}
// переиспользуем Statement для другого запроса - это допустимо
try ( ResultSet rs = stmt.executeQuery("SELECT column FROM table") ) {
while ( rs.next() ) {
System.out.println(rs.getString(1));
}
}
// вариант без try-with-resources для Java6 и ниже
ResultSet rs2 = null;
try {
rs2 = stmt.executeQuery("SELECT column2 FROM table2");
// делаем что-то с rs2
} finally {
close(rs2);
}
}
private static void close(ResultSet rs) {
if ( rs != null ) {
try {
rs.close();
} catch ( SQLException e ) {
e.printStackTrace();
}
}
}
}
package hello.world;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import java.sql.*;
import java.util.Properties;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
// пул, в котором содержатся все соединения
private static HikariDataSource dbPool;
// в этом сервисе будем параллельно выполнять запросы
private static ExecutorService executor = Executors.newFixedThreadPool(5);
public static void main(String[] args) throws SQLException {
// конфигурируем пул
Properties props = new Properties();
props.setProperty("dataSourceClassName", "com.mysql.jdbc.jdbc2.optional.MysqlDataSource");
props.setProperty("dataSource.url", "jdbc:mysql://localhost/hello");
props.setProperty("dataSource.user", "user");
props.setProperty("dataSource.password", "password");
props.setProperty("poolName", "MyFirstPool");
props.setProperty("maximumPoolSize", "5"); // в этом пуле будет максимум 5 соединений
props.setProperty("minimumIdle", "1"); // как минимум одно активное соединение там будет жить постоянно
dbPool = new HikariDataSource(new HikariConfig(props));
doTheJob();
}
private static void doTheJob() throws SQLException {
// сколько запросов будем делать параллельно
int selects = 5;
// этот объект позволит нам дождаться выполнения всех запросов,
// выполняющихся в параллельных потоках чтобы подсчитать общее время
// выполнения всех запросов
CountDownLatch waitLatch = new CountDownLatch(selects);
long startTime = System.nanoTime();
for ( int i = 0; i < selects; ++i ) {
executor.submit(new ThreadPoolJob(dbPool, waitLatch));
}
try {
// ждём когда все воркеры закончат
waitLatch.await();
} catch ( InterruptedException e ) {
System.out.println("latch was broken by interruption request");
}
long timeElapsed = System.nanoTime() - startTime;
System.out.println("All queries was executed in: " + (timeElapsed / 1000000000) + " sec");
}
// класс-воркер, который будет выполнять запрос
private static class ThreadPoolJob implements Runnable {
private final HikariDataSource dbPool;
private final CountDownLatch waitLatch;
ThreadPoolJob(HikariDataSource dbPool, CountDownLatch waitLatch) {
this.dbPool = dbPool;
this.waitLatch = waitLatch;
}
@Override
public void run() {
String tName = Thread.currentThread().getName();
System.out.println(tName + ": Start query");
try (
Connection conn = dbPool.getConnection();
Statement stmt = conn.createStatement();
) {
// здесь мы не получаем и не работаем с ResultSet, поэтому не
// описываем его в try-with-resources
stmt.execute("SELECT SLEEP(5)");
System.out.println(tName + ": Query completed");
} catch ( SQLException e ) {
e.printStackTrace();
} finally {
waitLatch.countDown();
}
}
}
}
The first question: please tell me if I built the scheme to work with the base correctly?
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question