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.
Related
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.
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 have a function to insert data using JDBC but it works just for one record how can insert multiple records dynamicaly
public void insertInfo() throws Exception{
try{
int codeNat = getNat();
String query = "INSERT INTO info (id,name,code_nat) VALUES (?,?,?)";
stat = cnx.prepareStatement(query);
stat.setString(1, txtId.getText());
stat.setString(2, txtName.getText());
stat.setInt(3, codeNat);
stat.execute();
Update_table();
}catch(SQLException ex){
JOptionPane.showMessageDialog(null,ex);
}
finally{
try{
stat.close();
cnx.close();
}catch(Exception e){
}
}
}
the exception i had "No operations allowed after connection closed."
You are closing your connection (cnx) in the finally of your method. This will close the connection the first time you insert (whether it fails or passes) and then the connection will still be closed the next time you come along to insert. You can try moving the connection opening into this method if you like, but connection can be expensive to open/close, perhaps move the closing/opening outside this method. It's really hard to say until we see more of the code you're working on.
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.