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.
Related
In our web application we are running into this issue very often
ORA-01000 maximum open cursors exceeded
I understand this has to do with the code not closing the cursors (ResultSet, PreparedStatement, etc.) properly.
Sample:
public List<Employee> getAllEmployees() throws DatabaseException{
Connection conn = DatabaseHelper.getConnection(); //Get a connection from the connection pool
PreparedStatement pst = null;
ResultSet rs = null;
List<Employee> emps = new ArrayList<Employee>();
try {
pst = conn.prepareStatement("SELECT * FROM EMPLOYEE ORDER BY EMP_ID");
rs = pst.executeQuery();
while(rs.next()) {
//Do something
}
} catch (SQLException e) {
logger.error("ERROR getting all employees", e);
throw new DatabaseException("Could not get all employees due to an internal error", e);
} finally {
try { pst.close(); } catch(Exception ignore) {} //Close the prepared statement
try { rs.close(); } catch(Exception ignore) {} //Close the Resultset
try { conn.close(); } catch(Exception ignore) {} ////Close the connection, thus returning it to the pool
}
return emps;
}
Though I understand that I'm closing the cursors and the connection in the finally block, what I don't understand is how can I actually verify that the cursors are closed in the Oracle database?
I am currently running the following query (assuming my DB username is EMP)
select * from v$open_cursor where sid in (select sid from v$session where username='EMP' and program ='JDBC Thin Client');
This gives me a list of rows for open cursors for sessions connected through the JDBC thin client. But even after the pst.close(), rs.close() and the conn.close() are called, the query keeps returning the same rows, which seems to indicate that the cursors are still open.
I used JProfiler to check for leaks. However, it tells me if I'm closing the Connection objects or not, but does not tell me about PreparedStatement, Statement and ResultSet
I have already referred to the following post, and have followed the instructions, but none of them seem to answer my question, which is, how can I verify if a cursor is being closed in Oracle (using SQL Developer or some other tool)?
Link to a very exhaustive explanation on this topic
First, and most important, v$open_cursor is not a list of cursors currently open. For that, I think you need some combination of v$sesstat and v$statname, but I'm not really sure.
What is your open_cursors parameter set to? I think the default is 50, but Oracle recommends setting that to at least 500.
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);
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.
I am leaning some Java for school, and for some reason the code below doesn't return any results? Is there a problem with this code? There is a single record in the mysql database, with a studentID (which is int(10)) of 12.
public static ResultSet GetByID(int studentID) {
// This method loads the mysql driver and establishes the database connection
Connect();
ResultSet results = null;
try {
String query = "SELECT * FROM student where studentID = ?";
PreparedStatement statement = Connection.prepareStatement(query);
statement.setInt(1, studentID);
results = statement.executeQuery();
} catch (SQLException ex) {
LogException(ex);
} catch (Exception ex) {
System.out.println(ex);
}
// This method terminates the mysql connection.
Disconnect();
return results;
}
The calling code is:
#Override
public ResultSet query() {
return DB.GetByID(getStudentID()); // this is 12
}
This does not return null, rather just an empty result set.
A ResultSet can only be used while the connection is still open. Read it before you "disconnect".
If fixing that doesn't give you a different result, the most likely cause is that the query didn't match any rows in the table.
You should get into the habit of closing connections, streams, etc in finally blocks to prevent resource leakage. (Your lecturer should have explained that. Check your notes / text book.)
Finally, since you are a beginner, it is worth pointing out that you should always conform to the accepted Java conventions for method naming. Java method names should start with a lower-case letter. GetByID should be getByID and Disconnect should be disconnect.
(And if your lecturer / tutor doesn't or didn't dock marks for that, he / she should be condemned to writing Visual Basic for the next 5 years for crimes against the Software Engineering industry.)
If you want to return the resultSet after closing the connection you have to use CachedRowSet.
As StephenC said, your ResultSet is empty after closing the connection.
In the context of a java application using SQLIte to persist data I am using the Zentus JDBC driver. Thus I am using the java.sql package to acces my database.
I am facing some strange (in a an environment with several Connection objects on the same database) issues and I am pretty sure my problems come from non closed ResultSet.
Is there any tool or technique allowing me to spot where to look in my source code to find these non closed objects ?
Edit May be using AspectJ ??
It seems like an aspect may be helpful.
How about wrapping the methods which return a result set in an aspect. Something like:
execution(public java.sql.ResultSet+ java.sql.Statement+.*(..))
Another aspect can monitor the close method on ResultSets. Perhaps:
execution(public * java.sql.ResultSet.close())
The first aspect would, on the return of every ResultSet, create a new Exception object and store it in a static Map somewhere using the hash of the ResultSet as the key. The second aspect, on the closing of the result set, would remove the Exception from the Map using the same hashcode as a key. At any time, the map should have one exception instance for every open ResultSet. From the exception you can obtain a stack trace to see where the ResultSet was opened.
You could perhaps store a larger object which includes an exception and some other contextual information; time that the ResultSet was created, etc.
A practical suggestion is to add some debug code and "log" creation and closing of resultsets to a csv file. Later on you could examine this file and check, if there's a "close" entry for each "create".
So, assuming you have a utility class with static methods that allows writing Strings to a file, you can do it like this:
ResultSet rs = stmt.executeQuery(query);
Util.writeln(rs.hashcode() + ";create"); // add this line whenever a
// new ResultSet is created
and
rs.close();
Util.writeln(rs.hashcode() + ";closed"); // add this line whenever a
// ResultSet is closed
Open the csv file with Excel or any other spread sheet program, sort the table and look if result sets are not closed. If this is the case, add more debug information to clearly identify the open sets.
BTW - Wrapping the interfaces (like JAMon) is pretty easy, if you have eclipse or something else, its coded in less then 15 Minutes. You'd need to wrap Connection, Statement (and PreparedStatement?) and ResultSet, the ResultSet wrapper could be instrumented to track and monitor creation and closing of result sets:
public MonitoredConnection implements Connection {
Connection wrappedConnection = null;
public MonitoredConnection(Connection wrappedConnection) {
this.wrappedConnection = wrappedConnection;
}
// ... implement interface methods and delegate to the wrappedConnection
#Override
public Statement createStatement() {
// we need MonitoredStatements because later we want MonitoredResultSets
return new MonitoredStatement(wrappedConnection.createStatemet());
}
// ...
}
The same for MonitoredStatement and MonitoredResultSet (MonitoredStatement will return wrapped ResultSets):
public MonitoredStatement implements Statement {
private Statement wrappedStatement = null;
#Override
public ResultSet executeQuery(String sql) throws SQLException
MonitoredResultSet rs = wrappedStatement.executeQuery(sql);
ResultSetMonitor.create(rs.getWrappedResultSet()); // some static utility class/method
return rs;
}
// ...
}
and
public MonitoredResultSet implements ResultSet {
private ResultSet wrappedResultSet;
#Override
public void close() {
wrappedResultSet.close();
ResultSetMonitor.close(wrappedResultSet); // some static utility class/method
}
// ...
}
At the end, you should only need to modify a single line in your code:
Connection con = DriverManager.getConnection(ur);
to
Connection con = new MonitoredConnection(DriverManager.getConnection(ur));
A Google Search pointed me directly to JAMon. It allows you to also monitor JDBC connections and cursors.
Personally, I would check the code and make sure that all Statement, PreparedStatement and ResultSet are closed when not needed. Even when using Connection Pooling, only JDBC Connection are returned into the pool and statements and ResultSet are closed.
This example shows how I achieve closing ResultSet and PreparedStatement in the finally close (for guarantee):
PreparedStatement ps = null;
ResultSet rs = null;
UserRequest request = null;
try {
ps = getConnection().prepareStatement(SQL_RETRIEVE);
ps.setLong(1, id);
rs = ps.executeQuery();
if (rs != null && rs.next()) {
request = mapEntity(rs);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
throw new DAOException(e);
} finally {
try {
close(rs, ps);
} catch (SQLException e) {
// TODO Auto-generated catch block
logger.error("Error closing statement or resultset.", e);
}
}
That's my 2 cents worth...hope it helps you.
It should be relatively simple to instrument your code with AOP of your choice. I was using AspectWerkz number of years ago to do load-time weaving of web app and collecting performance related statistics. Also if you're using IOC framework, such as Spring it's very easy to wrap your DataSources and trace calls to getConnection() etc.