I have created a Database class which uses a static connection object in order to be used in common between instances of itself. my question is that is there any problem with this approach or not?
class Database {
private static Connection connection = null;
public Database() {
if(connection == null){
...
connection = DriverManager.getConnection(...);
...
}
}
}
If you are going to have many (hundreds) of queries per second then implementing a connection pool is the way to go. See the answer to this question for more details. However, if you a Java novice (we all were one day!) then I don't imagine you will be needing this requirement, and probably will struggle to implement it.
Instead, the simple pattern of creating a new connection if required, and then closing it when finished will be the best way to go forward for you. Below is a modified version of your Database class which I think is a good way to move forward.
class Database {
private Connection con = null;
private final String connectionString;
public Database(String connectionString) {
this.connectionString = connectionString;
}
public void connect() throws SQLException {
if (con != null // if the connection exists
&& !con.isClosed() // and has not been closed
&& con.isValid(0)) { // and appears to be functioning (with a test timeout of 0ms)
return; // skip connection creation
}
// create the connection
con = DriverManager.getConnection(connectionString);
}
public void testFunction() {
try {
connect();
// .. do some stuff with the connection ..
} catch (Exception e) {
// log or otherwise deal with the error
} finally {
try {
con.close();
} catch (Exception e) {
System.err.println("Failed to close connection: " + e.toString());
}
}
}
}
Some things to note about this solution:
It is not very efficient - creating a new connection always takes more time than using an existing one
This class if not thread safe - if you need this requirement, I recommend using a thread pool. However, if you create a new instance of this class per thread then it will be thread safe (as there is not static connection to worry about!)
It does do the job - certainly for simple cases. I use the model for a relatively low volume database which has approx 50-100 connections made/closed per minute and it does not add a noticeable lag
It is very robust - nothing is safer than opening and closing a connection per query. You are guaranteed to be able to handle a connection failure per query, and the connection will always be closed (unless it already has been).
Disclaimer The solution above is not a particularly amazing solution. However, I believe it is simple to implement and a good way for a Java novice to get to know the ropes before jumping into external libraries.
There is nothing wrong with creating an object to manage your connections, however, connections should be opened and closed and can be used in multi-threaded environments, so having a static connection is not a good idea. For a method that needs a connection, get a connection use it, close it. Even if you are not using it in a multi-threaded environment, the connection can time-out, then you need to constantly check if the connection is up and available, instead of just saying, get me a connection, use the connection, close it.
Related
I am implementing a program that needs to establish connection to mysql database. I'm currently connecting independently for each class (like sign up, sign in, show users etc), using the following lines:
Class.forName("com.mysql.cj.jdbc.Driver");
con = DriverManager.getConnection("jdbc:mysql://localhost:3308/myfirstdb","root");
What I am thinking is to implement a class for the connection and call its default constructor each time. Does it give any advantages/disadvantages or doesn't matter. This is the class:
public class MyConnection {
private Connection con;
public MyConnection() {
//establishing connection
try {
Class.forName("com.mysql.cj.jdbc.Driver");
con = DriverManager.getConnection("jdbc:mysql://localhost:3308/myfirstdb","root","");
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
}
//for future use
public Connection getCon() {
return con;
}
}
With very rare exceptions, a single connection to the database for the entire program is the "correct" thing to do.
Connecting costs something. All your queries can use that one connection.
Sure, have the "constructor" do the "connect". And have the "destructor" do "disconnect".
The class should be a "singleton" (or equivalent) to avoid accidentally getting two connections.
Your code has public MyConnection(), which begs the user to create multiple connections. That should be private and called only once, such as this way:
public Connection getCon() {
if (con == NULL) { // or whatever the syntax is
MyConnection(); // Here's the _one_ connection
}
return con;
}
Then users call getCon() to get the one connection and use it to perform queries.
Beware: If you language facilitates multiple threads, do one of these:
Do database operations only from one thread, or
Have (at most) one connection per thread.
PS: I believe this advice applies to any OO language.
As a footnote, establishing two connections in an attempt to get extra performance is likely to be futile. Or, at least, not worth the effort.
Another thing to be aware of... HTTP is, mostly, stateless. So, if you have one web page to "sign up", that will come and go -- one connection with some number of SQLs, then it goes away. Another web page to "sign in" will involve another HTTP request, another connection, etc.
After that, the memory that the user is "signed in" need to be held somewhere:
In URL parameters -- subject to hacking
In a cookie -- reasonable for lightweight apps
Other -- You need security advice if working with sensitive (credit card, health care, etc) info and need to go from web page to web page.
This is a solved problem in Java, don't try to write this yourself. Use a javax.sql.DataSource implementation that is backed by a connection pool (for example Apache DBCP, HikariCP or c3p0).
You can then obtain a connection from the data source for a unit-of-work, and close the connection when you're done. Closing the connection will return the connection to the connection pool for re-use, eliminating much of the overhead of opening a connection.
I have been playing around with JDBC drivers. I would like some advice from the experience code masters out there. I was wondering if this is a good way to find if am connected to a database. If it is not, could someone let me know how would they do it?
Connection con = null;
try {
con = DriverManager.getConnection("jdbc:mysql://localhost/"+database+"?+user="+user+"&password="+password);
} catch (SQLException e) {
System.out.println(e.getMessage());
if (con != null) {
System.out.println("hello");
} else {
System.out.println("Not Connected!");
}
}
I would really appreciate all helpful comments. Many thanks in advance.
If the getConnection method returns normally, and does not throw an exception, then a connection to the database has been made. The logic within the catch clause is unrequired, because if an exception is caught a connection was not established.
The returned Connection object must be close()d (as many of the JDBC classes must, such as Statements and ResultSets for example). Assuming Java7, a convenient way to ensure the Connection is closed is using the try-with-resources statement:
try (Connection con = DriverManager.getConnection(...))
{
}
catch (final SQLException e)
{
}
As stated by SnakeDoc in the comments this may be impractical in production systems because establishing a connection to the database is a typically expensive operation.
The JDBC API will perform these checks for you. Whenever you perform a database operation, such as opening a connection, executing a statement, it will check to see if the connection is valid. If not it will throw an exception.
For example, the method Connection.createStatement throws the following:
SQLException - if a database access error occurs or this method is called on a closed connection
All you have to do is some basic exception handling. Surrounding your JDBC calls with try-catch blocks is one way do this. You could also throw the exception and handle it somewhere else.
That's definitely a good way of doing it! If conn can't be initialised it's either your connection string that is wrong or the database is down.
I am passing Resultset object to each thread. Each thread is connecting to the database and inserting data. Untill thread 110 it is working fine. After it crosses 111 thread it throws the above exception.
I am using oracle 11g.
My sample Thread code is:
class MyThreadClass implements Runnable
{
public Connection connection;
public Statement statement2;
public ResultSet rs2;
public String cookie;
public MyThreadClass(ResultSet rs1)
{
rs2=rs1;
}
public void run()
{
try
{
cookie=rs2.getString("COOKIE");
driver = "oracle.jdbc.driver.OracleDriver";
url = "jdbc:oracle:thin:#127.0.0.1:1521:xx";
/* connection
statement2.executeUpdate("INSERT INTO visit_header VALUES ('"+cookie+"')");
}
I am not getting how to handle this exception.
Your multi-threaded application is opening too many Connections/Sessions. Hence, the listener is dropping and blocking new connections for a while.
Check your DB resource usage first:
SELECT * FROM v$resource_limit WHERE resource_name IN ('processes','sessions');
Check to see if your MAX_UTILIZATION for either your Processes or Sessions is getting too close to the LIMIT_VALUE. If yes, you should either:
Use DB Connection pooling to share Connection objects between threads. Or,
Increase the number of processes/sessions that Oracle can service simultaneously.
Actually, Connection Pooling (#1) should always be done. An application cannot scale up otherwise. Check Apache Commons DBCP for details. For #2, open a new SQL*Plus session as SYSTEM and run:
ALTER system SET processes=<n-as-per-number-of-threads> scope=spfile;
to increase backend concurrency. Then RESTART the Database. IMPORTANT!
I guess the database just don't accept more connections from your host. If I understand your question right you are making maybe 100 threads which each connects to the database in short time. Maybe you don't even close the connection correctly, or the accesses are lasting so long that a huge amount of connections are opened. The database have a limit to which it accepts connections.
You should definitely reduce the number of connections by some clever technique. Maybe reduce the number of concurrent threads and/or use a connection pool.
Try this solution at your end. It worked for me.
Close the connection in try/catch block and just after closing the connection,
write-
Thread.sleep(1000);
In this case you can write it as-
finally {
try {
if (conn != null && !conn.isClosed())
{
conn.close();
Thread.sleep(1000);
}
}
catch (SQLException e) {
e.printStackTrace();}
}
I am using below code snippet to create a singleton instance of Connection object for a web application which will be used by multiple users.
static {
try {
String driver = PropertyReader.getPropertyReader("driverClassName");
Class.forName(driver).newInstance();
} catch (Exception ex) {
ex.printStackTrace();
}
}
private static Connection conn = null;
private static synchronized Connection getDBConnection()
{
try{
if(conn == null || conn.isClosed()){
conn = null;
String URL = PropertyReader.getPropertyReader("url");
String userName = PropertyReader.getPropertyReader("username");
String password = PropertyReader.getPropertyReader("password");
conn = DriverManager.getConnection(URL,userName,password);
logger.info("Preparing Connection...");
}
else{
logger.info("Returning already prepared connection..");
}
}
catch(Exception e)
{
e.printStackTrace();
}
return conn;
}
This class will return same instance of connection until and unless connection is closed or null.
I suppose same connection will be shared by all users on different machine as it is static one.
If one user is setting auto commit to off to commit couple of statements as transaction, will this create problems for other users by restricting their connection to disable autocommit as well or by commiting their transaction in mid way if one user has used con.commit()?
Yes, it will cause problems. They are sharing the same instance, so this statement is wrong
If one user is setting auto commit to off to commit couple of statements as transaction, will this create problems for other users by restricting their connection to disable autocommit as well or by commiting their transaction in mid way if one user has used con.commit()?
It should read
If one user is setting auto commit to off to commit couple of statements as transaction, will this create problems for other users because the connection they are sharing has been set to not autocommit and all of their statements will now become part of the new transaction**
Since all the users (threads) are using the same instance, changes made to it by one user will affect the others.
As Shivam Kalra says, connection pools are a better tool. Most probably your web server will already provide them, and if not there are third party libraries.
will this create problems for other users by restricting their connection to disable autocommit
Yes.
as well or by commiting their transaction in mid way if one user has used con.commit()?
Yes.
Database connections are not safe for use by multiple threads, and should not in general even be member fields let alone singletons. They should be method-local variables. If you want to economize on creating & destroying them, you must use a connection pool.
I created one thread with java.sql.Connection and String parameters.
But from within the thread, I observed that String value was available but Connection object was not. Any clues?
(Editing details into question):
Well, it seems the connection object is available, but closed inside the thread.
Here's the code:
package com.catgen.helper;
import java.sql.Connection;
public class ImageCheckHelper extends Thread{
public Connection conn = null;
public String str = null;
public ImageCheckHelper(Connection conn, String str){
this.conn = conn;
this.str = str;
try{
System.out.println("From inside the constructor");
System.out.println((this.conn!=null)?"Connection is not null":"Connection is null");
System.out.println((this.str!=null)?"String is not null":"String is null");
System.out.println((this.conn.isClosed())?"Connection is closed.":"Connection is not closed");
System.out.println("\n\n");
}catch(Exception e){
e.printStackTrace();
}
}
public void run(){
try{
System.out.println("From inside the thread");
System.out.println((conn!=null)?"Connection is not null":"Connection is null");
System.out.println((str!=null)?"String is not null":"String is null");
System.out.println((conn.isClosed())?"Connection is closed.":"Connection is not closed");
}catch(Exception e){
e.printStackTrace();
}
}
public void initiateImageCheck(){
this.start();
return;
}
}
And here's the output:
From inside the constructor
Connection is not null
String is not null
Connection is not closed
From inside the thread
Connection is not null
String is not null
Connection is closed.
Is another thread closing the connection between the time it is given to the constructor and the time it is used in the run() method? My guess is that the connection is closed after the call to initiateImageCheck() returns but before the run() method has got as far as the isClosed() check.
If not, do you have access to the JDBC driver's source code? I wonder if it is protecting itself against multi-threaded use.
Connections are not guaranteed to be thread-safe, so you should obtain the connection from within the thread that is going to use it.
You also have unsynchronized access to conn from two different threads. Public member variables are not a good idea either - especially in classes that need to be thread-safe.
I don't see what your problem is - looking at the output, you can see that both the Connection and String are non-null within the constructor and when you come to run the thread.
The only difference is that the connection has been closed at some point between the thread being constructed, and the thread being run. Depending on how you provided the connection, and how other threads were using it, this is not particularly unusual. In any case, you should be looking at other threads calling close() on the same Connection object if you want to track this down.
As a general guideline, it's typically easiest to have each thread manage its own Connection, because otherwise you end up with some very tricky semantics about committing and closing them (as you've seen here). Sharing a connection between multiple threads can work, and on rare occasions is necessary, but in general it should be the exception rather than the rule.
Edit: Additionally, a lot of Connection implementations are not even threadsafe, so you can't really use them between multiple threads in a reliable fashion. If one thread is running a statement and you then try to use the connection on a different thread, bad things will happen. Even more justification to just give each thread its own connection and let it get on with what it wants to do, without having to engage in some kind of mutex synchronization (a bottleneck that removes some of the attraction of multithreading, too!).