Java Swing Timer with SQL - java

I'm trying to setup a thread that loops every 100ms with every iteration querying a table in a SQL database. Here is what I have in my public static void main class. How can I define the connection outside of the listener and only call the query in the loop?
// Database credentials
final String url = "jdbc:mysql://192.168.0.0/";
final String db = "db";
final String driver = "com.mysql.jdbc.Driver";
final String table = "table";
public final Connection conn = null;
// Define listner
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
//...Perform a task...
System.out.println("Reading Info.");
try {
Class.forName(driver);
try {
conn = DriverManager.getConnection(url+db,"root","pass");
Statement st = (Statement) conn.createStatement();
String sql = "";
st.executeUpdate(sql);
conn.close();
} catch (SQLException s) {
s.printStackTrace();
JOptionPane.showMessageDialog(null, "ERROR: Please try again!");
}
} catch (ClassNotFoundException cnfe){
JOptionPane.showMessageDialog(null, "ERROR:");
}
}
};
Timer timer = new Timer( 100 , taskPerformer);
timer.setRepeats(true);
timer.start();
Thread.sleep(100);
}
Right now it's giving me the following error:
Exception in thread "AWT-EventQueue-0" java.lang.Error: Unresolved compilation problem:
The final local variable conn cannot be assigned, since it is defined in an enclosing type

You don't want to. Connections are not thread safe per JDBC specification. Hence there is no reason or justification for Connection variable not being local to the thread. Why isn't it?

Now that you have an answer to your non-proximate issues, let me complement that with your proximate issue. You have this: public final Connection conn = null; which makes no sense. You have assigned null to a final variable. You may have added final because the compiler complained you are using a non-final variable in an inner class. What you probably want to achieve is a lazily initialized singleton. Remove the final modifier and then write a separate synchronized function that retrieves the connection and initializes it as needed:
private Connection conn;
private synchronized Connection connection() {
if (conn == null) conn = createConnection();
return conn;
}
Of course, you'd better make sure that you never use the connection concurrenly, but your use case doesn't call for that. Another issue with this naive approach to connection pooling are connections left in an invalid state.

Related

JDBC and Multithreading

I am trying to run few queries using a multithreaded approach, however I think I am doing something wrong because my program takes about five minute to run a simple select statement like
SELECT * FROM TABLE WHERE ID = 123'
My implementation is below and I am using one connection object.
In my run method
public void run() {
runQuery(conn, query);
}
runQuery method
public void runQuery(Connection conn, String queryString){
Statement statement;
try {
statement = conn.createStatement();
ResultSet rs = statement.executeQuery(queryString);
while (rs.next()) {}
} catch (SQLException e) {
e.printStackTrace();
}
}
Finally in the main method, I start the threads using the snippet below.
MyThread bmthread = new MyThread(conn, query);
ArrayList<Thread> allThreads = new ArrayList<>();
double start = System.currentTimeMillis();
int numberOfThreads = 1;
for(int i=0; i<=numberOfThreads; i++){
Thread th = new Thread(bmthread);
th.setName("Thread "+i);
System.out.println("Starting Worker "+th.getName());
th.start();
allThreads.add(th);
}
for(Thread t : allThreads){
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
double end = System.currentTimeMillis();
double total = end - start;
System.out.println("Time taken to run threads "+ total);
Update : I am now using separate connection for each thread.
ArrayList<Connection> sqlConn = new ArrayList<>();
for(int i =0; i<10; i++){
sqlConn.add(_ut.initiateConnection(windowsAuthURL, driver));
}
loop:
MyThread bmthread = new MyThread(sqlConn.get(i), query);
As rohivats and Asaph said, one connection must be used by one and only one thread, that said, consider using a database connection pool. Taking into account that c3p0, DBCP and similars are almost abandoned, I would use HikariCP which is really fast and reliable.
If you want something very simple you could implement a really simple connection pool using a thread safe collection (such as LinkedList), for example:
public class CutrePool{
String connString;
String user;
String pwd;
static final int INITIAL_CAPACITY = 50;
LinkedList<Connection> pool = new LinkedList<Connection>();
public String getConnString() {
return connString;
}
public String getPwd() {
return pwd;
}
public String getUser() {
return user;
}
public CutrePool(String connString, String user, String pwd) throws SQLException {
this.connString = connString;
for (int i = 0; i < INITIAL_CAPACITY; i++) {
pool.add(DriverManager.getConnection(connString, user, pwd));
}
this.user = user;
this.pwd = pwd;
}
public synchronized Connection getConnection() throws SQLException {
if (pool.isEmpty()) {
pool.add(DriverManager.getConnection(connString, user, pwd));
}
return pool.pop();
}
public synchronized void returnConnection(Connection connection) {
pool.push(connection);
}
}
As you can see getConnection and returnConnection methods are synchronized to be thread safe. Get a connection (conn = pool.getConnection();) and don't forget to return/free a connection after being used (pool.returnConnection(conn);)
Don't use the same connection object in all threads. Give each thread a dedicated database connection.
One Connection can only execute one query at a time. You need multiple connections available to execute database operations in parallel. Try using a DataSource with a connection pool, and make each thread request a connection from the pool.

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();
}

