JDBC Best practice - java

i'm gonna create class that will operate on database. The class will have functions addRecord(), getAllRecords(), stuff like that. I'm looking for a good approach to design the class. Should i have to:
1) create new Connection for every function. Like this:
void readRecords(){
try {
Connection con = DriverManager.getConnection (connectionURL);
Statement stmt = con.createStatement();
ResultSet rs = stmd.executeQuery("select moviename, releasedate from movies");
while (rs.next())
System.out.println("Name= " + rs.getString("moviename") + " Date= " + rs.getString("releasedate");
}
catch (SQLException e) {
e.printStackTrace();
}
catch (Exception e) {
e.printStackTrace();
}
finally {
con.close();
}
}
or
2) it's better to have one connection as a memeber variable
class MyClass{
private Connection con;
public MyClass(){
con = DriverManager.getConnection (connectionURL);
}
}
and create just the statement for every function.
3) or something else...

Both approaches are bad. The first one won't allow you to implement proper transaction management, since you can't call several methods inside the same transaction. The latter one requires unnecessary creation of multiple objects.
The best approach would be to introduce a notion of the current connection, which can be obtained from some kind of transactional context. Basically, it should look like this:
beginTransaction(...); // Opens connection and starts transaction
readRecords(...); // Uses the current connection
addRecord(...);
...
commitTransaction(...); // Commits transaction and closes connection
The simpliest but not very elegant implementation is to open a Connection inside the calling method (which defines boundaries of the transaction) and pass it to your methods as a parameter.
More sophisticated solution is to create a static ThreadLocal storage for the current Connection, place it there when you start a transaction and obtain it from that storage inside your methods. Some frameworks implement this approach implicitly, for example, Spring Framework.
Note that connection pooling is completely orthogonal to these matters.

If there are frequent regular jdbc calls, then use a database connection pool.

Connection pooling is the way to go. The biggest reason is that on average the time it takes for the DB access (DML etc) is much smaller than the time it takes to create a connection and then close the connection. Additionally, don't forget to close your ResultSet, PreparedStatement and Connection variables after the transaction is done.
You can use tomcat or apache connection pooling classes.
THese classes are defined for example in the package
org.apache.commons.dbcp.*;
org.apache.tomcat.dbcp.dbcp.*;
where dbcp stands for database connection pooling.

Related

Multiple DB connections using a connection pool vs Single connection with multiple statements

I am developing a server working with MySQL, and I have been trying to understand advantage of working with a connection pool vs a single connection that is kept open, and being passed down to the different methods through out the application.
The idea of working with a connection pool is understood, however there could be scenarios that this could create a bottleneck, that wouldn't be in case of working without the pool.
Better explain my meaning using code:
Lets say the following method is called simultaneously connectionPoolSize + 1 (e.g. 10) times, meaning that we have exhausted our connections from the connection pool, the last query attempt will fail since no connections available:
public void getData(con) {
Connection con = null;
Statement s = null;
ResultSet rs = null;
try {
con = connectionPool.getConnection();
s = con.createStatement();
rs = s.executeQuery("SELECT * FROM MY_TABLE;");
// Some long process that takes a while....
catch(Exception e) {
throw new Exception(e.getMessage())
} finally {
s.close();
rs.close();
con.close();
}
}
However if we are using a single connection, that is kept open, and all methods can use it, there is no need for any of the methods to wait for the connection to be sent back to pool (which as we saw above, could take some time).
e.g. call this method also 10 times, this would work
public void getData(con) {
Statement s = null;
ResultSet rs = null;
try {
s = con.createStatement();
rs = s.executeQuery("SELECT * FROM MY_TABLE;");
// Some long process that takes a while....
// But this time we don't care that this will take time,
// since nobody is waiting for us to release the connection
catch(Exception e) {
throw new Exception(e.getMessage())
} finally {
s.close();
rs.close();
}
}
Obviously the statements and result sets will still be kept open until the method is finished, but this doesn't affect the connection itself, so it doesn't hold back any other attempts to use this connection.
I assume there is some further insight that I am missing, I understand the standard is working with connection pools, so how do you handle these issues?
Depends on your use case. Suppose you are building a web application that would be used by multiple users simultaneously. Now if you have a single connection, all the queries from multiple user threads will be queued. And single db connection will process them one by one. So in a multi-user system(mostly all normal cases), single db connection will be a bottleneck & won't work. Additionally, you need to take care of thread safety in case you are writing & committing data to db.
If you need truly simultaneous query execution in db, then you should go ahead with connection pool. Then different user threads can use different connections & can execute queries in parallel.
Connection pools are used to keep a number of opened connections ready for use and to eliminate the need to open a new connection each time it is required.
If your application is single threaded then you probably don’t need a pool and can use a single connection instead.
Even though sharing a connection between multiple threads is permitted there are some pitfalls of this approach. Here is a description for Java DB: https://docs.oracle.com/javadb/10.8.3.0/devguide/cdevconcepts89498.html. You should check if this is also the case for MySQL.
In many cases it is easier to have an individual connection for each thread.

Is Postgres JDBC driver `org.postgresql.ds.PGSimpleDataSource` thread-safe?

In the JDBC driver for Postgres, is PGSimpleDataSource thread-safe?
That is, if I use a cached singleton instance of that class, can I pass it out to multiple threads? Each thread may be calling getConnection at the same moment. The documentation makes no mention of thread-safety.
I am trying to avoid both (a) making multi-threaded calls on a Connection and (b) using a connection pool, as discussed in the doc. I want a separate Connection for each servlet thread.
I'm assuming you won't be changing the data source configuration on multiple threads, because then it isn't thread-safe. You can inspect the source code yourself, on https://github.com/pgjdbc/pgjdbc, the specific code for getConnection is in BaseDataSource:
public Connection getConnection(String user, String password) throws SQLException {
try {
Connection con = DriverManager.getConnection(getUrl(), user, password);
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, "Created a {0} for {1} at {2}", new Object[]{getDescription(), user, getUrl()});
}
return con;
} catch (SQLException e) {
LOGGER.log(Level.SEVERE, "Failed to create a {0} for {1} at {2}: {3}",
new Object[]{getDescription(), user, getUrl(), e});
throw e;
}
}
In other words, it is a thin wrapper around DriverManager. DriverManager itself is thread-safe, so then it becomes a question if org.postgresql.Driver is thread-safe. I don't have time to try to verify that, but lets just say it would be really surprising if that wasn't thread-safe (and otherwise world-wide applications would fail with all kinds of strange race-conditions, etc).
As a side note: PGSimpleDataSource does not provide connection pooling, you might want to consider whether that is right for your use case.

