get connection with singleton pattern - java

My task is to get connection with jdbc using singleton pattern. I wanted to ask whether I am using the pattern or not?
public class DbUtils {
private static Connection conn = null;
static {
final String DB_URL = "jdbc:mysql://localhost:3306/library";
final String USER = "root";
final String PASS = "12345";
try {
conn = DriverManager.getConnection(DB_URL, USER, PASS);
} catch (SQLException e) {
throw new RuntimeException(e);
}
System.out.println("Connected to database");
}
public static Connection getConnection() {
return conn;
}
}

It's not quite a singleton object. In the singleton pattern you're calling a single instance of the object, whereas with this use of a static class you aren't really dealing with an instance.
Larger issues with the implementation:
You can't really close a connection. If you do close it, you won't be able to reopen it.
catch (SQLException e) { throw new RuntimeException(e); } makes it difficult to recover from connection failures.
You want something more like:
public class DbConnection {
private static DbConnection instance = null;
private Connection conn = null;
private DbConnection() {}
private void init() throws SQLException {
final String DB_URL = "jdbc:mysql://localhost:3306/library";
final String USER = "root";
final String PASS = "12345";
conn = DriverManager.getConnection(DB_URL, USER, PASS);
System.out.println("Connected to database");
}
public Connection getConnection() {
return conn;
}
public static Connection getInstance() throws SQLException {
if (instance != null && !instance.getConnection().isClosed()) {
return instance;
} else {
instance = new DbConnection();
instance.init();
}
}
}
The private DbConnection() {} overrides the default public constructor, meaning other classes won't be able to create a new instance of your class. The class maintains a single reference to an instance.
The check for !instance.getConnection().isClosed() makes sure that you return a new instance if the previous connection was closed.

Related

SQL connections dangling: Where am I not correctly closing up connections correctly?

I am building a basic java application to load some files into a mysql database. I am able to load the files up and populate my tables without any problems. However after speaking to someone who reviewed my code, I am apparently not correctly closing my connections and wasting resources. Where am I not closing up the connections? Have I done this incorrectly?
I am using the try-with-resources construct within my DbSinger class to execute prepared statements to my database, which should automatically close the connection so long as the AutoCloseable interface is implemented, which it is in the parent class of Db. The close() method however is never reached. The DbSinger is instantiated inside my main() and then runs it's single method populateSingers() with an ArrayList of Singer objects.
Connection Class
public class SQLConnection {
private static final String servername = "localhost";
private static final int port = 3306;
private static final String user = "ng_user";
private static final String pass = "ng";
private static final String db = "ng_music";
private static final String connectionString = "jdbc:mysql://" + servername + ":" + port + "/" + db;
public Connection provide() {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
return DriverManager.getConnection(connectionString, user, pass);
}
catch (SQLException | ClassNotFoundException e) {
throw new SQLConnectionException(e);
}
}
public class SQLConnectionException extends RuntimeException {
SQLConnectionException(Exception e) {super(e);}
}
}
Abstract parent class
public abstract class Db implements AutoCloseable{
private Connection connection;
Db() {
SQLConnection sqlC = new SQLConnection();
this.connection = sqlC.provide();
}
#Override
public synchronized void close() throws SQLException {
if(connection != null) {
connection.close();
connection = null;
System.out.println("Connection closed");
}
}
Connection getConnection() {
return connection;
}
boolean checkIfPopulated(String query){
try {
PreparedStatement ps = getConnection().prepareStatement(query);
ResultSet rs = ps.executeQuery();
return !rs.next();
} catch (SQLException e) {
e.printStackTrace();
}
return true;
}
}
Concrete class to execute queries to database for singers table
public class DbSinger extends Db {
public DbSinger() {
super();
}
public void populateSingers(ArrayList<Singer> singers) {
String populateSingersQuery = "insert into ng_singers(name, dob, sex) values(?,?,?)";
if(!checkIfPopulated("select * from ng_singers")){
System.out.println("Singer Table is already populated");
return;
}
try (PreparedStatement ps = getConnection().prepareStatement(populateSingersQuery)) {
for (Singer s : singers) {
ps.setString(1, s.getName());
ps.setDate(2, java.sql.Date.valueOf(s.getDob()));
ps.setString(3, s.getSex());
ps.addBatch();
}
ps.executeBatch();
System.out.println("Singers added to table");
} catch (SQLException e) {
e.printStackTrace();
}
}
}
My code is able to execute is able to run fine and does what it needs to, but I want to understand why and where I am not closing connections, and to understand how I can resolve this. Or at least understand if I am approaching this wrong.
In your case, you need to instantiate DBSinger class in try-with-resources statement to close the underlying connection.
Instead of doing:
DbSinger dbSinger = new DbSinger();
You need to do:
try (DbSinger dbSinger = new DbSinger()) {
// Your other code
}
This way the close() method you are overriding in your Db class will be called automatically.
Also, close the preparedStatement you created in your checkIfPopulated method by:
try (PreparedStatement ps = getConnection().prepareStatement(query)) {
// Other codes
}
Your code is old way. And you do need close manually. However, with Java 8, you can use try with resource like below,
try (Connection conn = ds.getConnection();
Statement stmt = conn.createStatement()) {
try {
stmt.execute(dropsql);
} catch (Exception ignore) {} // ignore if table not dropped
stmt.execute(createsql);
stmt.execute(insertsql);
try (ResultSet rs = stmt.executeQuery(selectsql)) {
rs.next();
} catch (Exception e2) {
e2.printStackTrace();
return("failed");
}
} catch(Exception e) {
e.printStackTrace();
return("failed");
}