Can I use the same connection object when calling within Methods?

I have got a program this way:
public void MethodOne()
{
String sqlquery = "select * from vendor_items where category_id = 1 ";
PreparedStatement consildatedPst = connection.prepareStatement(sqlquery);
ResultSet consilatedReslset = consildatedpst.executeQuery();
while(consilatedReslset.next())
{
String name = consilatedReslset.getString("name");
if(name!=null)
{
MethodTwo();
}
}
}
public void MethodTwo(String name)
{
String sqlquery2 = "select ename from Vendor where name=?";
PreparedStatement otherPst = connection.prepareStatement(sqlquery2);
otherPst.setString(1,name);
}
This is the way connection is established (Later I will go for Connection Pooling).
public class DBConnection {
public static Connection getDBConnection() {
String sURL="jdbc:mysql://localhost:3306/oms";
String sUserName="root";
String sPwd="";
Connection conn = null;
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(sURL, sUserName,sPwd);
return conn;
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return conn;
}
}
My question is Can I use the same connection object when calling within Methods??
Yes, you can.
When you do:
connection.prepareStatement(sqlquery2);
It creates a new statement object using the same connection. So the ResultSets that you obtain from them will belong to different Statements and will be different and there will be NO PROBLEM for you.
In short: Different Statements manage different ResultSets. If you get 2 ResultSets from the same Statement when you get the second one the first one will be dropped but if you have 2 Statements you can manage 2 ResulSets without problem (while the connection is open, of course)
Only if you aren't using the connection in multiple threads or nesting your own methods. In other words, no. Use a new connection per method. To avoid overhead use a connection pool.

Swing form database connection

I am new to Java and NetBeans, and I am attempting to create a form that
connects to a database using JDBC connection
reads information from seven columns and displays them on a jTable component already on the form
I already have this working. I am now trying to optimize my code and use a better architecture to separate the database connection and the user interface (UI forms) code so that I can have a separate class to perform the connection and then simply call the method from this class in the code behind the button. The problem with using NetBeans and forms is that I don't know where to instantiate this class and such. Below is a cope of the class that I have created to perform the JDBC connection
public class ConnectionManager {
private static String url = "jdbc:mysql://localhost:3306/prototypeeop";
private static String driverName = "com.mysql.jdbc.Driver";
private static String username = "root";
private static String password = "triala";
private static Connection con;
private static String url;
public static Connection getConnection() {
try {
Class.forName(driverName);
try {
con = DriverManager.getConnection(url, username, password);
} catch (SQLException ex) {
// log an exception. fro example:
System.out.println("Failed to create the database connection.");
}
} catch (ClassNotFoundException ex) {
// log an exception. for example:
System.out.println("Driver not found.");
}
return con;
}
}
This is already a .java file. I have a JForm, and I need to call this method behind the button. Here is how I do it in the form currently without using a connection class:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
DefaultTableModel model=(DefaultTableModel)jTable1.getModel();
model.setRowCount(0);
String sql="Select * from eopdata";
try
{
Class.forName("com.mysql.jdbc.Driver");
Connection con=(Connection)DriverManager.getConnection("jdbc:mysql://localhost:3306/prototypeeop","root","jakamuga");
Statement stmt=con.createStatement();
ResultSet rs=stmt.executeQuery(sql);
while(rs.next())
{
String Year=rs.getString("Year");
String Month=rs.getString("Month");
String Day=rs.getString("Day");
String MJD=rs.getString("MJD");
Double xarcsec=rs.getDouble("xarcsec");
Double yarcsec=rs.getDouble("yarcsec");
Double UT1UTCsec=rs.getDouble("UT1UTCsec");
model.addRow(new Object[] { Year, Month, Day, MJD,xarcsec,yarcsec,UT1UTCsec});
}
}
catch(Exception e) {
JOptionPane.showMessageDialog(this, e.getMessage());
}
How can I use the class instead of hard coding in the connection? I have already created the class but where do I instantiate it. Do I do it in the main of the form or do I do it in the actionevent code with the following code?
private Connection con = null;
private Statement stmt = null;
private ResultSet rs = null;
con = ConnectionManager.getConnection();
stmt = con.createStatement();
rs = stmt.executeQuery(sql);
To literally answer your question: your getConnection method is a public static method so you can call this from anywhere. Just call ConnectionManager.getConnection() where-ever you need that connection.
Some other remarks about your code:
You shouldn't query a database in the actionPerformed method. This method is called on the EDT, and doing a database query and looping over the results is a long-running task. Doing this task on the EDT will block your UI. Consult the Concurrency in Swing tutorial for more info about Swing and threading
Consider caching the Connection object
Do not forget to close your resources. If I remember correctly, a ResultSet must be closed afterwards. Do this in a finally block