How should I model my system - database implication

I have a main class, a login class and a gui class.
Within my main I am creating a database connection using the Singleton pattern - only one instance of this connection.
I want to access the database connection from login, to verify users upon logging into the system.
My connection method within main:
/**
* Use the Singleton pattern to create one Connection
*/
private static Connection getConnection() {
if (conn != null) {
return conn;
}
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
System.out.println(e.getMessage() + " load driver error");
System.exit(0);
}
try {
//conn = DriverManager.getConnection(host);
conn = DriverManager.getConnection(host + "create=true", dbUsername, dbPassword);
} catch (SQLException e) {
displayErr("Get connection error: ", e);
System.exit(0);
}
return conn;
}
Now, I want to create a login method where I need to use the connection conn. The method is static and I cannot use conn.
I'm sure this is wrong but I've also tried making a public method which returns the connection conn and then tried calling that method from Main.
conn = Main.returnConnection();
What should I do in this situation? Pretty confused at how I'm supposed to model this.
Your approach is so primitive when it's compared with Connection Pooling. Connection pool means a pool that includes cached, reusable connections those can be used in future requests. As you said opening a connection for each user is an expensive process also giving a static connection for each user occurs conflictions. Connection pooling is the standart that should be used in these kind of circumstances.
connection = connectionPool.getConnection();
Upper code means get a connection from the pool, if all connections are already allocated, mechanism automatically creates a new one.
The most popular libraries are:
BoneCP
Apache DBCP
C3p0
I figured out the purpose of the Singleton pattern is to create one instance of something and allow it to be seen by everyone.
So I made it public static void instead and can now access the connection, without making a new one each time.
Correct me if I am wrong but this works fine.

Sharing database connection in Java EE

