JDBC Too Many Connections Error - java

I know this probably is a similar question from the rest, (well originally, before I tried something new, it was a bit unique but it never solved the main problem), but I probably need to discuss this with someone who can help because I could never get what's causing this despite already reading various posts from this site. Bottom line is I need to keep on making plenty of sequential queries but I ended up making too many connections.
What my program does is that it displays data about each member and that it's sort of a tree or network where, in order to get the data you need for each member, you have to scout through every other member that points to that current member (or child's data) , and the data of the member that points to the member that points to the current member (or grandchild's data) and so on. Hence, why I need to keep making queries cause I need to get the data off of each child. Each node has I think a minimum children of 5 and on my 34th member, it gave off that "Too Many Connections" error.
I have read how to open and close the Connections and all but am I still doing it incorrectly? I've tried changing the max connections but that's not really a long term solution for me. Here's how I do it:
public class SQLConnect {
private Connection con;
private Statement st;
private ResultSet rs;
public SQLConnect() {
try {
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/dbname?zeroDateTimeBehavior=convertToNull", "root", "");
st = con.createStatement();
} catch (ClassNotFoundException | SQLException ex) {
System.out.println("Error in constructor: " + ex);
}
}
//this method gets called before I make another query
public void reconnect() {
try {
st.close();
con.close();
if (con.isClosed()) {
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/dbname", "root", "");
st = con.createStatement();
}
} catch (SQLException ex) {
Logger.getLogger(SQLConnect.class.getName()).log(Level.SEVERE, null, ex);
}
}
//sample method on how I do queries
public ResultSet getMemberViaMemberId(String mID) {
try {
String query = "CALL getMemberViaMemberId(" + mID + ");"; //procedure call
rs = st.executeQuery(query);
} catch (Exception ex) {
System.out.println("Error: " + ex);
}
return rs;
}
}//end of class
The way I call it in my JForm is this..
SQLConnect connect;
public Class(){
connect = new SQLConnect();
}
public void methodThatGetsCalledALot(String current_id){
connect.reconnect(); //refer to SQLConnectClass displayed above
ResultSet member = connect.getMemberViaMemberId(current_id);
try{
if (member.next()) {
lastName = member.getString("last_name");
firstName = member.getString("first_name");
}
//display data...
} catch (SQLException ex){
}
}
The code:
connect.reconnect();
ResultSet rs = connect.callSQLMethod();
is the most essential bit and is called by every class, and by every method that needs to fetch data. I have to acknowledge that I never bother closing ResultSet because often times it's inside a loop and gets replaced with new data anyway.
Again, my problem is: I cant continue fetching data anymore because of too many connections. Am I really closing things properly or am I missing something? Any suggestions on how to fix this? If my question is too confusing, I'd add more details if required. Thank you. If anyone's to keen on freely helping me out, I'd go for some emailing. Thank you! And Happy New Year btw.

You seem to be creating a lot of connections and recursing with the ResultSet open. Don't create new connections all the time, all you need is one connection and don't reconnect all the time. You actually don't need the reconnect method at all (unless you connection closes automatically, in which case you can check if it is closed before executing query). And you need to close the ResultSet once you are done retrieving values.
All you need is the data and not the resultset. So take the data and release the resource ie ResultSet. So do this -
In your getMemberViaMemberId don't return ResultSet, in that method itself, iterate through the resultset and create the object for the row and store it into a collection and return that collection after closing the ResultSet. And dont call reconnect method at all.
Close the single connection that you have when exiting the program.

Related

Database connection with JDBC using Ucanaccess no output

I try to create a connection between JDBC and MS Access.
I follow the instruction as per this link. I am using IntelliJ Idea. Here I am sharing some snaps to describe my problem.
This is the code that I write down to make a connection with Database Database2. But as you can see there is no error neither any output. Now I am sharing the table structure and content on the table.
2nd picture is
My code is:
import java.sql.*;
public class Connection_sample {
public static void main(String[] args) {
try {
Class.forName("net.ucanaccess.jdbc.UcanaccessDriver");
Connection conn= DriverManager.getConnection("jdbc:ucanaccess://D://tutorial/Database2.accdb");
Statement s = conn.createStatement();
s.executeQuery("select * from Student");
ResultSet rset = s.getResultSet();
while (rset.next()) {
System.out.println(rset.getInt(1)+""+rset.getInt(2));
}
} catch (SQLException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Can anyone help me to find the error?
Your problem is the result of using getResultSet() instead of using the result set returned by executeQuery(). You should only use getResultSet() in combination with execute().
A result set should only be obtained once, and it was already returned from executeQuery (which you ignored). When you called getResultSet, you - apparently - got an empty one (which technically violates the contract).

SQL PreparedStatement; Am I doing it right?

I am building a web app with a single (not pooled) full time (jdbc) connection between static classes and the database. This is expected to be a low traffic site and the static methods are synchronized. In an effort to speed up access to product information, I am trying PreparedStatements for the first time. As I test, on localhost, sure that I'm the only one running the app., it seems clear to me that my the prepared statements are slower than the unprepared statements I use earlier in the process. This may not be a fair comparison. The unprepared statements get a single result set from one table and it's done. As you can see from the code below, what I'm doing with prepared statements involves three tables and multiple queries. But since this is my first time, I would appreciate review and comment. This does actually work; i.e. all data is retrieved as expected.
The first method below (initialize()) is called once from a servlet init() method when the application is first started. The second method (getItemBatch()) retrieves information about as many product items as match a product name (Titel). My little development / test database has less than 100 (total) items and only 1-3 items matching each name; most often only 1. The server app and database are on the same machine and I'm accessing from a browser via localhost. I'm surprised by the consistent perceptible wait for this detailed product data compared to fetching a master product list (all items) mentioned above.
public static boolean initialize (Connection connArg, String dbNameArg, String dbmsArg) {
con = connArg;
dbName = dbNameArg;
dbms = dbmsArg;
sqlserver_con = connArg;
ItemBatchStatement =
"select Cartnr, Hgrupp, Prisgrupp, Moms from dbo.Centralartregister " +
"where Titel = ?";
ForArtNrStatement =
"select Artnr, Antal from dbo.Artikelregister " +
"where Cartnr = ? and Antal > 0";
ItemHgruppStatement =
"select Namn from dbo.Huvudgrupper " +
"where Hgrupp = ?";
try {
con.setAutoCommit(false);
getItemBatch = con.prepareStatement(ItemBatchStatement);
getForArtNr = con.prepareStatement(ForArtNrStatement);
getItemHgrupp = con.prepareStatement(ItemHgruppStatement);
} catch (SQLException e) {
return(false);
} finally {
try {con.setAutoCommit(true);} catch (SQLException e) {}
}
return(true);
}
-
public static synchronized String getItemBatch (String Titel) throws SQLException {
String ret_xml;
ResultSet rs = null;
ResultSet rs1 = null;
ResultSet rs2 = null;
Titel = charChange(Titel);
ret_xml = "<ItemBatch Titel='" + Titel + "'>";
try {
con.setAutoCommit(false);
getItemBatch.setString(1,Titel);
rs = getItemBatch.executeQuery();
while (rs.next()) {
getForArtNr.setInt(1,rs.getInt("Cartnr"));
rs1 = getForArtNr.executeQuery();
getItemHgrupp.setInt(1,rs.getInt("Hgrupp"));
rs2 = getItemHgrupp.executeQuery();
if (rs1.next() && rs2.next()) {
ret_xml += "<item><Hgrupp>" + rs2.getString("Namn") + "</Hgrupp><Price>" + rs.getInt("Prisgrupp") + "</Price><Moms>" + rs.getInt("Moms") + "</Moms><Cartnr>" + rs.getInt("Cartnr") + "</Cartnr><Artnr>" + rs1.getInt("Artnr") + "</Artnr></item>";
}
}
ret_xml += "</ItemBatch>";
return(ret_xml);
} catch (SQLException e) {
return("SQLException: " + e);
} finally {
try {con.setAutoCommit(true);} catch (SQLException e) {}
if (rs != null) {rs.close();}
if (rs1 != null) {rs1.close();}
if (rs2 != null) {rs2.close();}
}
}
.
UPDATE: I'm still googling and looking for ways to do better. Let me add something for your consideration.
I'm closing the prepared statements via the servlet's destroy() method; the same servlet that calls the method "initialize()" above in order to create them. The idea is to create them once (and only once) and have them available forever for all users (i.e. until the app or server is shut down). I'm going for a kind-of a pseudo-stored procedure. I would just use stored procedures straight out, but the database exists to support another application (their in-house sales system) and I'm going to use it for Internet sales read-only ... avoiding any potential conflict with their maintenance efforts or agreements etc. by not doing anything to change their database set-up. I have suggested that my app use a new account limited to read-only privileges. And come to think of it, I haven't tested whether I can use Prepared Statements in that mode; just seems like it should work.
Each result set is closed in the finally block in the method where they are created. I guess that's ok? I reuse the same RS variable name for multiple result sets (on the second two) but close only once. But wait! Do I even need that? The ResultSets are declared within the scope of the method. If resetting them without closing the old ones doesn't cause leaks, then exiting the method should do just as well on its own. It is a static method, but the ResultSets will be reset every time it's used (at the very least). So, at most, there would just be a single set of ResultSet handles available for reuse; not run-away "leakage."
I'm wondering if I can send the two select requests in the loop both at the same time, simply by turning them into one prepared statement separated by ';'. Or just found "MultipleActiveResultSets=True"; document allowing SQL Server to process multiple transaction requests on a single connection ... still investigating this. Or is there another way to create a prepared statement that would fetch ALL the data via a single submission? (Seems to me like there are too many round trips.) Finally, I might get a boost from using connection pooling, which I haven't done yet. It's low priority in my project right now, but I might have to do it before we go online.
If you create web applicaton and use some web container like tomcat, jetty etc you always can use jdbc datasource and connection pool. It is simple. Good explanation gives here
If you don't want to use connection pool I suppose it would be better use Method Scope Connections described link above

Java, code works, but exception is still thrown

I am creating a simple registration frame that adds records onto a database. It gives me an error message every time it runs the SQL query that adds records in the database, however it still adds them, but because of that my programs gets to a standstill, instead of opening another window.
here's that part of the code:
regButton.addActionListener(new ActionListener() {
#Override public void actionPerformed( ActionEvent e ) {
//Execute when button is pressed
if( uNameField.getText().equals("")
|| new String(newPassField.getPassword()).equals("")
|| new String(repeatPassField.getPassword()).equals("") ) {
errorLabel.setForeground(Color.red);
errorLabel.setText("Some fields are left blank");
}
else if( new String(newPassField.getPassword()).equals(
new String(repeatPassField.getPassword()))){
Statement stmt;
ResultSet res;
try
{
//SET USERNAME AND PASSWORD FROM FIELDS TO UPPER CASE
String username = uNameField.getText().toUpperCase();
String password = new String(newPassField.getPassword()).toUpperCase();
//SQL INSERT QUERY
String sql;
sql = "INSERT INTO Employees VALUES ('" +username +"','" +password +"');";
stmt = con.createStatement();
res = stmt.executeQuery(sql);
System.out.println("Added to database!");
con.close();
}
catch(SQLException exe) {
System.out.println("Error creating or running statement: " + e.toString());
try {
con.close();
}
catch(Exception eex){}
}
}
else {
errorLabel.setForeground(Color.red);
errorLabel.setText("Password missmatch");
}
}
Every time it registers a new employee (user) it displays this "Error creating or running statement: ..... " although, I can find the newly added employees in the employee list.
What may be causing this problem?
Before we get to your specific problem, some general advice:
Connection con = ...
try {
// your stuff
}
catch (Exception e) {
e.printStackTrace();
}
finally {
try {
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
The way you are doing it now not only swallows the exception, but also avoids printing its stacktrace. And close must be performend once and only once, regardless of the exception.
If you are on Java 7, this would be much easier:
try (Connetion con = ...) {
// stuff to do
}
catch (Exception e) {
e.printStackTrace();
}
The closing in a finally is now done automatically.
Specifically about your exception, you execute an INSERT by calling executeQuery. This method sends the statement to the DB, which properly executes it, but its response back to the JDBC is not a ResultSet. This is where it blows up, after the record is already inserted. Since you are in autocommit mode, there is no transaction to roll back. Lesson: always use transactions.
You need to use executeUpdate for SQL INSERTs
int rowCount = stmt.executeUpdate(sql);
I hate seeing code written this way. You didn't ask about this, and my comment won't solve your problem, but I think it needs to be said.
You're creating a maintenance nightmare for yourself by putting persistence code in a Swing Listener method.
A better idea is to think about objects in a way that gives them a single responsibility.
Take your persistence code and move it into a separate class that you can develop and test on its own. Once it's working, give a reference to the class that needs it.
Your code will be more modular, easier to test, more reusable, and less of a nightmare to understand.
Uncle Bob Martin has a succinct mneumonic for this and other ideas worth remembering: SOLID.
why dont you try PreparedStatement
try{
//SET USERNAME AND PASSWORD FROM FIELDS TO UPPER CASE
String username = uNameField.getText().toUpperCase();
String password = new String(newPassField.getPassword()).toUpperCase();
//SQL INSERT QUERY
PreparedStatement pstmt = con.prepareStatement("insert into Employees values(?,?)");
pstmt.setString(1,username);
pstmt.setString(2,password);
if(!pstmt.execute())
{
//means your code worked correctly
System.out.println("Inserted successfully");
}
else
{
System.out.println("Unsuccessfull");
}
}
catch(Exception ex)
{
ex.printStackTrace();
}

Resultset not open

I get following error on Result set
java.sql.SQLException: ResultSet not open. Verify that autocommit is OFF.
at org.apache.derby.client.am.SQLExceptionFactory40.getSQLException(Unknown Source)
at org.apache.derby.client.am.SqlException.getSQLException(Unknown Source)
at org.apache.derby.client.am.ResultSet.next(Unknown Source)
public ResultSet insertDb(int Id,String firstName,String lastName,String title) throws SQLException{
try {
try {
Class.forName(driver);
con = DriverManager.getConnection(connectionURL);
} catch (SQLException ex) {
Logger.getLogger(Connect.class.getName()).log(Level.SEVERE, null, ex);
} catch (ClassNotFoundException ex) {
Logger.getLogger(Connect.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println(con.getAutoCommit());
statement = con.createStatement() ;
res = statement.executeQuery("SELECT * FROM CUSTOMER") ;
con.setAutoCommit(false);
System.out.println(con.getAutoCommit());
while(res.next()){
if(res.getString("ID").equalsIgnoreCase(Integer.toString(Id))){
UNIQUE = false;
error= "Duplicate Entry Found Please Enter New Data";
throw new SQLException("Duplicate info<br>ID " + Id );
}
}
// IF value to be added IS UNIQUE
if(UNIQUE){
String qry1= "insert into CUSTOMER(ID, FIRSTNAME,LASTNAME,TITLE) values(?,?,?,?)";
stm = con.prepareStatement(qry1);
String ID=Integer.toString(Id);
stm.setString(1, ID);
stm.setString(2, firstName);
stm.setString(3, lastName);
stm.setString(4, title);
stm.executeUpdate();
}
}
catch(Exception e){
String errorMessage = "Exception caught : ";
System.out.println(errorMessage + e.toString());
}finally{
if (con != null){
con.close();
}
}
return res;
}
Try moving the setAutoCommit() and getAutoCommit() to before you create and execute the statement. Changing it after you execute the statement may be invalidating the query.
The problem is that you have closed your query before reading your resultset. Closing the query, closes the resultset, hence why you get the "ResultSet not open" error. You should close the query right at the end, in a finally block:
i.e. con.setAutoCommit(false);
will close the query and along iwth it it closes the resultset also.
Not strictly related, but your code probably doesn't do what you expect. This kind of read-modify-write code doesn't work well when there are multiple concurrent invocations.
If you imagine two invocations running though the code, it becomes clear that sometimes, depending on the execution order, BOTH invocations could reach the insert statement.
In addition, selecting from a table without using a WHERE clause is not generally useful. In this case you select '*', then iterate over all the results to see if "ID" == Id. The database is much much better at that than java is. You should add a where clause. (Note that this still won't solve the above problem)
Its also generally a bad idea to 'select *' from any table. Just pick the columns that you need. This will 'fail fast' if the schema changes and the columns that you need are no longer available, and will allow the database optimiser to do the 'right thing' about its disk accesses.
Finally, if its just a numeric ID that you are looking to assign, its normal practice to use 'autonumber' for these, rather than get the program to pick them. Different databases call them different things, so you might also know them as IDENTITY, or have to use a sequence.
In case it helps anyone down the line, I had the same error with Derby 10.5.1.1 that turned out to be a bug in the driver itself that would appear some times and not others depending on the underlying data. Upgrading the driver to a newer version (10.8.2.2) resolved the problem.

INSERT SQL in Java

I have a Java application and I want to use SQL database. I have a class for my connection :
public class SQLConnection{
private static String url = "jdbc:postgresql://localhost:5432/table";
private static String user = "postgres";
private static String passwd = "toto";
private static Connection connect;
public static Connection getInstance(){
if(connect == null){
try {
connect = DriverManager.getConnection(url, user, passwd);
} catch (SQLException e) {
JOptionPane.showMessageDialog(null, e.getMessage(), "Connection Error", JOptionPane.ERROR_MESSAGE);
}
}
return connect;
}
}
And now, in another class I succeeded to print my values but when I attempt to insert a value nothing is happening ...
Here's my code :
try {
Statement state = SQLConnection.getInstance().createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
Statement state2 = SQLConnection.getInstance().createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
state2.executeUpdate("INSERT INTO table(field1) VALUES (\"Value\")"); // Here's my problem
ResultSet res = state.executeQuery("SELECT * FROM table");
You need to commit (and close) the connection (and statement) after use. You also need to ensure that you aren't swallowing any SQLExceptions which may cause that you see "nothing" to happen.
That said,
private static Connection connect;
This is a terribly bad idea. You should never declare external resources as static in your application. Your application will break when the other side decides to close the resource because it's been released for a too long time. You really need to acquire and close those resources (Connection, Statement and ResultSet in the shortest possible scope. I.e. inside the very same method block as where the query is to be executed.
Also, I strongly recommend to use PreparedStatement instead of Statement since that will prevent your code from SQL injection attacks.
You may find this article useful to learn more about how to do basic JDBC interaction the right way.
state2.executeUpdate("INSERT INTO table(field1) VALUES (\"Value\")");
should be:
state2.executeUpdate("INSERT INTO plateau(field1) VALUES (\"Value\")");
Copuld just be a copy over to SO error, but looking but shoulding INSERT INTO table(field1) be INSERT INTO plateau(field1)?

Categories

Resources