Using JDBC driver, how can I use multiple result sets from different queries without continually opening and closing the connections, as it stand im extracting w.e I need and passing it to another method. Each time opening a new conn,statement and resultset
public static void OppQuery() {
Connection conn = null;
Statement stmt = null;
ResultSet result_set = null;
try {
Class.forName(JDBC_DRIVER);
conn = DriverManager.getConnection(DB_URL);
stmt = conn.createStatement();
String emailInfoQuery = "FROM WHERE";
}
public static void addQuery(String latestRenewalId) {
Connection conn = null;
Statement stmt = null;
ResultSet result_set = null;
try {
Class.forName(JDBC_DRIVER);
conn = DriverManager.getConnection(DB_URL);
stmt = conn.createStatement();
String new_AddressLine1, new_AddressLine2;
new_AddressLine1=new_AddressLine2="";
int new_ChannelOption= 0;
}
I tried to use multiple result sets in one method but it kept throwing exceptions saying the result set was closed. I don't have much experience with SqlServver so any guidance would help :-)
In JDBC, when the connection is in auto-commit mode (which is the default), any execution of a statement will commit the previous transaction and close any open result sets on the same connection (assuming the holdability is ResultSet.CLOSE_CURSORS_AT_COMMIT, which actually isn't the default for SQL Server). When you need to have multiple result sets open, you need to have auto-commit disabled (or use ResultSet.HOLD_CURSORS_OVER_COMMIT) and you need to use multiple Statement objects. JDBC requires that a new execute on the same Statement object closes any other open result sets from that same statement.
So
Disable auto-commit (Connection.setAutoCommit(false))
Use multiple Statement objects to open the ResultSets
Further to Mark's answer, since the Microsoft SQL Server JDBC driver seems to create "Holdable" ResultSet objects by default, the following test code does work when AutoCommit is enabled:
import java.sql.*;
public class SqlServerTest {
public static void main(String[] args) {
try {
String connectionUrl =
"jdbc:sqlserver://localhost:52865;" +
"databaseName=myDb;" +
"integratedSecurity=true";
Connection con = DriverManager.getConnection(connectionUrl);
System.out.println(String.format("con.getAutoCommit returned %s", con.getAutoCommit()));
Statement st1 = con.createStatement();
ResultSet rs1 = st1.executeQuery("SELECT id FROM odds");
rs1.next();
System.out.println(String.format("value from rs1: %d", rs1.getInt(1)));
Statement st2 = con.createStatement();
ResultSet rs2 = st2.executeQuery("SELECT id FROM evens");
rs2.next();
System.out.println(String.format("value from rs2: %d", rs2.getInt(1)));
rs1.next();
System.out.println(String.format("value from rs1: %d", rs1.getInt(1)));
rs2.next();
System.out.println(String.format("value from rs2: %d", rs2.getInt(1)));
rs2.close();
rs1.close();
con.close();
} catch(Exception e) {
e.printStackTrace();
}
}
}
For test data in tables named [odds]...
id description
-- -----------
1 one
3 three
5 five
...and [evens]...
id description
-- -----------
2 two
4 four
6 six
...the console output is:
con.getAutoCommit returned true
value from rs1: 1
value from rs2: 2
value from rs1: 3
value from rs2: 4
Related
For the life of me I cannot see how it "is already closed"
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class RsetTest2 {
public static void main(String[] args) throws Exception {
String dbpath = "jdbc:h2:c:/mydb;IFEXISTS=TRUE;DB_CLOSE_ON_EXIT=FALSE;AUTO_SERVER=TRUE";
Connection conn = null;
System.setProperty("h2.bindAddress", "127.0.0.1");
Class.forName("org.h2.Driver");
conn = DriverManager.getConnection(dbpath, "sa", "sa");
conn.setAutoCommit(false);
System.out.println("success. querying database for latest values...");
Statement qry = conn.createStatement();
String sql = "select id from CONSTITUENTS where manager = 'abc' limit 1";
ResultSet rset = qry.executeQuery(sql);
while (rset.next()) {
int id = rset.getInt("id");
System.out.println(id);
qry.executeUpdate("insert into PAYREQUESTS (constituent, inblock) values (" + id + ", 238)");
}
rset.close();
qry.close();
}
}
here is the output:
success. querying database for latest values...
103
Exception in thread "main" org.h2.jdbc.JdbcSQLException: The object is already closed [90007-196]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
at org.h2.message.DbException.get(DbException.java:179)
at org.h2.message.DbException.get(DbException.java:155)
at org.h2.message.DbException.get(DbException.java:144)
at org.h2.jdbc.JdbcResultSet.checkClosed(JdbcResultSet.java:3208)
at org.h2.jdbc.JdbcResultSet.next(JdbcResultSet.java:130)
at RsetTest2.main(RsetTest2.java:22)
where 22 corresponds to the "while (rset.next()) {" line
the DB is returning values, see that println statement that gives us 103.
and even weirder, if I // comment out the executeUpdate line, it all completes normally
Exception in thread "main" org.h2.jdbc.JdbcSQLException: The object is already closed [90007-196]
Your problem is that you are reusing the SQL Statement inside of your while loop. As soon as you call the qry.executeUpdate(...) method in the loop, the ResultSet rset associated with the previous statement is closed, hence the error. It is the while(rset.next()) statement that is called after the first executeUpdate(...) in the loop that fails.
If you use a new statement in the loop then it should work.
Statement qry = conn.createStatement();
String sql = "select id from CONSTITUENTS where manager = 'abc' limit 1";
ResultSet rset = qry.executeQuery(sql);
while (rset.next()) {
int id = rset.getInt("id");
System.out.println(id);
// we can't reuse the same Statement here so we need to create a new one
conn.createStatement().executeUpdate("insert into PAYREQUESTS ...");
}
You might consider keeping a collection of necessary updates and then issue the updates at the end of the loop.
and even weirder, if I // comment out the executeUpdate line, it all completes normally
Yep, that sounds right. Not weird at all. :-)
Also for simplifying your code you can use try-with-resources statement that utilizes
java.lang.AutoCloseable interface, thus you can get rid of lines:
rset.close();
qry.close();
The whole block can look somehow like this:
try (ResultSet rset = conn.createStatement().executeQuery("select id from CONSTITUENTS where manager = 'abc' limit 1")) {
String insertSQL = "insert into PAYREQUESTS (constituent, inblock) values ('%d', 238)";
while (rset.next()) {
int id = rset.getInt("id");
Savepoint savePoint = conn.setSavepoint("beforeInsert");
try {
conn.createStatement().executeUpdate(String.format(insertSQL, id));
conn.commit();
} catch (SQLException ex) {
conn.rollback(savePoint);
//log exception
}
}
} catch (SQLException e) {
//log exception
}
Since your connection has auto-commit mode equals false maybe it make sense to possible harmful action.
I have two SQL server running on two different location having same structure but different IP a = 100.0.0.1 and IP b = 192.0.0.1. I have a table a.table and b.table of same structure. Now i want to move all data that is in a. Table from 100.0.0.1 machine to b.table machine 192.0.0.1 .I want to transfer this data using java either connection or by hibernate. Currently i am doing this manually by running SQL query.
Here is the code you can use
import java.sql.*;
import java.io.*;
import java.util.*;
public class test1
{
public static void main(String[] argv) throws Exception
{
try
{
Connection con = DriverManager.getConnection( "jdbc:postgresql://localhost:5432/old","user","pass");
Connection con1 = DriverManager.getConnection( "jdbc:postgresql://localhost:5432/new","user","pass");
String sql = "INSERT INTO users("+ "name,"+ "active,"+ "login,"+ "password)"+ "VALUES(?,?,?,?)";
Statement statement = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
PreparedStatement pstmt = con1.prepareStatement(sql);
ResultSet rs = statement.executeQuery("SELECT * FROM users");
while ( rs.next() )
{
String nm = rs.getString(2);
Boolean ac = rs.getBoolean(3);
String log = rs.getString(4);
String pass = rs.getString(5);
pstmt.setString(1, nm);
pstmt.setBoolean(2, ac);
pstmt.setString(3, log);
pstmt.setString(4, pass);
pstmt.executeUpdate();
}
con.close();
con1.close();
}
catch (SQLException e)
{
System.out.println("could not get JDBC connection: " +e);
}
}
}
Create a connection with something like this
Connection con=DriverManager.getConnection(url, dbProperties);
//then create a query
String query = "select * from a.table";
Statement statement = connect.createStatement(query);
save result in resultset or somewhere else : ResultSet rs = statement.executeQuery(); then create a second connection to your other database like above and call an insert for each result in your resultset. there might be much better methods to insert so much data. i hear about bulk operations but i don't know how they work
If I create a statement with JDBC and execute a query, do I need to close said statement and create a new one before executing again? Eclipse doesn't complain about the second case.
try {
connection = dataSource.getConnection();
try {
statement = connection.createStatement();
statement.execute("set search_path to '...'");
} finally {
Utils.tryClose(statement);
}
try {
statement = connection.createStatement();
statement.execute("SET statement_timeout TO " + (QUERY_TIMEOUT_SECONDS * 1000));
} finally {
Utils.tryClose(statement);
}
try {
statement = connection.createStatement();
statement.execute(query);
} finally {
Utils.tryClose(statement);
}
} finally {
Utils.tryClose(connection);
}
As opposed to:
try {
connection = dataSource.getConnection();
statement = connection.createStatement();
statement.execute("set search_path to '...'");
statement.execute("SET statement_timeout TO " + (QUERY_TIMEOUT_SECONDS * 1000));
statement.execute(query);
} finally {
Utils.tryClose(statement);
Utils.tryClose(connection);
}
That is not required you can use the same statement to query the DB multiple times, the only thing to remember is that each resultset returned with a statement execution will be closed after creating a new statemnet. Quoting from java docs:-
By default, only one ResultSet object per Statement object can be open at the same time. Therefore, if the reading of one ResultSet object is interleaved with the reading of another, each must have been generated by different Statement objects. All execution methods in the Statement interface implicitly close a statment's current ResultSet object if an open one exists.
Hence you can do something like this:-
try {
connection = dataSource.getConnection();
statement = connection.createStatement();
ResultSet rs1=statement.execute("....");
//parse rs1
//close rs1
ResultSet rs2= statement.execute(....);
//parse rs1
//close rs1
} finally {
Utils.tryClose(statement);
Utils.tryClose(connection);
}
I am not sure why eclipse is complaining in case of PreparedStatements, the whole purpose of PreparedStatements is to define a query structure and execute the query multiple times by only changing the parameters. For example when you want to parse and insert a large text file into DB. Quoting from javadocs
If you want to execute a Statement object many times, it usually reduces execution time to use a PreparedStatement object instead.
I'm a novice java programmer and here is my code snippet to delete a record based on it's ID.
private void RemovebuttonActionPerformed(java.awt.event.ActionEvent evt) {
BookIDvar=Integer.parseInt(BookID.getText());
System.out.println(BookIDvar);
Connection conn = null;
Statement stmt = null;
try{
//STEP 2: Register JDBC driver
Class.forName("com.mysql.jdbc.Driver");
//STEP 3: Open a connection
System.out.println("Connecting to database...");
conn = DriverManager.getConnection(DB_URL,USER,PASS);
//STEP 4: Execute a query
System.out.println("Creating statement...");
stmt = conn.createStatement();
String sql;
sql="DELETE FROM book_details WHERE book_id="+BookIDvar+"";
stmt.executeUpdate(sql);
//STEP 6: Clean-up environment
stmt.close();
conn.close();
}
The code is working fine. But i want to check whether if there existed a record with that particular ID. Is there a way to check it using the current code itself? Does Java provide some constructs to check the return value of executUpdate similar to executeQuery?
Answer
int a = stmt.executeUpdate(sql);
System.out.println(a); // ---> Number of columns the query has manipulated in the database
Syntax
int executeUpdate(String sql) throws SQLException
Executes the given SQL statement, which may be an INSERT, UPDATE, or DELETE statement or an SQL statement that returns nothing, such as an SQL DDL statement.
Note that the executeUpdate(); method return type is "int" i.e it returns the number of columns the query has manipulated in the database
When I execute the following code, I get an exception. I think it is because I'm preparing in new statement with he same connection object. How should I rewrite this so that I can create a prepared statement AND get to use rs2? Do I have to create a new connection object even if the connection is to the same DB?
try
{
//Get some stuff
String name = "";
String sql = "SELECT `name` FROM `user` WHERE `id` = " + userId + " LIMIT 1;";
ResultSet rs = statement.executeQuery(sql);
if(rs.next())
{
name = rs.getString("name");
}
String sql2 = "SELECT `id` FROM `profiles` WHERE `id` =" + profId + ";";
ResultSet rs2 = statement.executeQuery(sql2);
String updateSql = "INSERT INTO `blah`............";
PreparedStatement pst = (PreparedStatement)connection.prepareStatement(updateSql);
while(rs2.next())
{
int id = rs2.getInt("id");
int stuff = getStuff(id);
pst.setInt(1, stuff);
pst.addBatch();
}
pst.executeBatch();
}
catch (Exception e)
{
e.printStackTrace();
}
private int getStuff(int id)
{
try
{
String sql = "SELECT ......;";
ResultSet rs = statement.executeQuery(sql);
if(rs.next())
{
return rs.getInt("something");
}
return -1;
}//code continues
The problem is with the way you fetch data in getStuff(). Each time you visit getStuff() you obtain a fresh ResultSet but you don't close it.
This violates the expectation of the Statement class (see here - http://docs.oracle.com/javase/7/docs/api/java/sql/Statement.html):
By default, only one ResultSet object per Statement object can be open at the same time. Therefore, if the reading of one ResultSet object is interleaved with the reading of another, each must have been generated by different Statement objects. All execution methods in the Statement interface implicitly close a statment's current ResultSet object if an open one exists.
What makes things even worse is the rs from the calling code. It is also derived off-of the statement field but it is not closed.
Bottom line: you have several ResultSet pertaining to the same Statement object concurrently opened.
A ResultSet object is automatically
closed when the Statement object that
generated it is closed, re-executed,
or used to retrieve the next result
from a sequence of multiple results.
I guess after while(rs2.next()) you are trying to access something from rs1. But it's already closed since you reexecuted statement to get rs2 from it. Since you didn't close it, I beleive it's used again below.