I am developing a web application using JSP & Servlet (IDE: Eclipse, Database: Oracle10).
I have developed java class which returns a static connection, and that connection will be used by my entire web application.
public class DBConnection
{
private static Connection con = null;
static Connection getConnection(String str)
{
try
{
Class.forName("oracle.jdbc.driver.OracleDriver");
con = DriverManager.getConnection("MyValuesHere");
System.out.println("New instance of Connection is created for: "+str);
}
catch(ClassNotFoundException cnfe)
{
System.out.println("Error loading class!");
cnfe.printStackTrace();
}
catch(SQLException sqle)
{
System.out.println("Error connecting to the database!");
sqle.printStackTrace();
}
return con;
}//getConnection()
}//class
Above class is working fine. Then I have another 4 java classes for
Inserting
Updating
Deleting
Selecting
data from database using the above connection. So in those 4 classes I am getting connection which is created in my DBConnection class, and those four classes are also working fine. This four classes are used in my all Servlet's.
To get Connection in those 4 classes I am writing following line:
private static Connection con = DBConnection.getConnection("UpdateQuery.java");
But problem is that I want to share the same connection in all four classes, but connection is created separately in those 4 classes. So how should I share the same connection in those four classes? is there better way of doing this? and if I use this approach will there be any issues in web application because of sharing the connection for whole application?
You are (implicitly) trying to solve a non-trivial task.
Such things are normally done by the container - taking connections from a pool, then returning them back, reconnection etc...
If you use a fully functional applications server you'd better configure and use data sources.
If your server doesn't support data sources, do not mess up with saving connection into a private field. What for example happenes when your connection is lost? Your private variable will have a non-working connection. Do you have any recovery mechanism?
Your code will be much more robust if you get it in the beginning of the business operation and then close it.
Or try to find a professionally written library that supports connection pools - it will do pretty much the same as a classic container in handling a connection pool.
Or write it yourself, but it will be a separate task with many questions.
Looks like you wanted to turn Connection into a singleton but then forgot to check whether it's been instantiated already. In getConnection you could check if con is not null in the first place and return that instance right away. Only if con is still null, proceed with initialization.
You should save the created connection instance into a private static field in DBConnection, and when getConnection is called, you check if the field is null, then create the connection, then return it:
if (connection == null) {
connection = createConnection();
}
return connection;
where connection is a private static Connection connection field of DBConnection class.
However I strongly suggest to not use this approach as sharing a connection between concurrent threads will cause serious problems. I suggest to use connection pooling

Is this use of PreparedStatements in a Thread in Java correct?

I'm still an undergrad just working part time and so I'm always trying to be aware of better ways to do things. Recently I had to write a program for work where the main thread of the program would spawn "task" threads (for each db "task" record) which would perform some operations and then update the record to say that it has finished. Therefore I needed a database connection object and PreparedStatement objects in or available to the ThreadedTask objects.
This is roughly what I ended up writing, is creating a PreparedStatement object per thread a waste? I thought static PreparedStatments could create race conditions...
Thread A stmt.setInt();
Thread B stmt.setInt();
Thread A stmt.execute();
Thread B stmt.execute();
A´s version never gets execed..
Is this thread safe? Is creating and destroying PreparedStatement objects that are always the same not a huge waste?
public class ThreadedTask implements runnable {
private final PreparedStatement taskCompleteStmt;
public ThreadedTask() {
//...
taskCompleteStmt = Main.db.prepareStatement(...);
}
public run() {
//...
taskCompleteStmt.executeUpdate();
}
}
public class Main {
public static final db = DriverManager.getConnection(...);
}
I believe it is not a good idea to share database connections (and prepared statements) between threads. JDBC does not require connections to be thread-safe, and I would expect most drivers to not be.
Give every thread its own connection (or synchronize on the connection for every query, but that probably defeats the purpose of having multiple threads).
Is creating and destroying PreparedStatement objects that are always the same not a huge waste?
Not really. Most of the work happens on the server, and will be cached and re-used there if you use the same SQL statement. Some JDBC drivers also support statement caching, so that even the client-side statement handle can be re-used.
You could see substantial improvement by using batched queries instead of (or in addition to) multiple threads, though. Prepare the query once, and run it for a lot of data in a single big batch.
The threadsafety is not the issue here. All looks syntactically and functionally fine and it should work for about half a hour. Leaking of resources is however the real issue here. The application will crash after about half a hour because you never close them after use. The database will in turn sooner or later close the connection itself so that it can claim it back.
That said, you don't need to worry about caching of preparedstatements. The JDBC driver and the DB will take care about this task. Rather worry about resource leaking and make your JDBC code as solid as possible.
public class ThreadedTask implements runnable {
public run() {
Connection connection = null;
Statement statement = null;
try {
connection = DriverManager.getConnection(url);
statement = connection.prepareStatement(sql);
// ...
} catch (SQLException e) {
// Handle?
} finally {
if (statement != null) try { statement.close(); } catch (SQLException logOrIgnore) {}
if (connection != null) try { connection.close(); } catch (SQLException logOrIgnore) {}
}
}
}
To improve connecting performance, make use of a connection pool like c3p0 (this by the way does not mean that you can change the way how you write the JDBC code; always acquire and close the resources in the shortest possible scope in a try-finally block).
You're best to use a connection pool and get each thread to request a connection from the pool. Create your statements on the connection you're handed, remembering to close it and so release it back to the pool when you're done. The benefit of using the pool is that you can easily increase the number of available connections should you find that thread concurrency is becoming an issue.

Categories

Resources