log unclosed PreparedStatement using c3p0 - java

Using c3p0 I can log unclosed Connection by setting properties debugUnreturnedConnectionStackTraces and
unreturnedConnectionTimeout. I wonder if is there any way to find out unclosed PreparedStatement because today I found a code as below:
...
ps=dbConnection.prepareStatement(qry);
rs=ps.executeQuery();
if(!rsCandItem.next())//to check Result Set has rows
{
rs.close();
qry = "SELECT * FROM TABLE1";
ps=dbConnection.prepareStatement(qry); //same PreparedStatement object is used without closing previous instance
rs=ps.executeQuery();
}
...
I guess using same PreparedStatement object (ps) without closing it is wrong/bad practice, correct me if I am wrong. So I want to log using c3p0 (or by any other way) unclosed PreparedStatement. Is there any way?

Unless the driver is broken, closing a Connection should also close associated statements and ResultSets. As you said, it is bad practice to not close them even if in particular cases they might not cause problems.
Since connection pools deal with Connections (and they're the ones that will leak resources), it's unlikely that there are settings for observing anything else.

Related

Using resultset data after closing the connection

I'm trying to write a small code snippet where I need to get some data from a database and then process the result in some other java file. I tried writing a program and the execution for the same was failing with error "Cannot access resultset as the connection was already closed".
Is there any way can we store the result fetched from database some where (Ex.some arraylist) and use it for computation after closing the connection? If yes, can someone please explain it with example?
Slightly handicapped since I'm new to it.
Class A {
public Map<String, Object> loadDat(int acc,Map<String,Object> result)
throws Exception {
Class.forName("com.teradata.jdbc.TeraDriver");
Connection conn = DriverManager.getConnection(connectionString, user, password);
query = "select * from mytable where id="+acc;
PreparedStatement stmt = conn.prepareStatement(query);
ResultSet rs=stmt.executeQuery();
result.put(" Result", rs) ;
return result;
}
}
In general,
don't code JDBC database access by hand.
Libraries already exist that do all the low level JDBC handling now and
they do it correctly.
You will never do it better than an one of the mature,
open source projects already do it.
Instead,
learn and use something like MyBatis.
If you use Spring,
here is a link to the Mybatis-Spring project.
MyBatis conceals all of the data conversion and JDBC junk.
Instead, you define your query in a simple XML file and receive a List
as the result of a query.
Just to add to #DwB's answer that is correct.
You can 1) retrieve all rows from your query into a Java List, 2) then close the connection, and 3) then use the Java List in another class (for further processing).
If you close the connection after retrieving only part of the result set, you'll lose the rest of it and will receive the error you mention. Don't do it this way.

Creating multiple instances of preparedstatement

