I'm not sure the best practice for this, but my overall problem is that I can't figure out why my connection isn't closing.
I'm basically iterating through a list, and then inserting them into a table. Before I insert them into a table, I check and make sure it's not a duplicate. if it is, I update the row instead of inserting it. As of now, I can only get 13 iterations to work before the debug lets me know I had a connection not close.
Since I have 2 connections, I'm having trouble figuring out where I'm suppose to close my connections, and I was trying to use other examples to help. Here is what I got:
Connection con = null;
PreparedStatement stmt = null;
PreparedStatement stmt2 = null;
ResultSet rs = null;
Connection con2 = null;
for (Object itemId: aList.getItemIds()){
try {
con = cpds2.getConnection();
stmt = con.prepareStatement("select [ID] from [DB].[dbo].[Table1] WHERE [ID] = ?");
stmt.setInt(1, aList.getItem(itemId).getBean().getID());
rs = stmt.executeQuery();
//if the row is already there, update the data/
if (rs.isBeforeFirst()){
System.out.println("Duplicate");
stmt2 = con2.prepareStatement("UPDATE [DB].[dbo].[Table1] SET "
+ "[DateSelected]=GETDATE() where [ID] = ?");
stmt2.setInt(1,aList.getItem(itemId).getBean().getID());
stmt2.executeUpdate();
}//end if inserting duplicate
else{
con2 = cpds2.getConnection();
System.out.println("Insertion");
stmt.setInt(1, aList.getItem(itemId).getBean().getID());
//Otherwise, insert them as if they were new
stmt2 = con.prepareStatement("INSERT INTO [DB].[dbo].[Table1] ([ID],[FirstName],"
+ "[LastName],[DateSelected]) VALUES (?,?,?,?)");
stmt2.setInt(1,aList.getItem(itemId).getBean().getID() );
stmt2.setString(2,aList.getItem(itemId).getBean().getFirstName());
stmt2.setString(3,aList.getItem(itemId).getBean().getLastName() );
stmt2.setTimestamp(4, new Timestamp(new Date().getTime()));
stmt2.executeUpdate();
}//End Else
}catch(Exception e){
e.printStackTrace();
}//End Catch
finally{
try { if (rs!=null) rs.close();} catch (Exception e) {}
try { if (stmt2!=null) stmt2.close();} catch (Exception e) {}
try { if (stmt!=null) stmt.close();} catch (Exception e) {}
try { if (con2!=null) con2.close();} catch (Exception e) {}
try {if (con!=null) con.close();} catch (Exception e) {}
}//End Finally
} //end for loop
Notification.show("Save Complete");
This is my pooled connection:
//Pooled connection
cpds2 = new ComboPooledDataSource();
try {
cpds2.setDriverClass("net.sourceforge.jtds.jdbc.Driver");
} catch (PropertyVetoException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} //loads the jdbc driver
cpds2.setJdbcUrl( "jdbc:jtds:sqlserver://SERVERNAME;instance=DB" );
cpds2.setUser("username");
cpds2.setPassword("password");
cpds2.setMaxStatements( 180 );
cpds2.setDebugUnreturnedConnectionStackTraces(true); //To help debug
cpds2.setUnreturnedConnectionTimeout(2); //to help debug
My main questions are, am i closing my connections right? Is my connection pool set up right?
Should I be closing the connection inside the for loop or outside?
Is my problem with c3p0? Or JTDS?
It's great that you are working to be careful to robustly close() your resources, but this is overly complicated.
Unless you are using a pretty old version of Java (something prior to Java 7) you can use try-with-resources, which really simplifies this stuff. Working with two different Connections in one logic unit-of-work invites misunderstandings. Resources should be a close()ed as locally to their use as possible, rather than deferring everything to the end.
Your Exception handling is dangerous. If an Exception occurs that you don't understand, you might want to print its stack trace, but your code should signall the fact that whatever you were doing didn't work. You swallow the Exception, and even notify "Save Complete" despite it.
All this said, your life might be made much easier by a MERGE statement, which I think SQL Server supports.
Here is an (untested, uncompiled) example reorganization:
try ( Connection con = cpds2.getConnection() ) {
for (Object itemId: aList.getItemIds()){
boolean id_is_present = false;
try ( PreparedStatement stmt = con.prepareStatement("select [ID] from [DB].[dbo].[Table1] WHERE [ID] = ?") ) {
stmt.setInt(1, aList.getItem(itemId).getBean().getID());
try ( ResultSet rs = stmt.executeQuery() ) {
id_is_present = rs.next();
}
}
if ( id_is_present ) {
System.out.println("Duplicate");
try ( PreparedStatement stmt = con.prepareStatement("UPDATE [DB].[dbo].[Table1] SET [DateSelected]=GETDATE() where [ID] = ?") ) {
stmt.setInt(1,aList.getItem(itemId).getBean().getID());
stmt.executeUpdate();
}
} else {
System.out.println("Insertion");
try ( PreparedStatement stmt = con.prepareStatement("INSERT INTO [DB].[dbo].[Table1] ([ID],[FirstName], [LastName],[DateSelected]) VALUES (?,?,?,?)") ) {
stmt.setInt(1,aList.getItem(itemId).getBean().getID() );
stmt.setString(2,aList.getItem(itemId).getBean().getFirstName());
stmt.setString(3,aList.getItem(itemId).getBean().getLastName() );
stmt.setTimestamp(4, new Timestamp(new Date().getTime()));
stmt.executeUpdate();
}
}
}
Notification.show("Save Complete");
}
Related
I need to accomplish the following:
1.- Save on different variables each field of a query result (Oracle DB).
The query result could be 1 o more rows (5 average).
2.- Invoke a WebService for each row.
4.- Wait for the WebService answer and then repeat the process.
I think that saving the result of 1 row and then invoke the WebService it easy but the problem is when the query result throws more than 1 row.
How can I do this? Is Arraylist the answer?
EDIT: I am using the following code. How can I print the arraylist to see if the connection is working?
If I run this i get:
com.packagename.SomeBean#1d251891
com.packagename.SomeBean#48140564
com.packagename.SomeBean#58ceff1
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
List<SomeBean> v = new ArrayList<SomeBean>();
String query = "select * from table where ROWNUM BETWEEN 1 and 3";
try
{
Class.forName("oracle.jdbc.driver.OracleDriver");
con = DriverManager.getConnection("jdbc:oracle:thin:user/pass#localhost:port:SID");
stmt = con.createStatement();
rs = stmt.executeQuery(query);
while( rs.next() ){
SomeBean n = new SomeBean();
n.setColumn1(rs.getInt("column1"));
n.setColumn2(rs.getString("column2"));
n.setColumn3(rs.getString("column3"));
n.setColumn4(rs.getInt("column4"));
n.setColumn5(rs.getString("column5"));
n.setColumn6(rs.getString("column6"));
n.setColumn7(rs.getString("column7"));
...
v.add(n);
}
for(SomeBean s : v){
System.out.println(s);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
stmt.close();
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
Answering to your question is quite difficoult.
But I can give you some hints.
Your startpoint is JDBC.
The Java Database Connectivity (JDBC)
The Java Database Connectivity (JDBC) API is the industry standard for database-independent connectivity between the Java programming language and a wide range of databases SQL databases and other tabular data sources, such as spreadsheets or flat files. The JDBC API provides a call-level API for SQL-based database access.
The Java Database Connectivity (JDBC)
Once you are able to establish a connection to the DB, this snippet can help you answering to your question.
// start connection
List<SomeBean> v = new ArrayList<SomeBean>();
Statement st;
try
{
st = conn.createStatement();
ResultSet rs = st.executeQuery(sql);
while( rs.next() ){
SomeBean n = new SomeBean();
n.setFirstField(rs.getInt("firstfield"));
n.setSecondField(rs.getString("secondfield"));
...
...
v.add(n);
}
}
catch (SQLException e)
{
e.printStackTrace();
}
// close connection
Once you have your collection of beans, just write a for loop that calls the webservice one time for each bean.
for(SomeBean s : v){
callToYouWS(s);
}
It is really freaking me out. In my code I hand over a generated uuid as my private Key. Now I want to select from a table with only one value inside (avg_distance_as). Everything works fine when I write the statement with a fix uuid. But because I want to get the specific row with my current uuid, I want to put that in my statement too.
soooo no error nothing - he does not even call the syso in the rs.next loop. This one is working:
public int getavgDistanceAs(String uuid) {
try {
Class.forName("org.sqlite.JDBC");
con = DriverManager.getConnection("jdbc:sqlite:test.db");
statement = con.prepareStatement("Select avg_distance_as, UUID from avg_distance");
System.out.println(uuid);
statement.setString(1, uuid);
ResultSet rs = statement.executeQuery();
while (rs.next()) {
System.out.println(rs.getDouble(1));
System.out.println("test");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
statement.close();
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return 0;
}
But this one isn't and it looks PRETTY much the same:
statement = con.prepareStatement("Select avg_distance_as, UUID from avg_distance where UUID = ?");
statement.setString(1, uuid);
Would be awesome if someone could help :)
OK - got it... I messed up my order in the calculation. #Kayaman was right: uuid was missing at the time needed.
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.
In the below code I want to call one stored procedures and execute one Query. I am facing error at statement.executeUpdate(); Please help in fixing it. I am not sure where it going wrong.
public void Dbexe() {
Connection connection;
connection = DatabaseConnection.getCon();
CallableStatement stmt;
try {
stmt = connection.prepareCall("{CALL optg.Ld_SOpp}");
stmt.executeUpdate();
stmt.close();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.out.println("Stored Procedure executed");
//PreparedStatement statement = null;
// ResultSet rs = null;
try{
PreparedStatement statement;
try {
statement = connection.prepareStatement("MERGE INTO OPTG.R_VAL AS TARGET USING" +
........... +
"");
statement.executeUpdate(); //Here the exception is thrown
statement.close();
connection.commit();
connection.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// statement = connection.prepareStatement(query);
//statement.close();
}
finally{
System.out.println("Data is copied to the Table");
}
}
Little off-topic: You should use CallableStatement instead if you want to call a store procedure (see documentation):
CallableStatement callableStatement = connection.prepareCall("{call opptymgmt.Load_SiebelOpportunity}");
ResultSet rs = callableStatement.executeQuery();
I would also suggest you check this topic How to properly clean up JDBC resources in Java?. It was very helpful to me.
Update: based on this stack trace:
com.ibm.db2.jcc.am.mo: DB2 SQL Error: SQLCODE=-104, SQLSTATE=42601, SQLERRMC=MERGE INTO OPPTYMGMT.REVENUE_VALIDAT;BEGIN-OF-STATEMENT;<variable_set>, DRIVER=4.7.85
The problem seems to be in the sql sentence you're trying to execute. I mean, is an error from DB2, not java. You should check your sql statement.
I got it working in this method:
PreparedStatement myStmt = conn.prepareStatement(sqlQuery);
myStmt.setInt(1, id); //position of parameter (1,2,3....) , value
ResultSet rs = myStmt.executeQuery();
while (rs.next()) {
int jobId = rs.getInt("jobId"); ....... }
Allright been trying to figure this out the last 2 days.
Statement statement = con.createStatement();
String query = "SELECT * FROM sell";
ResultSet rs = query(query);
while (rs.next()){//<--- I get there operation error here
This is the query method.
public static ResultSet query(String s) throws SQLException {
try {
if (s.toLowerCase().startsWith("select")) {
if(stm == null) {
createConnection();
}
ResultSet rs = stm.executeQuery(s);
return rs;
} else {
if(stm == null) {
createConnection();
}
stm.executeUpdate(s);
}
return null;
} catch (Exception e) {
e.printStackTrace();
con = null;
stm = null;
}
return null;
}
How can I fix this error?
It's hard to be sure just from the code you've posted, but I suspect that the ResultSet is inadvertently getting closed (or stm is getting reused) inside the body of the while loop. This would trigger the exception at the start of the following iteration.
Additionally, you need to make sure there are no other threads in your application that could potentially be using the same DB connection or stm object.
IMHO, you should do everything you need with your ResultSet before you close your connection.
there are few things you need to fix. Opening a connection, running a query to get the rs, closing it, and closing the connection all should be done in the same function scope as far as possible. from your code, you seem to use the "con" variable as a global variable, which could potentially cause a problem. you are not closing the stm object. or the rs object. this code does not run for too long, even if it has no errors. Your code should be like this:
if (stringUtils.isBlank(sql)){
throw new IllegalArgumentsException ("SQL statement is required");
}
Connection con = null;
PreparedStatement ps =null;
Resultset rs = null;
try{
con = getConnection();
ps = con.preparestatement(sql);
rs = ps.executeQuery();
processResults(rs);
close(rs);
close(ps);
close(con);
}catch (Execption e){
log.Exception ("Error in: {}", sql, e);
throw new RuntimeException (e);
}finally{
close(rs);
close(ps);
close(con);
}
use another Statement object in inner loop
Like
Statement st,st1;
st=con.createStatement();
st1=con.createStatement();
//in Inner loop
while(<<your code>>)
{
st1.executeQuery(<<your query>>);
}
I know this is a few years late, but I've found that synchronizing the db methods usually get rid of this problem.