I'm currently building a program with SQL in JavaFX.
I am calling DbConnect() in my main window and it all works fine.
The Issue I am having right now is to get this database connection in other classes (Another window/scene). Right now I am calling the DB connection function in all other scene's also which will cause issue's later on because it always opens a new database connection. So my question here is how can I share the database connection in all my classes.
Only want to open it once in main class and then inherit it to the other classes
Here is my Database connection function:
public Connection DbConnect() {
try {
con = DriverManager.getConnection(dbPath, user, pass);
statm = con.createStatement();
SetupSystem();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return con;
}
From the first window
// Initilizing all the database connections
public void DbConnect() {
con.DbConnect();
disconnectMenuItem.setVisible(true);
connectMenuItem.setVisible(false);
}
From the second Window (don't want to open new connection here) want to inherit connection from the first window
public void initialize(URL location, ResourceBundle resources) {
db.DbConnect();
}
thanks in advance,
You can use Singleton pattern that can share one instance through your classes:
public final class Singleton {
private static volatile Connection con = null;
private Singleton() {}
public static Singleton getInstance() {
if (con== null) {
try {
con = DriverManager.getConnection(dbPath, user, pass);
statm = con.createStatement();
SetupSystem();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return con;
}
}
Now,you can access to your database connection from the other classes like this :
public class ClassOne {
Singleton.getInstance();
}
public class ClassTwo {
Singleton.getInstance();
}
Related
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");
}
I have got a singleton class as shown below for accessing Database connection as
public class DBConnection {
private static volatile DBConnection instance;
private static DataSource dataSource;
private DBConnection(){
}
public static synchronized DBConnection getInstance() {
if (instance == null) {
instance = new DBConnection();
}
return instance;
}
static {
try {
dataSource = (DataSource) new InitialContext()
.lookup("java:comp/env/jdbc/MySQLDataSource");
} catch (NamingException e) {
e.printStackTrace();
try {
throw new Exception("'jndifordbconc' not found in JNDI", e);
} catch (Exception e1) {
logger.error("Error description", e);
}
}
}
public static Connection getDBConnection() {
try {
return dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
logger.error("Error description", e);
return null;
}
}
}
And when i am trying to access the DBConnection this way
SeperateClass
Here i am getting the yellow warning
public String fetchGlobalIndicesData(#QueryParam("region_name") String region_name )
{
Connection dbConnection = null;
String selectsql = "";
try
{
dbConnection = DBConnection.getInstance().getDBConnection();
selectpstmt = dbConnection.prepareStatement(selectsql);
selectpstmt.setString(1, region_name);
selectRset = selectpstmt.executeQuery();
}
catch (Exception e)
{
logger.error("Error description",e);
}
}
Eclipse IDE is giving me a yellow warning saying
The static method getDBConnection() from the type DBConnection should be accessed in a static way
Could you please tell me whats the proper way of doing this ??
I modified my code as
public static Connection getDBConnection() {
try {
return getInstance().dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
logger.error("Error description", e);
return null;
}
}
Since it is static, you are supposed to call the method directly on the class , not on an instance of the class :
DBConnection.getDBConnection()
Calling the method on an instance has no sense, though it is possible.
As #Berger mentioned, you defined the method as static, so you have to call it as he mentioned.
If you don't want it static, you can modify your code by removing static from the getDBConnection method and call it as:
DBConnection.getInstance().getDBConnection()
The code above is already correct in your fetchGlobalIndicesData method.
Just for the sake of it:
public static Connection getDBConnection()
Becomes:
public Connection getDBConnection()
This way, getInstance will initialize a DBConnection instance, and the static initializer block to init your datasource should fire. Then when you call getDBConnection, your code should work fine.
That is an static method, you can remove the static keyword of the getDBConnection() signature or use DBConnection.getDBConnection()
I'm trying to build a simple mailer daemon for a Tomcat 7, MySQL app (and Eclipse). This the first time I have tried to use a ServletContextListener.
Everything works perfectly. Except, if I change my mailer code, and Tomcat reloads the class. It then bombs with a JNDI exception where it can't find the database. I'm not comfortable using it as-is. I don't want a class reload to kill the task on the server.
Everything works fine after a restart and before the reload. So I must be missing something or doing things in the wrong order.
The database connection is done in the DAO. So after restarting, the DAO must be getting severed?
Any help would be most appreciated...
The error I am getting is:
Name [comp/env/jdbc/somedb] is not bound in this Context. Unable to find [comp].
javax.naming.NameNotFoundException: Name [comp/env/jdbc/somedb] is not bound in this Context. Unable to find [comp].
PooledConnection has already been closed.
at org.apache.naming.NamingContext.lookup(NamingContext.java:819)
at org.apache.naming.NamingContext.lookup(NamingContext.java:167)
at org.apache.naming.SelectorContext.lookup(SelectorContext.java:156)
at javax.naming.InitialContext.lookup(Unknown Source)
at util.DbUtil.getConnection(DbUtil.java:23)
at dao.NoticeDao.getNoticesByEvent(NoticeDao.java:49)
at dao.NoticeDao.getNoticesByStatus(NoticeDao.java:46)
at util.AppMailer.sendMailQueue(AppMailer.java:88)
at util.AppMailer.run(AppMailer.java:71)
at java.lang.Thread.run(Unknown Source)
java.sql.SQLException: PooledConnection has already been closed.
at org.apache.tomcat.jdbc.pool.DisposableConnectionFacade.invoke(DisposableConnectionFacade.java:86)
at com.sun.proxy.$Proxy7.prepareStatement(Unknown Source)
at dao.NoticeDao.getNoticesByEvent(NoticeDao.java:60)
at dao.NoticeDao.getNoticesByStatus(NoticeDao.java:46)
at util.AppMailer.sendMailQueue(AppMailer.java:88)
at util.AppMailer.run(AppMailer.java:71)
at java.lang.Thread.run(Unknown Source)
Update: For a second attempt, I simplified and separated the daemon stuff from the application logic. The app logic is now fully standalone. But I have the same problem.
public class AppMailerRunner implements ServletContextListener {
private ServletContext context = null;
private Thread mailerThread;
public AppMailerRunner() {}
#Override
public void contextInitialized(ServletContextEvent event) {
this.context = event.getServletContext();
System.out.printf("Starting: %s\n",this.getClass());
mailerThread = new Thread(new MailerDaemon());
mailerThread.setDaemon(true);
mailerThread.start();
}
#Override
public void contextDestroyed(ServletContextEvent event) {
System.out.printf("Stopping: %s\n",this.getClass());
mailerThread.interrupt();
this.context = null;
}
class MailerDaemon implements Runnable {
#Override
public void run() {
AppMailer appMailer = new AppMailer();
while(!Thread.currentThread().isInterrupted()){
try {
appMailer.sendMailQueue();
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
...
<listener>
<listener-class>util.AppMailerRunner</listener-class>
</listener>
...
public class AppMailer{
private NoticeDao noticeDao;
private Session mailSession;
private Boolean sending;
...
public AppMailer() {
super();
noticeDao = new NoticeDao();
sending = false;
}
do stuff...
...
public class NoticeDao {
public NoticeDao() {
}
...
public List<Notice> getNotices() {
Connection conn = DbUtil.getConnection();
List<Notice> notices = new ArrayList<Notice>();
try {
PreparedStatement ps = conn.prepareStatement("SELECT * FROM notices");
ResultSet rs = ps.executeQuery();
while (rs.next()) {
Notice notice = mapFields(rs);
notices.add(notice);
}
} catch (SQLException e) {
System.out.println(e.getMessage());
e.printStackTrace();
} finally {
DbUtil.close(conn);
}
return notices;
}
private static Notice mapFields(ResultSet rs) throws SQLException {
Notice notice = new Notice();
notice.setId( rs.getLong("id"));
notice.setItemid( rs.getLong("itemid"));
notice.setItemtype( rs.getString("itemtype"));
notice.setTestmode( rs.getBoolean("testmode"));
notice.setName( rs.getString("name"));
notice.setStatus( rs.getString("status"));
notice.setError( rs.getString("error"));
notice.setCreated( rs.getDate("created"));
notice.setModified( rs.getDate("modified"));
notice.setLog( rs.getString("log"));
return notice;
}
...
}
...
public class DbUtil {
private static Connection conn = null;
public DbUtil() {
}
public static Connection getConnection() {
InitialContext ctx;
try {
ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/somedb");
conn = ds.getConnection();
} catch (NamingException e) {
System.out.println(e.getMessage());
e.printStackTrace();
} catch (SQLException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
return conn;
}
public static void close(Connection conn){
if(conn!=null)
try {
conn.close();
} catch (SQLException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
}
Try adding break statement in the catch block in your MailerDaemon class.
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
Note that interruption status is cleared when InterruptedException is thrown. So the thread created in the contextInitialized will never break out of the loop.
See the javadoc here.
Hope this helps.
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.
import java.sql.*;
// I think this is a poor abstraction
public class NewConnection {
/*very important: dont use statics for your Connection, Statement and Query objects,
since they can and will be overriden by other Instances of your NewConnection.*/
// There's no need at all for having class members here. It's actually
// a terrible idea, because none of these classes are thread-safe.
private Connection con;
private ResultSet rs;
private Statement sm;
// Better to pass these in.
private final String DRIVER = "sun.jdbc.odbc.JdbcOdbcDriver";
private final String URL = "jdbc:odbc:Driver={Microsoft Access driver (*.mdb)};DBQ=E:\\db1.mdb;DriverID=22";
// private final String URL = "jdbc.odbc.Cooper_Dsn1";
// Another poor idea. Why not just pass this in to the query method?
private static String query;
int i;
private void getConnection(){
try {
Class.forName(DRIVER);
}
catch(ClassNotFoundException e)
// Less information that printing the stack trace.
{System.out.println("Error ="+e);}
try{
System.out.println("Driver Connected");
con=DriverManager.getConnection(URL,"","");
System.out.println("Database Connected");
sm=con.createStatement();
}catch(SQLException e){
System.out.println(e.getMessage());
}
}
// lower case "execute" is the Java convention
private int ExecuteUpdate(String query1)
{ try{
System.out.println(query1);
i=sm.executeUpdate(query1);
con.commit();
}catch(SQLException e){
// No rollback in the event of a failure
System.out.println(e.getMessage());
}
return i;
}
public int executeUpdate(String sql) throws SQLException
{
System.out.println(sql);
con.commit(); // What's this doing? Incorrect
return sm.executeUpdate(sql);
}
// Here's how I might write an update method.
public static int update(Connection connection, String sql)
{
assert connection != null && sql != null;
int numRowsAffected = 0;
PreparedStatement ps = null;
connection.setAutoCommit(false);
try
{
numRowsAffected = ps.execute(sql);
connection.commit();
}
catch (SQLException e)
{
e.printStackTrace();
DatabaseUtils.rollback(connection); // Add this method.
numRowsAffected = 0;
}
finally
{
DatabaseUtils.close(ps);
}
return numRowsAffected;
}
public static void main(String []args) throws SQLException{
NewConnection n= new NewConnection();
n.getConnection();
query="insert into Employee(empid,ename,ephone,email) values('samr','sam','sa','aas');";
System.out.println(n.ExecuteUpdate(query));
}
}
I had modified the code to this....but still has no effect... The query runs successfully but doesn't add data in database. Don't know y..? The code creates the table in database successfully if query changed.
Can any one tell me what is the problem Or Where i m wrong..
You won't see any INSERT with Access until you close your Connection properly.
Your code doesn't close any resources, which will surely bring you grief. Call the close methods in reverse order in a finally block.
public class DatabaseUtils
{
public static Connection createConnection(String driver, String url, String username, String password)
throws ClassNotFoundException, SQLException
{
Class.forName(driver);
return DriverManager.getConnection(url, username, password);
}
public static void close(Connection connection)
{
try
{
if (connection != null)
{
connection.close();
}
}
catch (SQLException e)
{
e.printStackTrace(e);
}
}
public static void close(Statement statement)
{
try
{
if (statement != null)
{
statement.close();
}
}
catch (SQLException e)
{
e.printStackTrace(e);
}
}
public static void close(ResultSet rs)
{
try
{
if (rs != null)
{
rs.close();
}
}
catch (SQLException e)
{
e.printStackTrace(e);
}
}
}