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;
}
}
Related
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.
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.
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();
}
I am new to javaEE and trying to make database connection. I can do it but i think my way of doing it is inefficient. Here is what i do:
static String dbUrl="jdbc:mysql://localhost:3306/Bank";
static String username="root";
static String password="";
static Connection con=null;
public static void connect ()
{
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
con=(Connection) DriverManager.getConnection(dbUrl,username,password);
System.out.println("Connected!");
}
catch (Exception e) {
e.printStackTrace();
System.out.println("not connected");
}
}
public void someFunctiontoConnectToDB{
try {
connect();
DO_THE_QUERY.....etc
}
}
Here is my problem, this method works fine, but i have to duplicate the same code whenever i try to connect to DB in another servlet or managed bean. I tried to create a class for connection and pass the Connection c as the parameter, but this time when it returns from the connection class, Connection object becomes null. Is there any other way i can make connection easier, and without code duplication?
Thanks
If it is possible try to get into JPA, it makes life much easier.
But if you are stuck with JDBC, here is a good approach for abstracting and encapsulating the Database Layer Core J2EE Patterns - Data Access Object
In a summary for your case I would do something like this:
The DAOFactory:
class MySqlDAOFactory {
static String dbUrl="jdbc:mysql://localhost:3306/Bank";
static String username="root";
static String password="";
static private Connection con;
public static void createConnection() {
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
con=(Connection) DriverManager.getConnection(dbUrl,username,password);
System.out.println("Connected!");
}
catch (Exception e) {
e.printStackTrace();
System.out.println("not connected");
}
}
public static BankDAO getBankDAO() {
return new BankDAO(con);
}
}
And the BankDAO:
class BankDAO {
Connection con;
public BankDAO(Connection con) {
this.con = con;
}
public Account getAccountFor(String name) {
//JDBC Operations
return acc;
}
}
In your Managed Bean or Servlet:
public void someFunction() {
MySqlDAOFactory.createConnection();
BankDAO dao = MySqlDAOFactory.getBankDAO();
//get other DAOs
Account acc = dao.getAccountFor("bob");
}
You can create a class that will connect to database and make a method return the connection.
When you want to use connection in other classes, you simply call that method.
Or else what you can do is
Create a ServletContextListener
Add database connection code in the listener.
Add a method to return connection
Use it whenever required.
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(...) {
...
}
}
}