This question already has answers here:
java.sql.SQLException: - ORA-01000: maximum open cursors exceeded
(14 answers)
Closed 5 years ago.
I have got ORA-0300: maximum open cursors exceeded exception
public void connectionexample(String email)
{
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = db.getConnection();
ps = conn.prepareStatement(select_query);
ps.setString(1, email);
rs = ps.executeQuery();
if(rs.next()) {
ps = conn.prepareStatement(update_query);
ps.setString(1, email);
ps.executeUpdate();
} else {
ps = conn.prepareStatement(insert_query);
ps.setString(1, email);
ps.executeUpdate();
}
} catch(Exception e) {
LOG.error("Exception occured ", e);
} finally {
DATABASE.release(rs);
DATABASE.release(ps);
DATABASE.release(conn);
}
}
You get this error because you are using the same PrepapredStatement multiple time :
ps = conn.prepareStatement(select_query);//<<----------------------Here
...
if (rs.next()) {
ps = conn.prepareStatement(update_query);//<<-------------------Then here
...
} else {
ps = conn.prepareStatement(insert_query);//<<-------------------or here
...
}
To solve your problem you have to close your statement and create a new one for the new query, or for better way, separate the actions in a different methods which each one create and release its statement and connection.
You are re-using the prepared statement ps:
public void connectionexample(String email)
{
Connection conn = null;
PreparedStatement ps = null;
PreparedStatement ps2 = null; -- Use another variable for the second prepared statement
ResultSet rs = null;
try {
conn = db.getConnection();
ps = conn.prepareStatement(select_query);
ps.setString(1, email);
rs = ps.executeQuery();
if(rs.next()) {
ps2 = conn.prepareStatement(update_query); -- Assign this to the second variable
} else {
ps2 = conn.prepareStatement(insert_query);
}
ps2.setString(1, email);
ps2.executeUpdate();
} catch(Exception e) {
LOG.error("Exception occured ", e);
} finally {
DATABASE.release(rs);
DATABASE.release(ps);
DATABASE.release(ps2); -- Make sure you also close the second prepared statement
DATABASE.release(conn);
}
}
However, you could get rid of the second round-trip to the database by using the SQL MERGE statement.
Related
public void insertTags(Elements[] elements) {
Connection con = (Connection) DbConnection.getConnection();
try {
String sql = "insert into htmltags(source) values(?),(?),(?)";
PreparedStatement ps = (PreparedStatement) con.prepareStatement(sql);
ps.setString(1, elements[0].toString());
ps.setString(2, elements[1].toString());
ps.setString(3, elements[2].toString());
int rs = ps.executeUpdate(sql);
System.out.println("Data inserted" + rs);
} catch (SQLException e) {
e.printStackTrace();
}
}
is this a valid syntax for Prepared statement.
This is your problem:
int rs = ps.executeUpdate(sql);
From the JavaDoc we see that PreparedStatement#executeUpdate() does not take any parameters. The reason is that we already passed the query earlier when preparing the statement. Your code should be this:
int rs = ps.executeUpdate(); // no parameter
Also no need to cast the result of prepareStatement to PrepareStatement
To insert multiple values, I don't thing using values(?),(?),(?) is the right syntax, instead use a loop, or for better way you can use batch :
String sql = "insert into htmltags(source) values(?)";
try (PreparedStatement ps = con.prepareStatement(sql);) {
for (Elements element : elements) {
ps.setString(1, element.toString());
ps.addBatch();//Add a new batch for each Element
}
int[] result = ps.executeBatch();//Submits a batch of commands to the database
} catch (SQLException e) {
e.printStackTrace();
}
I know many questions were asked before for this issue but for this situations I can't find an answer.
This is my code:
private Collection<Coupon> getCouponsMain(Company company, String filters) throws DAOException
{
String sql = null;
if (filters != null)
{
sql = "SELECT couponsystem.coupon.* FROM couponsystem.company_coupon LEFT JOIN couponsystem.coupon ON "
+ "couponsystem.company_coupon.COUPON_ID = couponsystem.coupon.ID WHERE couponsystem.company_coupon.COMP_ID = ? AND ?";
}
else
{
sql = "SELECT couponsystem.coupon.* FROM couponsystem.company_coupon LEFT JOIN couponsystem.coupon ON "
+ "couponsystem.company_coupon.COUPON_ID = couponsystem.coupon.ID WHERE couponsystem.company_coupon.COMP_ID = ?";
}
try (Connection con = pool.OpenConnection(); PreparedStatement preparedStatement = con.prepareStatement(sql);)
{
// query command
preparedStatement.setLong(1, company.getId());
if (filters != null)
{
preparedStatement.setString(2, filters);
}
ResultSet rs = preparedStatement.executeQuery();
if (rs.next())
{
CouponDBDAO couponDao = new CouponDBDAO();
rs.previous();
return couponDao.BuildCoupons(rs);
}
else
{
return null;
}
}
catch (SQLException | NullPointerException e)
{
throw new DAOException("Failed to retrieve data for all coupons" + e.getMessage());
}
}
I think the query itself is not the important issue here but, once I use next() for the ResultSet, I get the error:
java.sql.SQLException: Operation not allowed after ResultSet closed"
This usually happened when using two rs for same statement, this is not the case this time.
Due to many issues with previous method and BuildCoupons(rs) issue, also this part does not work properly for the same reason:
#Override
public Company getCompany(long id) throws DAOException
{
String sql = "SELECT * FROM couponsystem.company WHERE ID = ?";
try (Connection con = pool.OpenConnection(); PreparedStatement preparedStatement = con.prepareStatement(sql);)
{
// query command
preparedStatement.setLong(1, id);
// query execution
ResultSet rs = preparedStatement.executeQuery();
Company comp = new Company();
if (rs.next())
{
//Fill customer object from Customer table
comp.setId(rs.getLong("ID"));
comp.setCompName(rs.getString("COMP_NAME"));
comp.setPassword(rs.getString("PASSWORD"));
comp.setEmail(rs.getString("EMAIL"));
comp.setCoupons(comp.getCoupons());
}
else
{
comp = null;
}
return comp;
}
catch (SQLException e)
{
throw new DAOException("Failed to retrieve data for customer id: " + id);
}
}
BTW - working with MySQL and insert, update and delete queries are working properly so there not issue with the connection to the db
Another update -
Once i replace it to regular statement, it's working but of course i'm losing all the advantages of prepared statement
Like i said i create new code in order to isolate the big program
This is the code:
public class testState
{
public static void main(String[] args) throws SQLException
{
DBDAO pool = DBDAO.getInstance();
String sql = "SELECT ID FROM couponsystem.company WHERE COMP_NAME = ? AND PASSWORD = ?";
String compName = "t";
String password = "t";
pool.CreatePool();
Connection con = pool.OpenConnection();
PreparedStatement preparedStatement = con.prepareStatement(sql);
preparedStatement.setString(1, compName);
preparedStatement.setString(2, password);
preparedStatement.executeQuery();
ResultSet rs = preparedStatement.executeQuery();
System.out.println("rs status: " + rs.isClosed());
if (rs.next())
{
System.out.println("log-in was successfuly performed");
System.out.println(rs.getLong(1));
System.out.println("hjhjh");
}
else
{
System.out.println("-1");
}
rs.close();
preparedStatement.close();
con.close();
pool.CloseConnection();
}
}
Problem was solved,
this is the problem:
sql = "SELECT couponsystem.coupon.* FROM couponsystem.company_coupon LEFT JOIN couponsystem.coupon ON "
+ "couponsystem.company_coupon.COUPON_ID = couponsystem.coupon.ID WHERE couponsystem.company_coupon.COMP_ID = ? AND ?";
the second ? is illegal, but the exception is ResultSet closed and not query issue
the problem is you are trying to go back to the previous record in the result set which is not possible.
learn about scrollable resultset and make it insensitive, once you use this you can go back to the previous record by using rs.previous()
ResultSet.TYPE_SCROLL_INSENSITIVE
I have two methods below for checking if a match is in the database and if not if would call the insert method. My program has to go through thousands of rows and it takes a very long time. Am I doing this incorrectly? Anything I can do to significantly make this faster?
public Boolean isMatchIdInDatabase(String matchId) throws SQLException
{
Connection conn = null;
PreparedStatement pst = null;
ResultSet rs = null;
Boolean exists = false;
try
{
Class.forName("org.postgresql.Driver");
conn = DriverManager.getConnection(url, props);
pst = conn.prepareStatement("SELECT COUNT(*) FROM match where match_id = ?");
pst.setString(1, matchId);
rs = pst.executeQuery();
while (rs.next())
{
exists = rs.getBoolean(1);
}
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
pst.close();
rs.close();
conn.close();
}
return exists;
}
public Boolean insertMatchId(String matchId, String name, Timestamp birthdate, String bio, String accountId) throws SQLException, ClassNotFoundException
{
Connection conn = null;
PreparedStatement pst = null;
Boolean exists = false;
try
{
Class.forName("org.postgresql.Driver");
conn = DriverManager.getConnection(url, props);
pst = conn.prepareStatement("INSERT INTO match (match_id, name, birthdate, bio, account_id) values(?, ? , ?, ?, ?)");
pst.setString(1, matchId);
pst.setString(2, name);
pst.setTimestamp(3, birthdate);
pst.setString(4, bio);
pst.setString(5, accountId);
pst.executeUpdate();
}
finally
{
pst.close();
conn.close();
}
return exists;
}
Are you calling first isMatchIdInDatabase then insertMatchId for many records?
Possible duplicate: Efficient way to do batch INSERTS with JDBC
It is an expensive operation to open a connection and query for a single record. If you do that thousands of times, it gets very slow. You should try to restructure your query so that you only use one SELECT. Then you can collect the records which you have to insert and doing it with batch insert.
You could try changing your SQL query that inserts the row to insert only if the row isn't in the database by using WHERE NOT EXISTS.
This post seems to be relevant - I know it's for MySQL instead of PostgreSQL but the principles should be the same.
MySQL Conditional Insert
This question already has answers here:
How should I use try-with-resources with JDBC?
(5 answers)
Closed 8 years ago.
Yesterday multiple people on Stack recommended using try-with-resources. I am doing this for all my database operations now. Today I wanted to change Statement to PreparedStatement to make the queries more secure. But when I try to use a prepared statement in try-with-resources I keep getting errors like 'identifier expected' or ';' or ')'.
What am I doing wrong? Or isnt this possible? This is my code:
try (Connection conn = DriverManager.getConnection(DBURL, DBUSER, DBPASS);
PreparedStatement stmt = conn.prepareStatement("SELECT id FROM users WHERE id = ? LIMIT 1");
stmt.setInt(1, user);
ResultSet rs = stmt.executeQuery()) {
// if no record found
if(!rs.isBeforeFirst()) {
return false;
}
// if record found
else {
return true;
}
} catch (SQLException e) {
// log error but dont do anything, maybe later
String error = "SQLException: " + e.getMessage() + "\nSQLState: " + e.getSQLState() + "\nVendorError: " + e.getErrorCode();
return false;
}
A try-with-resource statement is used to declare (Autoclosable) resources. Connection, PreparedStatement and ResultSet are Autoclosable, so that's fine.
But stmt.setInt(1, user) is NOT a resource, but a simple statement. You cannot have simple statements (that are no resource declarations) within a try-with-resource statement!
Solution: Create multiple try-with-resource statements!
try (Connection conn = DriverManager.getConnection(DBURL, DBUSER, DBPASS)) {
executeStatement(conn);
} catch (SQLException e) {
// log error but dont do anything, maybe later
String error = "SQLException: " + e.getMessage() + "\nSQLState: " + e.getSQLState() + "\nVendorError: " + e.getErrorCode();
return false;
}
private void executeStatement(Connection con) throws SQLException {
try (PreparedStatement stmt = conn.prepareStatement("SELECT id FROM users WHERE id=? LIMIT 1")) {
stmt.setInt(1, user);
try (ResultSet rs = stmt.executeQuery()) {
// process result
}
}
}
(Please note that technically it is not required to put the execution of the SQL statement into a separate method as I did. It also works if both, opening the connection and creating the PreparedStatement are within the same try-with-resource statement. I just consider it good practice to separate connection management stuff from the rest of the code).
try this code:
try (Connection conn = DriverManager.getConnection(DBURL, DBUSER, DBPASS)) {
PreparedStatement stmt = conn.prepareStatement("SELECT id FROM users WHERE id = ? LIMIT 1");
stmt.setInt(1, user);
ResultSet rs = pstmt.executeQuery())
// if no record found
if(!rs.isBeforeFirst()) {
return false;
}
// if record found
else {
return true;
}
} catch (SQLException e) {
// log error but dont do anything, maybe later
String error = "SQLException: " + e.getMessage() + "\nSQLState: " + e.getSQLState() + "\nVendorError: " + e.getErrorCode();
return false;
}
note that here, resource is your Connection and you have to use it in the try block ()
Move
stmt.setInt(1, user);
ResultSet rs = stmt.executeQuery()
...within the try{ /*HERE*/ }
This is because stmt is the resource being created try (/*HERE*/) {} to be used try{ /*HERE*/ }
Try-with-resources
try (/*Create resources in here such as conn and stmt*/)
{
//Use the resources created above such as stmt
}
The point being that everything created in the resource creation block implements AutoClosable and when the try block is exited, close() is called on them all.
In your code stmt.setInt(1, user); is not an AutoCloseable resource, hence the problem.
This question already has answers here:
Cannot issue data manipulation statements with executeQuery()
(11 answers)
Closed 6 years ago.
I can't seem to work out the bug. I need the ResultSet though to get the actual Object. The error is: java.sql.SQLException: Can not issue data manipulation statements with executeQuery(). at rs = pst.executeQuery();. Code:
Connection con = null;
PreparedStatement pst = null;
ResultSet rs = null;
String url = null; //Set, but not visible in code.
String user = null; //Set, but not visible in code.
String password = null; //Set, but not visible in code.
public Object get(String table, String key){
try {
con = DriverManager.getConnection(url, user, password);
String query = "SELECT * FROM `" + table + "` WHERE key = ?;";
pst = con.prepareStatement(query);
pst.setString(1, key);
pst.executeUpdate();
rs = pst.executeQuery();
rs.next();
return rs.getObject(1);
} catch (SQLException ex) {
return null;
} finally {
try {
if (rs != null) {
rs.close();
}
if (pst != null) {
pst.close();
}
if (con != null) {
con.close();
}
} catch (SQLException ex) {
return null;
}
}
}
donot use executeQuery use executeUpdate that your sql statement is
between (update,insert,delete) see
https://docs.oracle.com/javase/7/docs/api/java/sql/Statement.html#executeUpdate(java.lang.String)