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

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.

Related

DAO insert behavior doesnt seem normal

I made the DAO to create a sales offer and it is similar to an other DAO where it makes users and that connects and works. But the one below keeps skipping the if statements and I'm not sure why it isn't adding to the data base. I ran the same command in the SQL string in oracle and it worked there.
public boolean sendOffer(Sales sell) {
boolean done = false;
int key =0;
Connection conn = cu.getConnection();
try {
String sql = "INSERT INTO sales (offer_amount, offer_who, car_id) values(?,?,?)";
String[]keys= {"ID"};
PreparedStatement ps = conn.prepareStatement(sql,keys);
ps.setInt(1, sell.getOfferAmount());
ps.setInt(2, sell.getOwnerID()); //foriegn key
ps.setInt(3, sell.getCarID()); // forgien key
int number = ps.executeUpdate();
ResultSet rs = ps.getGeneratedKeys();
if(number!=1)
{
log.warn("data insert fail");
}
else
{
log.trace("success");
done=true;
}
if(rs.next()) {
key=rs.getInt(1);
sell.setID(key);
conn.commit();
}
else {
log.warn("data not found");
}
}catch(SQLException e)
{
}
finally {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
}
}
// TODO Auto-generated method stub
return done;
}'''
The main issue is that an exception is happening in your code but the try/catch block is intercepting it and swallowing it silently. While it may be tempting to catch and swallow exceptions, truth is it always causes more problems than it solves and the key concept of handling exceptions is to NOT handle them: just put the throws declaration and let the application crash.
You then have other possible side-issues depending on how the Connection was obtained in the first place, like the fact that you're never closing the PreparedStatement and the ResultSet (if the connection is closed, they are closed as well... but if the connection is returned to a pool then they are never going to be closed).
In general the above code tends to pack too much functionality in a single method and can quickly spiral out of control, so you might want to divide it in smaller chunks with clear individual responsibilities.
All of the above is common to observe wherever Connection and PreparedStatement are used directly, be it for maximum performance reasons or for lack of experience. Typically in web applications using the Spring framework this is solved through the use of a JdbcTemplate but I cannot assume that you are using Spring so I won't show its usage here.
At a minimum, I would modify your code roughly as follows:
public boolean sendOffer(Sales sell) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = cu.getConnection();
ps = prepareInsertOfferStatement(sell, conn);
ps.executeUpdate();
rs = ps.getGeneratedKeys();
sell.setID(extractKey(rs));
conn.commit();
log.trace("success");
return true;
}
catch(Exception ex) {
log.error(ex); // this is actually probably bad. Consider putting a throws declaration and get rid of this catch
return false;
}
finally {
closeQuietly(rs, ps, conn);
}
}
private void closeQuietly(AutoCloseable... objs) {
for(AutoCloseable obj : objs) {
try {
obj.close();
} catch (SQLException e) {
// this is usually mostly safe to ignore. Maybe log a warning somewhere
}
}
}
private PreparedStatement prepareInsertOfferStatement(Sales sell, Connection conn) throws SQLException {
String sql = "INSERT INTO sales (offer_amount, offer_who, car_id) values(?,?,?)";
String[] keys= {"ID"};
PreparedStatement ps = conn.prepareStatement(sql,keys);
ps.setInt(1, sell.getOfferAmount());
ps.setInt(2, sell.getOwnerID()); //foreign key
ps.setInt(3, sell.getCarID()); // foreign key
return ps;
}
private int extractKey(ResultSet rs) throws SQLException {
if(rs.next()) {
return rs.getInt(1);
}
else {
throw new Exception("The statement did not return any generated key.");
}
}
As you can see it's not shorter, but responsibilities are clearer and all objects are closed accordingly. Furthermore, it gives you nice reusable primitives to close connections and related objects and to extract the key from other inserts you will want to do. Further abstractions would allow you to obtain more primitives, but I think this is sufficient for you to get the gist of it.

Java try-with at complex apis

I want to wrap some JDBC code into my own and different classes. So the resource is created in those classes, the result set is returned. If the client is ready, then all in that chain opened resources should be closed.
I wrote the following, but I'm not sure if that is correct enough and the easiest way.
I build a SQL string for insertion of a data-row.
From my data source (hikari pool), I get a database connection. Then I create a prepared statement, I execute this and get a ResultSet back.
This result set I return to the caller.
The connection and prepared statement have to remain open, until the caller is ready with that returned result set
public DbResult insert(int cache, String shema, String table, LinkedHashMap<String, Object> data, boolean returnAutoCreate) throws SQLException
{
//building sql-string or take it from my cache
//...
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try
{
connection = ds.getConnection();
preparedStatement = connection.prepareStatement(sqlString);
int i = 0;
for (Object value : data.values())
{
preparedStatement.setObject(i++, value);
}
preparedStatement.executeUpdate();
resultSet = preparedStatement.getResultSet();
DbResult dbResult = new DbResult(connection, preparedStatement, resultSet);
return dbResult;
}
catch (Exception e)
{
try
{
if (resultSet != null) resultSet.close();
}
catch (Exception e2)
{
e.addSuppressed(e2);
}
try
{
if (preparedStatement != null) preparedStatement.close();
}
catch (Exception e2)
{
e.addSuppressed(e2);
}
try
{
if (connection != null) connection.close();
}
catch (Exception e2)
{
e.addSuppressed(e2);
}
throw e;
}
}
Here is my DbResult class
class DbResult implements AutoCloseable
{
private final ResultSet rs;
private final PreparedStatement ps;
private final Connection conn;
public DbResult(Connection conn, PreparedStatement ps, ResultSet rs)
{
this.conn = conn;
this.ps = ps;
this.rs = rs;
}
#Override
public void close() throws SQLException
{
try (conn; ps; rs;){}
}
public ResultSet getResultSet()
{
return rs;
}
}
And here the client/caller-code
DatabaseHelper databaseHelper = new DatabaseHelper(ds, defaultShema);
try(DbResult result = databaseHelper.insert(1001, defaultShema, "test", new LinkedHashMap<>(), true);)
{
//do sth with result
}
In my insert method I added that try catch, cause if something fails there, I must close the resources.
If there is no problem, I add the resources to my DbResult object, and there I close the resources with the close()-method. In that, I use a try-with, cause if in that chain one close fails, then the others are still closed, and the exception is forwarded correctly.
At my caller, I use also a try-with, which calls that close()-method in DbResult after I'm done with the result.
But it's a lot of code, especially the try-catch construct in my insert-method.
I'm not sure, if there is a easier or a better way of doing that.
One more question I have:
I could cache the result, so I don't have to take care of that resource closing outside of my DatabaseHelper class.
There exists a CachedRowSet. But I'm not sure about, how expensive this is. Does that copy also the MetaInformations?
I guess the normal ResultSet retrieves the data first, if I access them:
the meta data, the row-data: row by row?
Is that a good idea to cache the data into ArrayList of Hashmaps?
Arraylist -> Rows
HashMap -> coloums by name -> value
So if I do that, I can close all resources immediately.
-> I don't have to care about that closing outside of my DatabaseClass
-> the pool gets the connection faster back
However, maybe I retrieve data, which I don't need (for example, the meta data).
Also, it's expensive to build a copy of my data into a ArrayList->Hashmap construct.
So what ideas do you have of that; whats the best practice?

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

Managing database connections in java

A full day of googling this problem has left me more confused than ever so I'm appealing to SO for help. I'm trying to use pooled connections to a mysql DB but I'm clearly misunderstanding something. Below are snippets of code from an application that scans a folder for new directories that represent "jobs"; when found, database objects are created for each folder found. I based the _insert() method on a pattern I found on SO. My understanding is that the connections are properly closed and returned to the connection pool. However, I noticed that, after adding 8 objects, the code would hang on getConnection(). I found somewhere that the default number of active connections was 8, so I added the debug line where I limit the number of active connections to 2. Sure enough, only two objects get added before the code hangs.
What's going on? What do I need to change to make these connections get freed and added back to the pool? I found one post that mentioned the PoolableConnection class but I'm confused by the documentation as well as by the fact that most other examples I've found don't seem to use it.
The Scanner class that creates Job objects in the database based on folders found in a particular directory on disk:
public class Scanner extends Thread {
public void run() {
syncJobs();
}
void syncJobs(List<String> folderNames) {
for (String folderName : folderNames) {
Job job = addJobToDB(folderName);
}
}
Job addJobToDB(String folderName ) {
Job job = new Job();
job.name = folderName;
job.save();
return job;
}
}
There's an abstract base class for all objects (each objects overrides _insert):
public abstract class DBObject {
private final int insert() {
return _insert();
}
public final void save() {
if (id == 0)
id = insert();
else
update();
}
}
And there's the actual Job object (with only the insert method shown):
public class Job extends DBObject {
public int _insert() {
String query = "insert into jobs (name) values (?)";
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
int id = 0;
try {
conn = Database.getConnection();
ps = conn.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
ps.setInt(1, id);
ps.executeUpdate();
rs = ps.getGeneratedKeys();
rs.next();
id = rs.getInt(1);
} catch (Exception e) {
System.out.println(e.getMessage());
} finally {
DbUtils.closeQuietly(rs);
DbUtils.closeQuietly(ps);
DbUtils.closeQuietly(conn);
}
return id;
}
}
And, lastly, the Database object that provides connections:
import org.apache.commons.dbcp.BasicDataSource;
public final class Database {
private static final BasicDataSource dataSource = new BasicDataSource();
static {
dataSource.setUrl("jdbc:mysql://localhost:3306/dbName?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC");
dataSource.setUsername("user");
dataSource.setPassword("****");
// This line added for debugging: sure enough, only 2 objects are created.
dataSource.setMaxActive(2);
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
}

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

Categories