Is singleton not good for get JDBC connection? Any good implementation of connection pooling?

I used singleton pattern to get jdbc connection for my standalone application. The code is as following.
public static synchronized MysqlConnect getDbCon() {
if ( db == null ) {
db = new MysqlConnect();
}
return db;
}
But I saw in many discussions singleton in not good for getting connection. Is it true?
And the suggested using connection pooling. Can anyone give me a good implementation of connection pooling to use instead of the above code?
Here's a simple, singleton based implementation of a connection pool. This connection pool supports getting a connection using either the DriverManager interface or via a DataSource (JNDI).
I use this connection pool for some of my projects (though the actual implementation is slightly more complex)
public class ConnectionPool{
private String jdbcDriver;
private String jdbcURL;
private String user;
private String password;
private int connectionCount=10;
private List<Connection> connections;
private static boolean loadFromDataSource;
private static DataSource dataSource;
private static ConnectionPool connPool;
private ConnectionPool() throws EasyORMException{}
private void setConnection(String jdbcDriver, String jdbcURL, String user, String password,String dbDataSource) throws EasyORMException{
this.jdbcDriver = jdbcDriver;
this.jdbcURL=jdbcURL;
this.user=user;
this.password=password;
connections= new ArrayList<Connection>();
connections.add((ConnectionPool.loadFromDataSource) ? getConnectionFromDataSource() : getConnection());
}
static ConnectionPool getInstance(){
return connPool;
}
private static ConnectionPool getInstanceFromJndi(String propertyFile,boolean loadFromJndi) throws EasyORMException{
ConnectionProp cp=readPropFromFile(propertyFile);
if(loadFromJndi){
dataSource=createDatasource(cp.getDataSource());
loadFromDataSource=true;
}
return ConnectionPool.createConnectionPool(cp.getJdbcDriver(),cp.getDbURL(), cp.getUsername(), cp.getPassword(),cp.getDataSource())
}
public static ConnectionPool getInstance(String propertyFile,boolean loadFromJndi) throws EasyORMException{
return ConnectionPool.getInstanceFromJndi(propertyFile, loadFromJndi, false);
}
public static ConnectionPool getInstance(ConnectionProp cp) throws EasyORMException{
return ConnectionPool.createConnectionPool(cp.getJdbcDriver(),cp.getDbURL(), cp.getUsername(), cp.getPassword(),cp.getDataSource());
}
public static ConnectionPool getInstance(String jndiName) throws EasyORMException{
dataSource=createDatasource(jndiName);
loadFromDataSource=true;
return ConnectionPool.createConnectionPool(null,null, null, null,jndiName);
}
public static ConnectionPool getInstance(String jdbcDriver, String jdbcURL, String user, String password) throws EasyORMException{
return ConnectionPool.createConnectionPool(jdbcDriver,jdbcURL, user, password,null);
}
private static ConnectionPool createConnectionPool(String jdbcDriver, String jdbcURL, String user, String password,String dbDataSource) throws EasyORMException{
if(connPool==null) {
connPool = new ConnectionPool();
connPool.setConnection(jdbcDriver, jdbcURL, user, password, dbDataSource);
}
return connPool;
}
synchronized Connection getAvailableConnection() throws EasyORMException {
Connection conn=null;
int connSize = connections.size();
if(connSize>0){
conn=connections.remove(connSize-1);
}else{
if(connSize<connectionCount){
for(int i=0;i<initialConnCount;i++)
conn=(ConnectionPool.loadFromDataSource)?getConnectionFromDataSource() :getConnection();
}else{
throw new EasyORMException(EasyORMException.CONNECTION_NUM_EXCEEDED);
}
}
return conn;
}
synchronized void returnConnection(Connection conn){
connections.add(conn);
}
private Connection getConnection() throws EasyORMException {
Connection conn=null;
try {
Class.forName(jdbcDriver);
conn = DriverManager.getConnection(jdbcURL, user, password);
} catch (ClassNotFoundException e) {
throw new EasyORMException(e);
} catch (SQLException e) {
throw new EasyORMException(e);
}
return conn;
}
private Connection getConnectionFromDataSource() throws EasyORMException {
try{
return dataSource.getConnection();
}catch(SQLException e){
throw new EasyORMException(e);
}
}
public void setNumberOfConnections(int count){
this.connectionCount=count;
}
public int getNumberOfConnections(){
return connectionCount;
}
private static DataSource createDatasource(String jndiDb)throws EasyORMException{
InitialContext initCtx=null;
try {
initCtx = new InitialContext();
return (DataSource)initCtx.lookup("java:comp/env/"+jndiDb);
} catch (NamingException e) {
throw new EasyORMException(e);
}finally{
if(initCtx!=null){
try {
initCtx.close();
} catch (NamingException e) {
throw new EasyORMException(e);
}
}
}
}
}
Some methods don't have public access (because they're written as part of a library) but you can change them to public if you need to.

