If I have a static field that I want to initialize, will initializing it in the constructor cause it to be assigned every time a new instance of the class is instantiated?
private static Connection connection;
public Database() {
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
connection = DriverManager.getConnection(HOST, USERNAME, PASSWORD);
} catch (SQLException | InstantiationException | IllegalAccessException | ClassNotFoundException e) {
e.printStackTrace();
}
}
I could do this:
private static Connection connection = DriverManager.getConnection(HOST, USERNAME, PASSWORD);
However I need to have exception handling. I have also looked at using a static block to but this has caused problems.
will initializing it in the constructor cause it to be assigned every time a new instance of the class is instantiated?
Yes; code in the constructor will run whenever you construct an object.
You need to use a static initializer block.
Static fields are belong to class, not to any instance of that class. So, initializing it in the constructor doesn't make any sense. Since for every instance creation, that will be reinitialized. This may cause problems to you. Use static initializer to initialize them and have class loading time initializer for static fields.
You should use a static constructor to initialize static variables that need more initialization than just a simple assignment. Of course you can only use static variables in a static constructor. For your example:
class Database {
private static Connection connection;
static {
try {
connection = DriverManager.getConnection(HOST, USERNAME, PASSWORD);
} catch (...) {}
}
...
}
In this example, HOST, USERNAME and PASSWORD need to be static variables too (in this class or somewhere else is fine). However, I doubt you really want to initialize your database like that.
Yes, this is how static fields work. They are shared across all instances of your class; any time you call new Database(), it'll reset the connection.
For databases, you should use connection pooling instead of a single, shared connection.
What you want is a static initializer:
static {
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
connection = DriverManager.getConnection(HOST, USERNAME, PASSWORD);
} catch (SQLException | InstantiationException | IllegalAccessException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
This block executes the first time you touch the static field (which will be when you create a new Database instance).
It is not safe to use a static Connection object across multiple instances.
Related stackoverflow question
Related
I have a program in which i need to connect to my postgreSQL DB. I have 4 classes:
public class FileReader {
public Stream<String> readFileFromResource(String path) throws URISyntaxException, IOException {
Path result = Paths.get(getClass().getClassLoader().getResource(path).toURI());
return Files.lines(result);
}
}
and
public class SQLQueryExecutor {
public void executeSQL(Connection connection, String sqlContents) throws SQLException {
try (Statement statement = connection.createStatement()){
statement.execute(sqlContents);
}finally {
connection.close();
}
}
}
and
public class SQLFileExecutor {
public void executeSQLFile(Connection connection, String path) throws URISyntaxException, IOException {
FileReader fr = new FileReader();
SQLQueryExecutor sqlQueryExecutor = new SQLQueryExecutor();
fr.readFileFromResource(path).forEach(i -> {
try {
sqlQueryExecutor.executeSQL(connection, i);
} catch (SQLException e) {
System.out.println("Table is not created");
e.printStackTrace();
}
});
}
}
and
public class SchoolApp {
private static final String USER = "user1";
private static final String PASSWORD = "01234";
private static final String URL = "jdbc:postgresql://localhost:5432/school";
public static void main(String[] args) throws SQLException, URISyntaxException, IOException {
Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);
SQLFileExecutor sqlFileExecutor = new SQLFileExecutor();
sqlFileExecutor.executeSQLFile(connection, "CreateTables.sql");
}
}
Unfortunately, I have an error: the connection has already been closed. I don't get it why I have this error. Maybe the reason is that I should have the statement initialization and connection closing in one method?
the error:
Table is not created
org.postgresql.util.PSQLException: Connection has already been closed
at org.postgresql.jdbc.PgConnection.checkClosed(PgConnection.java:885)
at org.postgresql.jdbc.PgConnection.createStatement(PgConnection.java:1727)
at org.postgresql.jdbc.PgConnection.createStatement(PgConnection.java:431)
at school_app.SQLQueryExecutor.executeSQL(SQLQueryExecutor.java:11)
at school_app.SQLFileExecutor.lambda$0(SQLFileExecutor.java:14)
at java.base/java.nio.file.FileChannelLinesSpliterator.forEachRemaining(FileChannelLinesSpliterator.java:117)
at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:658)
at school_app.SQLFileExecutor.executeSQLFile(SQLFileExecutor.java:12)
at school_app.SchoolApp.main(SchoolApp.java:17)
You call forEach, so you do executeSQL for each line or whatever readFileFromResource returns.
However, executeSQL will close the connection it is given, thus guaranteeing that the second and all further invocations will fail.
You have two style issues with your code setup:
Resources should be closed by the creator
The connection is made in your main, but it is closed in your executeSQL. That's no good. You need to get in the habit of having the creator also be the closer.
You do it right in your SQLQueryExecutor code: The creator of the Statement (which also needs closing) is also the closer; the try-with-resources construct makes it very easy. You need to do the same thing with the connection: Remove that entire finally block, and then do to the creation of your connection the same you do to when you make statements.
Bad exception handling
You're calling forEach. This is bad style - you don't want to use lambdas unless there is a clear advantage, because they have intrinsic disadvantages non-lambda-based code doesn't have: They are not exception transparent, mutable local variable transparent, or control flow transparent.
That is an especially big problem here, given that the call you do for each element may throw a checked exception.
The general rule about exception handling is simply this: IF you catch it, then handle it. Logging it is not handling it. Note that psv main is allowed to (and generally should!) throws Exception, and any method that clearly does SQL things (it's right there in the name!) should probably be declared to throws SQLException. Then all the various catch blocks you have can all go away. This means you have far less code and if an exception does occur, you get better handling (java itself handles it far better than you can, by properly rolling up each method and logging all relevant details, instead of only logging some parts and blithely trucking on, even though all sorts of assumptions are now broken due to the exception having occured).
So, just use for (String line : fr.readFromResource(path)) { }. Calling forEach on a collection is rarely correct. (It makes sense if you already have a Consumer<T> instance ready to go, and not much more than that.
NB: If ever 'just add a throws clause to the method' isn't going to work, then the right ¯\(ツ)/¯ no clue how to handle this exception handler is not e.printStackTrace(), that has all sorts of disadvantages. The right way to do it is: throw new RuntimeException("uncaught", e);. Update your editor's templates.
You should not close the connection in SQLQueryExecutor.
This question already has answers here:
What is an efficient way to implement a singleton pattern in Java? [closed]
(29 answers)
Closed 4 years ago.
I am new to design patterns. I want to use the singleton design pattern for this database class. Can anyone help me with this?
Here is my complete code:
public interface ResourceConnection {
public Connection getConnection();
}
public class ResourceConnectionFactory {
public ResourceConnection getConnection() {
return new MysqlResourceConnectionImpl();
}
}
public class MysqlResourceConnectionImpl implements ResourceConnection {
Connection con = null;
#Override
public Connection getConnection() {
try {
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/library", "root", "root");
}
catch (ClassNotFoundException ex) {
Logger.getLogger(MysqlResourceConnectionImpl.class.getName()).log(Level.SEVERE, null, ex);
} catch (SQLException ex) {
Logger.getLogger(MysqlResourceConnectionImpl.class.getName()).log(Level.SEVERE, null, ex);
}
return con;
}
}
To make any class singleton you have to insure following things. (Singleton design pattern can be applied anywhere. There is no different implementation for database class)
Private constructor to restrict instantiation of class
Private static variable of the same class which will store the only instance of the class.
Public method to get this instance of class. This is the access point for other classes.
You can use this link from Java Singleton Design Pattern. All the credit to this url.
I understand what you are doing is that getting a single connection for a application.If you are re-using that connection in multiple places it will become error prone. Instead of doing that you can use Connection Pool to set up the connection for you. Here is an example for Connection Pool using DBCP
I am using JavaFX for my project and I have two classes - MainApp class and Database class.
Very simplified implementation would look like this:
public class MainApp extends Application {
#Override
public void start(Stage stage) throws Exception {
// Getting username & password doing some initialization, etc.
Database.setUserName(username);
Database.setPassword(password);
Database.testConnection();
}
// This method was pretty much generated by IDE
public static void main(String[] args)
{
launch(args);
}
}
Only relevant part of Database class implementation is as follows (note that I have declared and implemented variables that appear in mentioned methods, I just don't paste them here to keep the code short)
public class Database {
private static OracleDataSource dataSource;
static {
try {
dataSource = new OracleDataSource();
dataSource.setURL("myjdbcaddress");
dataSource.setUser(userName);
dataSource.setPassword(password);
System.out.print("Static block executed...");
}
catch (SQLException e)
{
System.out.print("Static block caught...");
throw new ExceptionInInitializerError("Initial Database Connection not established. Sorry.");
}
}
public static Connection getConnection()
{
Connection conn = null;
try
{
conn = dataSource.getConnection();
if (conn != null)
isConnected = true;
}
catch (SQLException e)
{
e.printStackTrace();
}
return conn;
}
}
I am getting null pointer exception because of this: static block in Database class is executed after overridden start() method. Therefore, when I access properties of Database class, they are not initialized yet.
Is there a way to force call static block before start method? Did I choose wrong approach? Should I start working with database somewhere else than start() method?
I am getting null pointer exception because of this: static block in Database class is executed after overridden start() method. Therefore, when I access properties of Database class, they are not initialized yet.
No this is not the issue. The static initializer is executed when the class is loaded, which should happen right before (It's always done before anything other than a static constant in the class is used.)
Database.setUserName(username);
or earlier.
The problem probably is that the userName and password not being assigned yet (although it's hard to tell without more code).
I don't recommend using static data to pass information but instead design the application in a way that allows access to a non-static object for communication with the database where it's needed.
However you could fix your problem by moving the code from the static initializer to a static method:
public class Database {
private static OracleDataSource dataSource;
public static void login(String userName, String password) {
try {
dataSource = new OracleDataSource();
dataSource.setURL("myjdbcaddress");
dataSource.setUser(userName);
dataSource.setPassword(password);
System.out.print("Static block executed...");
} catch (SQLException e) {
throw new IllegalStateException("Initial Database Connection not established. Sorry.", e);
}
}
...
}
Database.login(username, password);
Database.testConnection();
But again: Try to avoid using such a Database class that allows access from everywhere.
BTW: If you need to initialize something before the start method of the Application runs, it should be done in a overriden init() method of the application class.
I'm using jdbc transactions as described here: JDBC Transaction example to store complicated object and its relations. For example to store a car I call public "general method" which need to store wheels, engine, car itself etc... It delegates these task to private methods, to which it pass connection. If at some step something went wrong thrown exception is being catch by public method and rollback is performed.
For example:
public boolean saveCar(Car car){
Connection con = null;
try{
con = ....//get connection
con.setAutoCommit(false);
storeCar(car, con);
storeWheels(car, con);
storeEngine(car, con);
con.commit();
} catch(Exception e){
e.printStackTrace();
con.rollback();
} finally {
con.close();
}
}
private void storeWheels(Car car, Connection con) throws Exception{
String sql = "...";
PreparedStatement ps = con.prepareStatement(sql);
ps.executeUpdate;
}
But I need to close PreparedStatement as well. It should be closed in a finally clause, so I have to write my private methods like this:
private void storeWheels(Car car, Connection con) throws Exception{
String sql = "...";
PreparedStatement ps = null;
try{
ps = con.prepareStatement(sql);
ps.executeUpdate;
} catch (Exception e) {
throw new Exception("Something went wrong");
} finally {
ps.close();
}
}
Too many try-catch it makes my code error prone and overloaded. Also throwing Exception from catch block isn't look good. My question how can or is it possible to delegate these tasks as I described and avoid an unnecessary try-catch blocks in every private method.
Can you store an Engine without storing a Car previously? The same question applies for every other component(s). If all those components must be created at the same time you create a Car you you should put the logic for those components all together inside saveCar. If not, your logic still is a little bit "obscure", since you are creating things separately — while you might be confused with an update operation, which, at some point can share the same code.
NOTE: I don't think it's a good idea to be passing a Connection object. Although there's nothing wrong with that but the inconvenience of having an unreleased resource at some point when your programs grows (if so). Look at it as "a good practice", not something you cannot do if it's well understandable/maintainable.
Find this beautiful library DBUtils which has solved my problem:
private QueryRunner runner = new QueryRunner(); //creating global runner object which used across all methods in my class
public boolean saveCar(Car car){
Connection con = null;
try{
con = ....//get connection
con.setAutoCommit(false);
storeCar(car, con);
storeWheels(car, con);
storeEngine(car, con);
DbUtils.commitAndCloseQuietly(con);
} catch(Exception e){
DbUtils.rollbackAndCloseQuietly(con);
}
}
private void storeWheels(Car car, Connection con) throws Exception{
String sql = "...";
runner.update(connection, sql); //all functionality encapsulated, performing update, closing statement, etc..
}
My problem is as follows. I need a class that works as a single point to a database connection in a web system, so to avoid having one user with two open connections. I need it to be as optimal as possible and it should manage every transaction in the system. In other words only that class should be able to instantiate DAOs. And to make it better, it should also use connection pooling! What should I do?
You will need to implement a DAO Manager. I took the main idea from this website, however I made my own implementation that solves some few issues.
Step 1: Connection pooling
First of all, you will have to configure a connection pool. A connection pool is, well, a pool of connections. When your application runs, the connection pool will start a certain amount of connections, this is done to avoid creating connections in runtime since it's a expensive operation. This guide is not meant to explain how to configure one, so go look around about that.
For the record, I'll use Java as my language and Glassfish as my server.
Step 2: Connect to the database
Let's start by creating a DAOManager class. Let's give it methods to open and close a connection in runtime. Nothing too fancy.
public class DAOManager {
public DAOManager() throws Exception {
try
{
InitialContext ctx = new InitialContext();
this.src = (DataSource)ctx.lookup("jndi/MYSQL"); //The string should be the same name you're giving to your JNDI in Glassfish.
}
catch(Exception e) { throw e; }
}
public void open() throws SQLException {
try
{
if(this.con==null || !this.con.isOpen())
this.con = src.getConnection();
}
catch(SQLException e) { throw e; }
}
public void close() throws SQLException {
try
{
if(this.con!=null && this.con.isOpen())
this.con.close();
}
catch(SQLException e) { throw e; }
}
//Private
private DataSource src;
private Connection con;
}
This isn't a very fancy class, but it'll be the basis of what we're going to do. So, doing this:
DAOManager mngr = new DAOManager();
mngr.open();
mngr.close();
should open and close your connection to the database in an object.
Step 3: Make it a single point!
What, now, if we did this?
DAOManager mngr1 = new DAOManager();
DAOManager mngr2 = new DAOManager();
mngr1.open();
mngr2.open();
Some might argue, "why in the world would you do this?". But then you never know what a programmer will do. Even then, the programmer might forger from closing a connection before opening a new one. Plus, this is a waste of resources for the application. Stop here if you actually want to have two or more open connections, this will be an implementation for one connection per user.
In order to make it a single point, we will have to convert this class into a singleton. A singleton is a design pattern that allows us to have one and only one instance of any given object. So, let's make it a singleton!
We must convert our public constructor into a private one. We must only give an instance to whoever calls it. The DAOManager then becomes a factory!
We must also add a new private class that will actually store a singleton.
Alongside all of this, we also need a getInstance() method that will give us a singleton instance we can call.
Let's see how it's implemented.
public class DAOManager {
public static DAOManager getInstance() {
return DAOManagerSingleton.INSTANCE;
}
public void open() throws SQLException {
try
{
if(this.con==null || !this.con.isOpen())
this.con = src.getConnection();
}
catch(SQLException e) { throw e; }
}
public void close() throws SQLException {
try
{
if(this.con!=null && this.con.isOpen())
this.con.close();
}
catch(SQLException e) { throw e; }
}
//Private
private DataSource src;
private Connection con;
private DAOManager() throws Exception {
try
{
InitialContext ctx = new InitialContext();
this.src = (DataSource)ctx.lookup("jndi/MYSQL");
}
catch(Exception e) { throw e; }
}
private static class DAOManagerSingleton {
public static final DAOManager INSTANCE;
static
{
DAOManager dm;
try
{
dm = new DAOManager();
}
catch(Exception e)
dm = null;
INSTANCE = dm;
}
}
}
When the application starts, whenever anyone needs a singleton the system will instantiate one DAOManager. Quite neat, we've created a single access point!
But singleton is an antipattern because reasons!
I know some people won't like singleton. However it solves the problem (and has solved mine) quite decently. This is just a way of implementing this solution, if you have other ways you're welcome to suggest so.
Step 4: But there's something wrong...
Yes, indeed there is. A singleton will create only ONE instance for the whole application! And this is wrong in many levels, especially if we have a web system where our application will be multithreaded! How do we solve this, then?
Java provides a class named ThreadLocal. A ThreadLocal variable will have one instance per thread. Hey, it solves our problem! See more about how it works, you will need to understand its purpose so we can continue.
Let's make our INSTANCE ThreadLocal then. Modify the class this way:
public class DAOManager {
public static DAOManager getInstance() {
return DAOManagerSingleton.INSTANCE.get();
}
public void open() throws SQLException {
try
{
if(this.con==null || !this.con.isOpen())
this.con = src.getConnection();
}
catch(SQLException e) { throw e; }
}
public void close() throws SQLException {
try
{
if(this.con!=null && this.con.isOpen())
this.con.close();
}
catch(SQLException e) { throw e; }
}
//Private
private DataSource src;
private Connection con;
private DAOManager() throws Exception {
try
{
InitialContext ctx = new InitialContext();
this.src = (DataSource)ctx.lookup("jndi/MYSQL");
}
catch(Exception e) { throw e; }
}
private static class DAOManagerSingleton {
public static final ThreadLocal<DAOManager> INSTANCE;
static
{
ThreadLocal<DAOManager> dm;
try
{
dm = new ThreadLocal<DAOManager>(){
#Override
protected DAOManager initialValue() {
try
{
return new DAOManager();
}
catch(Exception e)
{
return null;
}
}
};
}
catch(Exception e)
dm = null;
INSTANCE = dm;
}
}
}
I would seriously love to not do this
catch(Exception e)
{
return null;
}
but initialValue() can't throw an exception. Oh, initialValue() you mean? This method will tell us what value will the ThreadLocal variable hold. Basically we're initializing it. So, thanks to this we can now have one instance per thread.
Step 5: Create a DAO
A DAOManager is nothing without a DAO. So we should at least create a couple of them.
A DAO, short for "Data Access Object" is a design pattern that gives the responsibility of managing database operations to a class representing a certain table.
In order to use our DAOManager more efficiently, we will define a GenericDAO, which is an abstract DAO that will hold the common operations between all DAOs.
public abstract class GenericDAO<T> {
public abstract int count() throws SQLException;
//Protected
protected final String tableName;
protected Connection con;
protected GenericDAO(Connection con, String tableName) {
this.tableName = tableName;
this.con = con;
}
}
For now, that will be enough. Let's create some DAOs. Let's suppose we have two POJOs: First and Second, both with just a String field named data and its getters and setters.
public class FirstDAO extends GenericDAO<First> {
public FirstDAO(Connection con) {
super(con, TABLENAME);
}
#Override
public int count() throws SQLException {
String query = "SELECT COUNT(*) AS count FROM "+this.tableName;
PreparedStatement counter;
try
{
counter = this.con.PrepareStatement(query);
ResultSet res = counter.executeQuery();
res.next();
return res.getInt("count");
}
catch(SQLException e){ throw e; }
}
//Private
private final static String TABLENAME = "FIRST";
}
SecondDAO will have more or less the same structure, just changing TABLENAME to "SECOND".
Step 6: Making the manager a factory
DAOManager not only should serve the purpose of serving as a single connection point. Actually, DAOManager should answer this question:
Who is the one responsible of managing the connections to the database?
The individual DAOs shouldn't manage them, but DAOManager. We've answered partially the question, but now we shouldn't let anyone manage other connections to the database, not even the DAOs. But, the DAOs need a connection to the database! Who should provide it? DAOManager indeed! What we should do is making a factory method inside DAOManager. Not just that, but DAOManager will also hand them the current connection!
Factory is a design pattern that will allow us to create instances of a certain superclass, without knowing exactly what child class will be returned.
First, let's create an enum listing our tables.
public enum Table { FIRST, SECOND }
And now, the factory method inside DAOManager:
public GenericDAO getDAO(Table t) throws SQLException
{
try
{
if(this.con == null || this.con.isClosed()) //Let's ensure our connection is open
this.open();
}
catch(SQLException e){ throw e; }
switch(t)
{
case FIRST:
return new FirstDAO(this.con);
case SECOND:
return new SecondDAO(this.con);
default:
throw new SQLException("Trying to link to an unexistant table.");
}
}
Step 7: Putting everything together
We're good to go now. Try the following code:
DAOManager dao = DAOManager.getInstance();
FirstDAO fDao = (FirstDAO)dao.getDAO(Table.FIRST);
SecondDAO sDao = (SecondDAO)dao.getDAO(Table.SECOND);
System.out.println(fDao.count());
System.out.println(sDao.count());
dao.close();
Isn't it fancy and easy to read? Not just that, but when you call close(), you close every single connection the DAOs are using. But how?! Well, they're sharing the same connection, so it's just natural.
Step 8: Fine-tuning our class
We can do several things from here on. To ensure connections are closed and returned to the pool, do the following in DAOManager:
#Override
protected void finalize()
{
try{ this.close(); }
finally{ super.finalize(); }
}
You can also implement methods that encapsulate setAutoCommit(), commit() and rollback() from the Connection so you can have a better handling of your transactions. What I also did is, instead of just holding a Connection, DAOManager also holds a PreparedStatement and a ResultSet. So, when calling close() it also closes both. A fast way of closing statements and result sets!
I hope this guide can be of any use to you in your next project!
I think that if you want to do a simple DAO pattern in plain JDBC you should keep it simple:
public List<Customer> listCustomers() {
List<Customer> list = new ArrayList<>();
try (Connection conn = getConnection();
Statement s = conn.createStatement();
ResultSet rs = s.executeQuery("select * from customers")) {
while (rs.next()) {
list.add(processRow(rs));
}
return list;
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e); //or your exceptions
}
}
You can follow this pattern in a class called for example CustomersDao or CustomerManager, and you can call it with a simple
CustomersDao dao = new CustomersDao();
List<Customers> customers = dao.listCustomers();
Note that I'm using try with resources and this code is safe to connections leaks, clean, and straightforward, You probably don't want to follow the full DAO pattern with Factorys, interfaces and all that plumbing that in many cases don't add real value.
I don't think that it's a good idea using ThreadLocals, Bad used like in the accepted answer is a source of classloader leaks
Remember ALWAYS close your resources (Statements, ResultSets, Connections) in a try finally block or using try with resources