Nullpointer Exception (Derby, JDBC)

Hy!!
My error code:
Exception in thread "main" java.lang.NullPointerException
at lesebank.Konto.getKontofromID(Konto.java:39)
at lesebank.Main.main(Main.java:18)
SQL EXCEPTIONJava Result: 1
BUILD SUCCESSFUL (total time: 1 second)
Method:
Konto konto = new Konto ();
Statement s = dbconn.getSt();
try
{ //in the next line the error occurs
s.execute("select id,inhaberin,ktostd,habenzinsen,notiz from Konto where id = " +id);
ResultSet set = s.getResultSet();
if (set.next())
{
konto.setId(set.getInt(1));
konto.setId_inhaberin(set.getInt(2));
konto.setKtostd(set.getDouble(3));
konto.setHabenzinsen(set.getDouble(4));
konto.setNotiz(set.getString(5));
return konto;
}
}
catch (SQLException ex)
{
System.out.print(ex.getMessage());
}
return null;
DBConn:
public class DBConnection {
private String url = "jdbc:derby://localhost:1527/Bank";
private Connection conn;
private Statement st;
public DBConnection() {
try
{
conn = DriverManager.getConnection(this.url, "test", "test");
st = conn.createStatement();
}
catch (SQLException ex)
{
System.out.print("SQL EXCEPTION");
}
}
public Statement getSt() {
return st;
}
Database:
Please help
This is Very Bad(tm):
public DBConnection() {
try
{
conn = DriverManager.getConnection(this.url, "test", "test");
st = conn.createStatement();
}
catch (SQLException ex)
{
System.out.print("SQL EXCEPTION");
}
}
Do not catch and ignore exceptions like this. There are there for a very good reason. In this case, if your constructor fails due to an exception, the whole DbConnection object is rendered useless, since the st field will be null. Yet because the code that instantiated DbConnection has no idea this has happened, you go on to use it, and end up with the null-pointer exception.
If DbConnection's constructor triggers an exception, you need to throw that exception out of the constructor, forcing your code to deal with the exception:
public class DBConnection {
private static final String URL = "jdbc:derby://localhost:1527/Bank";
private final Connection conn;
private final Statement st;
public DBConnection() throws SQLException {
conn = DriverManager.getConnection(URL, "test", "test");
st = conn.createStatement();
}
public Statement getSt() {
return st;
}
}
Note also the final fields. This gives you a compile-time guarantee that something will be assigned to those fields.
Please check that dbconn.getSt() is not returning null. What is getSt(), anyway; anything like createStatement()? Now that I see your edit, it is likely that your DBConn class is not successful in its call to createStatement().
Not quite able to test right now, but I would sugest you make your DBConnection.getSt() method return a brand new Statement object, instead of reusing the same one over and over. Would be something like:
public Statement getSt() {
return conn.createStatement();
}
Remember to close your statement after using it.

Categories