I am new to jdbc programming. I am creating instance of PreparedStatement multiple times and assigning it to same reference variable. Do I need to close the first instance of PreparedStatement prior to creating second instance of PreparedStatement?
oPrepStmt = oRoot.con.prepareStatement(strSql);
if (strProviderType.length() > 0) {
strSql += " and users.usertype IN (?)";
// DO I need to close prepare statement, before creating another instance of preparestatement and assigning to same reference variable.
// i.e. oPrepStmt.close();
oPrepStmt = oRoot.con.prepareStatement(strSql);
oPrepStmt.setString(2,strProviderType);
}
oPrepStmt.setInt(1,oRoot.getTrUserId());
Does the unclosed first instance of preparedstatement causes resource leaks?
JDBC statements implement AutoCloseable and therefore indicate that should explicitly be closed when no longer needed.
An object that may hold resources (such as file or socket handles)
until it is closed. The close() method of an AutoCloseable object is
called automatically when exiting a try-with-resources block for which
the object has been declared in the resource specification header.
This construction ensures prompt release, avoiding resource exhaustion
exceptions and errors that may otherwise occur.
So as suggested by the Javadoc use a try-with-resources statement:
try (PreparedStatement pstmt = oRoot.con.prepareStatement(strSql)) {
... run sql commands ...
}
In your example you create a statement and discard it for some cases. Better to avoid this and write like:
boolean checkUserType = strProviderType.length();
try (PreparedStatement pstmt = oRoot.con.prepareStatement(checkUserType ? strSql : strSql + " and users.usertype IN (?)") {
oPrepStmt.setInt(1,oRoot.getTrUserId());
if (checkUserType)
oPrepStmt.setString(2,strProviderType);
...
}
You should always close a statement when you are done with it. In some databases/JDBC drivers, a statement also has a serverside handle. Not closing the statement will leave that handle open on the server, causing unnecessary resource consumption (mostly memory, but it might lock certain metadata objects).
On top of that on the driver side not closing the statement could also have additional resource consumption (memory, listeners to connection events, etc). Closing as soon as possible is therefor advisable.
A driver will likely deallocate this eventually, either through a finalizer, or when you close the connection, but it is not a good idea to rely on that (eg connections in a connection pool do not always correctly close statements when they are returned to the pool, etc).
Now as to your specific problem, you should modify your code to something like:
if (strProviderType.length() > 0) {
strSql += " and users.usertype IN (?)";
}
try (PreparedStatement oPrepStmt = oRoot.con.prepareStatement(strSql)) {
oPrepStmt.setInt(1,oRoot.getTrUserId());
if (strProviderType.length() > 0) {
oPrepStmt.setString(2, strProviderType);
}
oPrepStmt.execute(); // or executeQuery or executeUpdate
}
I also included a try-with-resources to ensure the statement is closed as soon as possible.
BTW, likely your use of IN(?) is not going to work like this on most (all?) databases. See PreparedStatement IN clause alternatives?

JDBC: Do I Need to Reset fetchSize on a Statement That is Guaranteed to be Closed?

Following an example in a book I am querying a table by using setFetchSize(). The book mentions to reset setAutoCommit() and setFetchSize() (the book doesn't close statement and connection in its example, so my snippet differs).
val connection = db.getConnection()
val statement = connection.prepareStatement(sql)
connection.setAutoCommit(false)
statement.setFetchSize(25)
try {
...
} finally {
statement.setFetchSize(0) // Do I need to call it if I close the stmt?
connection.setAutoCommit(true)
statement.close()
connection.close()
}
Resetting auto commit makes sense to me, because I guess after close() the connection object might be reused in a connection-pool at a later point.
However, I am curious if I need to reset the fetch size in that case. The Javadoc for connection.prepareStatement() in java.sql.Connection states:
#return a new default PreparedStatement object containing the pre-compiled SQL statement
Am I right that when closing statement I wouldn't need to reset the fetch size by calling setFetchSize(0) in the finally block?
Once a Statement is closed, it cannot be reused. There's no harm per se in resetting the fetchSize, but it doesn't serve any useful purpose.
If you close the statement you can't reuse it so anything you do on it right before or after closing would'nt change a thing.Same for the connection once you closed it you can't reuse it.(to the best of my knowledge)

NullPointerException while setting prepared statement parameters

I think this is a bug.
I'm using latest MySQL JDBC library.
I have multiple threads. Each thread execute a query and for each row add a batch to a prepared statement.
Sometimes the instruction "stmt.setLong(i, aLong)" launch a NullPointerException.
stmt,i and aLong are not null.
PreparedStatement stmt = db.prepareStatement("myinsert");
while (rs.next()) {
long aLong = rs.getLong(1);
...
stmt.setLong(1,aLong);
stmt.addBatch();
}
Here is the exception:
java.lang.NullPointerException
at com.mysql.jdbc.ConnectionImpl.getServerCharacterEncoding(ConnectionImpl.java:3124)
at com.mysql.jdbc.PreparedStatement.setInternal(PreparedStatement.java:3729)
at com.mysql.jdbc.PreparedStatement.setLong(PreparedStatement.java:3751)
at org.apache.commons.dbcp2.DelegatingPreparedStatement.setLong(DelegatingPreparedStatement.java:127)
at org.apache.commons.dbcp2.DelegatingPreparedStatement.setLong(DelegatingPreparedStatement.java:127)
at com.mypackage.MyClass$MyThread.run(MyClass.java:117)
If I launch only one thread, it works.
The exception also occurs without apache dbcp2 library.
I'm going crazy!
I solved the problem removing these lines of codes before creation of the ResultSet
Statement stmt = Database.getDatabase().createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(Integer.MIN_VALUE);
From MySQL documentation here.
The combination of a forward-only, read-only result set, with a fetch size of Integer.MIN_VALUE serves as a signal to the driver to stream result sets row-by-row. After this, any result sets created with the statement will be retrieved row-by-row.

What is the best way/template to set up connection mysql and jdbc?

What is the best way to set up connection with mysql's jdbc?
And execute simple statement. How to do that?
Thank you.
The basic boilerplate for MySQL/JDBC goes something like this:
Get the connection:
Class.forName("com.mysql.jdbc.Driver").newInstance();
Connection conn = DriverManager.getConnection("jdbc:mysql://databaseName");
Execute the statement:
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * from tableName");
while (rs.next()) {
System.out.println(rs.getString(1));
}
Close the statement and connection:
rs.close();
stmt.close();
conn.close();
You just need to make sure you have the driver installed and/or in your CLASSPATH.
This is the twenty first century - use a JPA (ORM) implementation. But if you insist on going back to the metal (at the risk of down votes) -
There are many ways of getting a JDBC connection from some driver. Using reflection with a hardwired class name is the commonest and perhaps most brain damaged. If you're going to hardwire a class name, you might as well as get the benefits of normal code (compiler catches typos, no extraneous exceptions to deal with, easier to read, explicit dependencies, better tool support, etc).
Also get in to the habit of clearing up resources safely.
So:
public static void main(String[] args) throws SQLException {
Driver driver = new com.mysql.jdbc.Driver();
Connection connection = driver.connect(
"jdbc:mysql://mydatabase",
new java.util.Properties() {{
put("user", "fred");
}}
);
try {
PreparedStatement statement = connection.prepareStatement(
"SELECT insideLeg FROM user WHERE name=?"
);
try {
statement.setString(1, "jim");
ResultSet results = statement.executeQuery();
try {
if (results.next() {
System.out.println("= "+results.getLong(1));
} else {
System.out.println("Missing.");
}
} finally {
results.close();
}
} finally {
statement.close();
}
} finally {
connection.close();
}
}
What a mess! And it doesn't even use transactions yet. Yes, use an ORM. They're very respectable these days.
You wont need to do all that for every single statement. You don't want to go around creating instantiating drivers every time. In particular the execute around idiom is useful.
It depends on your case.
If you simply need to execute some queries from standalone application then you should use single connection like:
Class.forName ("yourDriverName");
Connection cn = DriverManager.getConnection ("db url");
Statement st = cn.createStatement ();
ResultSet rs = st.executeQuery ("select * from foo");
while (rs.next()) {
doSmth ();
}
rs.close ();
st.close ();
cn.close ();
But if you are developing real application (specially web-application) then use DataSource's. Read manual of your DB and Web-server how to configure datasource. DataSource allows you to use connection-pooling - it'll nessecary to increase performance.
Configuring DataSource isn't difficult process.
Here's the sun documentation for creating a JDBC connection. From there it's easy to get access to a Statement object and run some simple SQL.
For production level systems you'll probably also want to create a connection pool.
Use Spring Framework's JDBC abstraction framework - all you need to do is create a context XML file, and use the JDBC template class. Just a few lines of XML + Java code will get you going. The advantage is keeping your connection details out of compiled Java. See:
http://www.springbyexample.org/examples/simple-spring-jdbc-template.html

Categories