"Too Many Connections" error in Java (MYSQLNonTransientConnectionException) - java

I want to insert every filename of my local drive into a mysql database.
When I execute this code, it start perfectly.
Code that reads the directory for filenames:
public void main(String[] args)throws IOException {
JOptionPane.showMessageDialog(null, "IT MAY TAKE SOMETIME TO LOAD \n PLEASE WAIT FOR CLOSING POPUP!!");
String s="D:\\";
Path startingDir = Paths.get(s);
String pattern="*";
Finder finder = new Finder(pattern);
Files.walkFileTree(startingDir, finder);
JOptionPane.showMessageDialog(null,"close\n NOW PLEASE CLICK\nSEARCH MY FILE! BUTTON");
This is the code to insert the results into the database:
public void find(Path file) {
Path name = file.getFileName();
String st = file.toString();
if (name != null && matcher.matches(name)) {
try {
Connection conn=DriverManager.getConnection("jdbc:mysql://localhost/login","root","");
conn.createStatement();
String query =" INSERT INTO `search`(`path`) VALUES (?)";
PreparedStatement pst=conn.prepareStatement(query);
pst.setString(1,st );
pst.execute();
//myst.executeUpdate(query);
} catch (SQLException e) {
// TODO Auto-generated catch block
JOptionPane.showMessageDialog(null, e);
}
After some time, the scripts stops with this exception
com.mysql.jdbc.exception.jdbc4.MYSQLNonTransientConnectionException:
Data source rejected establishment of connection,
message from server:"Too Many connections"
Is there any way to solve this problem?

For every insert you create a new connection. If you keep doing this they build up and eventually you run out of connections to the database. This limit could be quite small e.g. 20.
Instead you can either
close the resources you have used. This means closing the PreparedStatement and the Connection
or more efficiently, create one Connection and one PrepareStatement ever and reuse it. The saves having to create and clean up resources which can be expensive (unless the driver does this recycling for you)

the easy fix would be to close the connection after you execute the query.
pst.close();
conn.close();
this should get the job done.
But it'd be better to reuse the connection.

Related

Unstable Oracle Database connection for Java-project

I'm a student and one of our assignments is creating a Java web project on a local GlassFish 5 webserver. The database used for this project is an OracleDB running locally in a Docker container.
I almost finished my project but some pages keep crashing (NullPointerException). I have to retrieve database records and save them in an ArrayList. But sometimes the SQLConnection doesn't return anything (but the records DO exist) and my code tries to preform actions on that empty ArrayList.
Now, as I said, the connection appears to be unstable, because at some seemingly random moments the database does respond with the appropriate records.
It's really frustrating and I cannot continue working on this project without a stable database connection. So I'd appreciate hearing from people with some more experience :-)
Thank you for your time.
Code for running a query:
protected ResultSet getRecords(String query) {
try {
Connection connection = DriverManager.getConnection(url, login, password);
Statement statement = connection.createStatement();
return (ResultSet) statement.executeQuery(query);
} catch (SQLException e) {
e.getStackTrace();
}
return null;
}
Code with the query:
List<Uitlening> uitleningen = new ArrayList<Uitlening>();
try {
ResultSet resultSet = getRecords("SELECT * FROM uitlening");
while(resultSet.next()) { //Here the code crashes because the ResultSet can sometimes be empty.
I think this is the actual error message: Listener refused the connection with the following error: ORA-12519, TNS:no appropriate service handler found
But I don't really understand what I should do now..
try {
ResultSet resultSet = getRecords("SELECT * FROM uitlening");
while(resultSet.next()) {
Uitlening uitlening = new Uitlening();
uitlening.setNr(resultSet.getInt("nr"));
uitleningen.add(uitlening);
}
} catch (SQLException e) {
e.addSuppressed(e);
}
return uitleningen;
It might be nothing, but it almost looks like the error only occurs when I run 2 queries almost immediately after each other. Is it possible that closing the connection takes a while?
Chances are that you run into the database connection problem because your code does not properly close the database connections as well as the statements and result sets.
A statement will also close its active result set. Most JDBC will also close the statement if the connection is closed.
So closing the connection is the most important part. It cannot be achieved with your current code structure because you create it in an inner method and do not return it.
It has also been mentioned that the exception handling is poor because you ignore exceptions and return null instead causing seemingly unrelated crashes later. In many cases it might be easier to declare that the method throws SQLException.
You might want to change your code like so:
List<Uitlening> retrieveData() {
final String query = "SELECT * FROM uitlening";
try (Connection connection = DriverManager.getConnection(url, login, password);
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(query)) {
return processResultSet(resultSet);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
List<Uitlening> processResultSet(ResultSet resultSet) throws SQLException {
List<Uitlening> uitleningen = new ArrayList<>();
while (resultSet.next()) {
Uitlening uitlening = new Uitlening();
uitlening.setNr(resultSet.getInt("nr"));
uitleningen.add(uitlening);
}
return uitleningen;
}
It closes the connection, the statement and the result set by using try/catch blocks that take advantage of AutoClosables (in this case: Connection, Statement, ResultSet).
The method processResultSet declares the SQLException so it doesn't need to handle it.
The code is rearrange so the data is fully processed before the code leaves the try/catch block that closes the connection.

Try-catch ignoring the assignment of a variable when executing an SQL query

This piece of code uses an SQL query to return how many entries there are in a certain table.
public int countAmountOfEntries() {
int amount;
try (Connection conn = DriverManager.getConnection(Connection.JDBC_URL);
PreparedStatement query = conn.prepareStatement("SELECT COUNT(*) FROM Table")) {
try (ResultSet rs = query.executeQuery();) {
if (rs.next()) {
amount = rs.getInt("COUNT(*)");
}
}
} catch (SQLException ex) {
throw new RuntimeException(ex);
}
return amount;
}
This should return any int other than 0. Initialising the variable to 0 will result in a NullPointerException being thrown as I'm using the return value of this to set the length of an array. Using the same code in another class returns the int it should return. I've tried using an alias for the COUNT(*) but to no avail.
Running the query directly into MySQL returns the int as well. I've tried removing the nested try (it was pretty much obsolete since I know it won't throw an exception if no one messes with my DB).
Did you register the JDBC driver before using it?
Class.forName("com.mysql.jdbc.Driver");
Is it required to provide an username/password upon connecting?
DriverManager.getConnection(url, user, pass);
Did you create a Connection class yourself which overwrites the Connection class returned upon opening the connection. The reason I ask this is because you retrieve the URL to connect to using Connection.JDBC_URL which is (as far as I know) not in the Connection class.
Is there already a connection opened and your database only allows 1 open connection?
Note: do not forget to close the resultset, statement, and connection before returning:
rs.close();
query.close();
conn.close();
Besides that, restructure your function because a try without catch does not help at all.
This looks really weird:
amount = rs.getInt("COUNT(*)");
Try this instead
amount = rs.getInt(1);

The driver was unable to create a connection to mysql

I'm programming in java SE and I get an error when trying to access to create a connection to mysql. I can connect to mysql, in fact, the error shows up when running a bucle.
What I do in this program is to check for a String in the table Colors of my database and if it finds nothing it creates this String in the table with an autoincrementing id.
It works fine, but after having checked it for a while it gives me the error.
I attach the image of the error and the code where I create the connection.
public Integer codiColor(String col){
Integer codi=null;
if(col.equals(""))
return 1;
try {
Class.forName(driver).newInstance();
con = DriverManager.getConnection(url, usuari, password);//here is the error
try {
Statement st = con.createStatement();
String sql = "SELECT CODICOL FROM COLORES where COLOR ='"+col+"'";
ResultSet res = st.executeQuery(sql);
if(res.next()){
codi = res.getInt("CODICOL");
}
try { res.close(); } catch (Exception e) {}
try { st.close(); } catch (Exception e) {}
}
catch(SQLException s){
JOptionPane.showMessageDialog(null, "Error:\n"+s.getMessage(),
"ERROR.",JOptionPane.ERROR_MESSAGE);
}
finally{
try { con.close(); } catch (Exception e) {}
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
return codi;
}
This code is the one that checks if the color already exists or not.
EDIT:
url = "jdbc:mysql://192.168.1.200:3306/mybbdd?zeroDateTimeBehavior=convertToNull";
The problem is that con is evidently a member variable where it should be a local variable. If this piece of code and others like it are called from multiple threads, a con value will be overwritten and therefore lost, so a connection leak will result. You will almost certainly also have other problems due to concurrent use of the connection. Make it a local variable.
NB you haven't needed the Class.forName() line since 2007. The close of the connection, statement, and result set would be redundant if you used try-with-resources. And you should use a prepared statement.
String sql = "SELECT CODICOL FROM COLORES where COLOR =?";
try (con = DriverManager.getConnection(url, usuari, password);
PreparedStatement st = con.prepareStatement(sql);
) {
st.setObject(1, col);
ResultSet res = st.executeQuery();
if(res.next()){
codi = res.getInt("CODICOL");
}
}
catch(SQLException s){
JOptionPane.showMessageDialog(null, "Error:\n"+s.getMessage(),
"ERROR.",JOptionPane.ERROR_MESSAGE);
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
I find the way out. I googled the number the java error gave to me and I found that adding a registry key to be able to do more connections should work.
I first did it on the server, to allow more connections from clients but it didn't still work so I tried to do it on my computer and for now it works.
This is the link from microsoft
In your code you giving a new connection on every call but you need to understand your OS allows you Only Limited Connection.
after cross Limit it will Not allow you to make another Connection.
i don't know what's your requirement but if you really need Connection
So better option is that you need to make Connection Pool. If user required a connection to do some task then user can Take Connection from connection Pool and after Work Finished user can return that connection to connection pool.
For Achieve this you need to Design Your Configuration File Or you need Design interface library interface and implement according to your Requirement.

JDBC Connection object automatically closes after the static block is executed and how to modularize the code

I have a class that is calling a database class to add entries to the database. The problem is that whenever I am adding a tuple to the database, I have to create a new Connection and a Statement object.
One hack I thought to get around this is to place the initialization of the Connection and the Statement object in a static block. And directly run the command statement.executeUpdate(sqlStatement).
But this gives an error that the Connection object is not initialized.
The code for this is as follows:
class Database{
static final String JDBC_DRIVER = "....";
static final String DB_URL = "...";
static final String USER = ".....";
static final String PASS = ".....";
static Connection conn = null; // Connection object for creating a connection with the Database
static Statement stmt = null; // Statement object to run queries on first table in Database
static{
try{
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(DB_URL,USER,PASS);
stmt = conn.createStatement();
}catch(SQLException se){
se.printStackTrace();
}catch(Exception e){ //Handle errors for Class.forName
e.printStackTrace();
}finally{ //finally block used to close resources
try{
if(stmt!=null){
stmt.close();
}
}catch(SQLException se2){
System.out.println("caught a SQLException " + se2 + " AND NOTHING CAN BE DONE ABOUT IT");
// nothing we can do
}
try{
if(conn!=null){
conn.close();
}
}catch(SQLException se){
se.printStackTrace();
}
}
}
public static void runSqlCommand(String command)throws java.lang.Exception{
stmt.executeUpdate(command); // This gives an error that connection is not initialized.
}
}
I want to know how can I modularize the code so that I can just call a runSqlCommand function and the sql code is executed without having to create a connection and a statement each time.
Also please tell by how much should the performance be improved if I initialize the objects only once and not for every sql command.
You are opening the connection in the static initializer block and you are closing it at the end of the block, so whenever your class will loaded, you'll always have your connection initialized and then closed, I think you need to move out the code which you have written in the finally block.
The compiler is correctly telling you that there is an execution path via which 'stmt' doesn't get initialized, namely if you get an exception opening the connection.
But in any case as you're carefully closing both the statement and the connection in the static block, the entire exercise is completely pointless in the first place.
I recommend a connection pool, and opening and closing connections as and when you actually need them. Much more robust than trying to keep a single connection open for the life of the process, and much kinder to the database than trying to tie up a single connection all day.
If you want to modularize the code, separate the connection management code in some other files, like you can use the DAO pattern, from where you get the initialized connection, and once you are done, close the connection through the DAO helper method.

H2: Error on all other computers

I'm using the H2 database in my Java project (embedded mode).
On my computer at home everything works, the connection can be established, but on all other computers I always receive the following error:
org.h2.jdbc.JdbcSQLException: Table "CUSTOMERS" not found; SQL
statement: SELECT * FROM CUSTOMERS [42102-162]
I'm sure, that within the DB everything is alright, it should be something with the connection.
But even if I import the h2-1.3.162.jar file, the error still remains.
String dbClass = "org.h2.Driver";
String dbDriver = "jdbc:h2:~/cc";
String user = "user1";
String pass = "test1";
private Connection conn = null;
private Statement stmt = null;
private ResultSet rs = null;
public void connect() {
boolean done = false;
//load driver
try {
Class.forName(dbClass).newInstance();
System.out.println("driver loaded"); // This is shown in the Compiler
} catch (Exception ex) {
System.out.println("error while loading driver");
System.err.println(ex);
}
// Connection
try {
conn = DriverManager.getConnection(dbDriver, user, pass);
System.out.println("connected"); // This is shown in the Compiler
done = true;
} catch (SQLException ex) {
System.out.println("SQLException: " + ex.getMessage());
System.out.println("SQLState: " + ex.getSQLState());
System.out.println("VendorError: " + ex.getErrorCode());
}
}
public Vector select() {
data = new Vector();
try {
stmt = conn.createStatement();
rs = stmt.executeQuery("SELECT * FROM CUSTOMERS");
while (rs.next()) {
Vector row = new Vector();
row.add(rs.getInt("id"));
row.add(rs.getString("fname"));
row.add(rs.getString("lname"));
row.add(rs.getString("street"));
row.add(rs.getString("city"));
row.add(rs.getString("zip"));
row.add(rs.getString("state"));
row.add(rs.getString("phone"));
row.add(rs.getString("birthday"));
row.add(rs.getString("email"));
row.add(rs.getInt("code"));
data.add(row);
}
rs.close();
stmt.close();
} catch (SQLException ex) {
System.out.println("error while selecting"); // I receive this error
System.err.println(ex);
}
return data;
}
The problem isn't with your connection as you'd receive an exception well before then if it was failing to connect to the database. The exception is pretty clear about what the issue is, as well - it can't find the CUSTOMERS table. That could be because the table doesn't exist at all, or the connection is pointing at the wrong database; try putting in the full schema information of the table, rather than just its name, and see if that works.
I'm sure, that within the DB everything is alright, it should be
something with the connection. But even if I import the h2-1.3.162.jar
file, the error still remains.
Check your assumptions. This one is incorrect.
There's nothing in the message to suggest that you couldn't connect. Either you connected to the wrong database OR the one you did connect to didn't CREATE TABLE CUSTOMERS. (Should be named CUSTOMER, not plural.)
You'll fix your error faster if you stop assuming that everything you did is correct. You should be assuming that everything is wrong.
I'd print the stack trace when you catch that exception. It'll give you more information.
Finally I figured it out!
It had nothing to do with my tables, the database couldn't be found. When trying to connect to a database which can't be found with String dbDriver = "jdbc:h2:~/cc";, a new database with the name cc (in my case) will be created (of course an empty one with no tables) and the connection is established. That's why I haven't received any connection errors.
In the next step I tried to retrieve some data from the new created empty database and therefore received the error, that my table doesn't exist.
So I changed this line: String dbDriver = "jdbc:h2:file:lib/cc"; and copied into the lib directory of my application my old database cc.h2.db.
That's all!
PS: Here is a similiar problem: h2 (embedded mode ) database files problem

Categories