Is a pooled db-access using method-level connection in a static class/method safe?

have been a long-time reader here and now I`ve got a problem I canĀ“t really get my head around.
For ease of access and to save object creation overhead I have a static class realizing database accesses. The used JVM implementation is Tomcat and for connection pooling org.apache.commons.dbcp is used.
I've read a lot about thread-safety, heap and stack here and elsewhere but I can`t get to a definitive conclusion if multiple method calls on my static class won't interfere with each other. Most topics I've read deal with instance methods while I use static ones which might have implications I overlooked.
If I understood everything correctly, as the variables connection, statement, resultset are on the method level, each function call should have a unique reference on the stack to a unique object in the heap and it should not be possible that multiple method calls interfere with each other.
Am I right or do I stand corrected? Any help would be appreciated.
The (shortened) code is :
public class DBQuery{
private static String pathToDataSource = "";
private static javax.naming.Context cxt = null;
private static javax.sql.DataSource ds = null;
private static void getDataSource() throws Exception {
if(pathToDataSource.equals("")){ pathToDataSource = Config.getParam("PathToDataSource"); }
cxt = new javax.naming.InitialContext();
ds = (javax.sql.DataSource) cxt.lookup(pathToDataSource);
}
private static Connection connect() throws Exception {
if(ds==null){ getDataSource(); }
return ds.getConnection();
}
public static Vector doDBquery(String querystring) throws Exception {
Vector retVec = new Vector();
Connection connection = null;
Statement statement = null;
ResultSet resultset = null;
try {
connection = getConnection();
statement = connection.createStatement();
resultset = statement.executeQuery(querystring);
...
} catch(Exception e) {
...
} finally {
myFinallyBlock(resultset, statement, connection);
}
return retVec;
}
// more methods like doDBInsert() following, hence closure in separate myFinallyBlock
private static void myFinallyBlock(ResultSet resultset, Statement statement, Connection connection) {
try {
if (resultset != null) resultset.close();
} catch (SQLException e) { resultset = null; }
try {
if (statement != null) statement.close();
} catch (SQLException e) { statement = null; }
try {
if (connection != null) connection.close();
} catch (SQLException e) { connection = null; }
}
} //close class
Yeah, you are right inside method there is no concurrency problems , until you are using shared variables inside it, in other words "Stateless objects are always thread-safe."
Servlet is quite good example of it ;)
edited.
For making your code safe I recommend you to do follow:
private static Connection connect() throws Exception {
if (ds == null) {
synchronized (Connection.class) {
if (ds == null) {
getDataSource();
}
}
}
return ds.getConnection();
}

How should a static database connection be initialised?

This class is the only thing that should ever access the database and I'd like to give it a single connection object when my application starts up. However, instantiation may cause an exception to be thrown, so I can't do this:
public class DBManager {
private static Connection conn = Database.getReadOnlyConnection();
...
...
}
I have a pretty ugly workaround, and I was wondering if there's a better way.
public class DBManager {
private static Connection conn = null;
private static DBManager instance = null;
public static DBManager getInstance() throws SQLException, ClassNotFoundException {
if (instance == null){
instance = new DBManager();
}
return instance;
}
private DBManager() throws SQLException, ClassNotFoundException {
conn = Database.getReadOnlyConnection();
}
...
...
}
There's also this alternative:
public class DBManager {
private static Connection conn = null;
public static void setConnection(Connection conn) throws NotSupportedException{
if (conn == null){
this.conn = conn;
}
else {
throw new NotSupportedException();
}
}
...
...
}
Is there a nicer way of handling this in Java?
Update
I've decided to use a static initializer block.
public class DBManager {
private static Connection conn;
static {
try {
conn = getReadOnlyConnection();
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
...
...
}
This causes the application to fail early if the database cannot be reached and avoids the problem of having to ensure that the DBManager is only being used via an instance.
You program should be more robust - sure you may have a connection now, but what happens if the DB does down - use the same logic for no DB now as DB goes down later
How about a static method and checking if the connection is still valid,
public class Config{
private static Connection con;
private String dbUrl = "jdbc:mysql:/localhost:3306/dbname","username","password";
public static Connection getConnection() throws SQLException{
if(con== null){
con = DriverManager.getConnection(dbUrl);
}
if(!con.isValid(10)){
con = DriverManager.getConnection.getConnection(dbUrl);
}
return con;
}
}

static global object

I've got class with one static method
makeConnection
The method returns Connection object for further JDBC operations. Is there a possibility, to create a global Connection field, with result of this method "return" ? I would like to use this field wherever I need.
public class Connection
{
public static Connection makeConnection() throws IOException, SQLException
{
try
{
Class.forName("org.postgresql.Driver");
Properties props = new Properties();
FileInputStream in = new FileInputStream("dataBase.properties");
props.load(in);
in.close();
String drivers = props.getProperty("jdbc.drivers");
if(drivers != null) System.setProperty("jdbc.drivers", drivers);
String url = props.getProperty("jdbc.url");
String username = props.getProperty("jdbc.username");
String password = props.getProperty("jdbc.password");
return DriverManager.getConnection(url, username,password);
}
catch (ClassNotFoundException e)
{
return null;
}
catch(IOException e)
{
return null;
}
catch(SQLException e)
{
return null;
}
}
}
It is possible, but the connection factory is better than a connection.
However, static variable is not a good idea for the lifecycle control of connections.
A good connection pool will take care many problem for you, such as the concurrent accessing, timed out detecting, recycle the alive connections, purging dead connections automatically.
You can do this:
class Foo {
public static Connection conn = bar();
private static Connection bar() {
...
}
}
Is that what you want?
This is not the way to handle connections ... but it might give you an idea how to resolve similar kinds of problems:
public class Wombat
{
public static Wombat getWombat ()
{
if (theWombat == null)
theWombat = new Wombat ();
return theWombat;
}
private static Wombat theWombat= null;
}
You can initialize a static variable in a static initializer block:
class Foo {
public static Connection conn;
static {
try {
conn = makeConnection();
} catch(...) {
...
}
}
}

Categories