I have a project that is structured like this
Business Logic Layer -->> DAO layer -->> QueryExecuter
Business Object calls dao layer and dao layer then called QueryExecuter class to execute the query. The QueryExecuter class is as follows
public class QueryExecutor {
private static final Logger LOG = Logger.getLogger(QueryExecutor.class);
//java.sql.Connection
private Connection connection;
public QueryExecutor(){
//apache commons db utils QueryRunner object.
queryRunner = new QueryRunner( );
initilizeConnection();
}
private QueryRunner queryRunner;
private QueryResult queryResult = new QueryResult();
private void initilizeConnection(){
LOG.info("Getting Connection ");
try {
this.connection = FitClineConnectionManager.getInstance().getConnection();
} catch (SQLException e) {
LOG.fatal("Problem Getting connection ");
LOG.fatal(e.getMessage());
} catch (IOException e) {
LOG.fatal("Problem Getting connection ");
LOG.fatal(e.getMessage());
} catch (PropertyVetoException e) {
LOG.fatal("Problem Getting connection ");
LOG.fatal(e.getMessage());
}
}
public QueryResult saveAndReturnId(String sql , Object[] params ) {
ResultSet rs = null;
Connection connection = null;
PreparedStatement statement = null;
try {
connection = getConnection();
statement = connection.prepareStatement(sql , Statement.RETURN_GENERATED_KEYS);
queryRunner.fillStatement( statement, params);
statement.executeUpdate();
rs = statement.getGeneratedKeys();
queryResult.setLastInsertedId( new AutoGeneratedKeyHandler().handle( rs ) );
queryResult.setStatus( QUERY_STATUS.SUCCESS.getCode() );
} catch (SQLException e) {
if ( e.getSQLState().equalsIgnoreCase("23000") ){
queryResult.setError( ErrorCodeProperties.getInstance().get_00004() );
}
LOG.error(e.getMessage());
} finally{
if ( statement != null ){
try {
//closing statement
DbUtils.close( statement );
} catch (SQLException e) {
LOG.error(e.getMessage());
}
}
closeConnection();
}
return queryResult;
}
}
In this structure , connections are managed in QueryExecuter class, how do I open transaction from Business Layer b/c connections are managed in QueryExecuter class. And I want connection object in my Business Layer to do so. Is there any smart way to achieve this.
I am not using any dependency injection in my project, Just apache commons DBUtils and jdbc.
P.S. In current scenario, QueryExecuter object is composed inside base Dao class, so multiple method call(for transaction) will result in multiple connection acquiring from pool.
Related
I am currently reworking an ADF Fusion application, that uses a lot of Java nested in Beans to actually manage JDBC requests. As the code ermerged from the pre-Java8 era there is a bunch of deprecated technologies in it and I neither have the time nor the knowledge to rework everything (which describes the percentage of the code that is outdated and hard to debug).
Something very regularly is that inside the backing bean classes manual JDBC requests with our inhouse DB are handled (often uncannily nested in other methods). As I began to outsource them I realized I wrote the same block of code over and over again:
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
conn = CC.getConn(); //CC is of type "CustomConnection",
//a static assist class that fetches the connection
stmt = conn.createStatement();
rs = stmt.executeQuery("Some SQL");
while(rs.next()) {
//handle the result
}
} catch(Exception e){
e.printStackTrace();
} finally {
try {
rs.close();
stmt.close();
conn.close();
} catch(Exception e){
e.printStackTrace();
}
}
or for PreparedStatement respectively:
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = CC.getConn(); //CC is of type "CustomConnection",
//a static assist class that fetches the connection
pstmt = conn.prepareStatement("Some SQL");
//populate the pstmt with params
rs = pstmt.executeUpdate();
while(rs.next()) {
//handle the result
}
} catch(Exception e){
e.printStackTrace();
} finally {
try {
rs.close();
pstmt.close();
conn.close();
} catch(Exception e){
e.printStackTrace();
}
}
While I'm aware that this is not the best practice it worked reliable so far but writing multiple methods like this with real difference only in the handling of the ResultSet became very tedious. So my approach was to write an abstract superclass that provides a request() method and let the extending classes define the parameters to populate a PreparedStatement and the handling of the ResultSet.
public abstract class Requestable {
public void request(String SQL, HashMap<String, Integer> args) {
Connection conn = null;
PreparedStatement pstmt = null;
try {
conn = CC.getConn();
pstmt = conn.prepareStatement(SQL);
pstmt = fill(args);
onResponse(pstmt.executeUpdate());
//handle result
} catch(Exception e) {
e.printStackTrace();
} finally {
try {
pstmt.close();
conn.close();
} catch(Exception e) {
e.printStackTrace();
}
}
}
public abstract PreparedStatement fill(HashMap args);
public abstract void onResponse(ResultSet rs);
public Requestable() {
super();
}
}
This would be an example for PreparedStatement. Statements would get an own separate method.
Writing this draft, I came across the issue that some classes which are intended to extend Requestable currently have multiple different requests that they perform (which all need a specific handling of the result). With my approach, I could define the methods fill() and onResponse() only once per class. Is there a way to like pass a function reference to request() that gets defined in the extending class and executed at the position of fill() and onResponse()?
I have the following class:
public class Refunds {
ResultSet dataToHash = null;
public Refunds (String UrnId) {
Database db = null;
CallableStatement callable;
String query = "select * from testmdb.dbo.ApEdiZcusSaSendFile where SourceID='LAN' and UrnID=?";
// Get database connection
try {
db = new Database("jdbc/refund");
} catch (NamingException | SQLException e1) {
e1.printStackTrace();
}
// Run the query
try {
callable = db.connection.prepareCall(query);
callable.setString(1, UrnId);
dataToHash = callable.executeQuery();
} catch (SQLException s) {
System.out.println("A SQL exception was thrown while running the query: ");
s.printStackTrace();
} catch (Exception e) {
System.out.println("A general exception was thrown while running the query: ");
e.printStackTrace();
} finally {
db.closeConnection();
}
}
public ResultSet getDataToHash() {
return dataToHash;
}
}
And I use it like this:
// Get the result set
Refunds refunds = new Refunds(urnId);
ResultSet dataToHash = refunds.getDataToHash();
However, every single time dataToHash is .closed(). I don't close my ResultSet. Whatever the problem is, how can I modify this code so that when I get it, it won't be closed?
PS - Just ignore my old school System.outs...
You close the connection, and that closes the ResultSet.
Instead of storing the ResultSet in a class member, store it in a local variable inside Refunds, and read all the data from it before returning from the Refunds method and closing the connection.
I am going to enhance the performance of my program. For this purpose I am going to implement some parts of my program to be done in memory instead of database. I dont know which one is better in this regards, in-memory database or normal java data structure.For in-memory database I considered Tentimes from oracle and H2. So another question would be which solution is better for around 100 million records of data on single machine for single user? Also another question would be is the old way of database connection works fine in this way? Here is the connection that I used for oracle, What is the appropriate Driver for this purpose.
public static Connection getConnection(){
//If instance has not been created yet, create it
if(DatabaseManager.connection == null){
initConnection();
}
return DatabaseManager.connection;
}
//Gets JDBC connection instance
private static void initConnection(){
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
String connectionUrl = "jdbc:oracle:thin:#localhost:1521:" + dbName;
DatabaseManager.connection =
DriverManager.getConnection(connectionUrl,"****","****");
}
catch (ClassNotFoundException e){
System.out.println("Oracle driver is not loaded!");
System.exit(0);
}
catch (SQLException e){
System.out.println(e.getMessage());
System.exit(0);
}
catch (Exception e){
}
}
public static ResultSet executeQuery(String SQL) throws SQLException
{
CachedRowSetImpl crs = new CachedRowSetImpl();
ResultSet rset = null ;
Statement st = null;
try {
st = DatabaseManager.getConnection().createStatement();
rset = st.executeQuery(SQL);
crs.populate(rset);
}
catch (SQLException e) {
System.out.println(e.getMessage());
System.exit(0);
}finally{
rset.close();
st.close();
}
return crs;
}
public static void executeUpdate(String SQL)
{
try {
Statement st = DatabaseManager.getConnection().createStatement();
st.executeUpdate(SQL);
// st.close();
}
catch (SQLException e) {
System.out.println(e.getMessage());
System.exit(0);
}
}
Regards.
Can someone help me with this: I'm making a java database application and I want to put my methods for select,insert,update and delete into separated class so they can be called from another classes and reused.
Till now I managed to separate only methods for update and delete and for insert when not using prepared statement. Problem I'm encountering is how to return data's when doing select from database and put them into table.
Here are my update and delete method's in Queries class:
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import com.Konekcija.Konekcija;
public class Queries {
Konekcija konekcija = new Konekcija();
public void updateTable(String sqlQuery){
Connection conn = null;
Statement st = null;
try{
Class.forName("com.mysql.jdbc.Driver");
conn = konekcija.getConn();
st = conn.createStatement();
st.executeUpdate(sqlQuery);
}catch(Exception e){
e.printStackTrace();
}finally{
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public void deleteFromTable(String sqlQuery){
Connection conn = null;
Statement st = null;
try{
Class.forName("com.mysql.jdbc.Driver");
conn = konekcija.getConn();
st = conn.createStatement();
st.executeUpdate(sqlQuery);
}catch(Exception e){
e.printStackTrace();
}finally{
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
P.S. Connection properties are in another class "Konekcija"
You should create a collection and populate it with the results of the query, it should look something like:
List<Foo> selectFoos(Connection connection) throws SQLException {
PreparedStatement ps = connection.prepareStatement("select * from foo");
try {
ResultSet resultSet = ps.executeQuery();
try {
List<Foo> foos = new ArrayList<Foo>();
while (resultSet.next()) {
Foo foo = new Foo();
// use resultSet methods get... to retrieve data from current row of results
// and populate foo
foos.add(foo);
}
} finally {
resultSet.close();
}
} finally {
ps.close();
}
return foos;
}
try executeQuery method. in the java doc for "resultset" class you will find a example:
http://docs.oracle.com/javase/6/docs/api/java/sql/ResultSet.html
Return data for "select from table" would be ResultSet.
You may return the ResultSet to caller and get values (or)
Inside the "Select" method of Queries class retrieve the data from resultset and set it some VO object and add this VO to collection and return the collection (assuming you will get more than one row in ResultSet). For example if you are querying User table, create Java bean class "User" with get/set methods. Set retrieved values to this bean and return it.
//Create User class with get/set in some package.
Class.forName("com.mysql.jdbc.Driver");
conn = konekcija.getConn();
st = conn.createStatement();
ResultSet rs=st.execute(sqlQuery);
//Instantiate user class
while (rs.next())
System.out.println("Name= " + rs.getString("moviename") + " Date= " + String fName = rs.getString("firstName");
User myUser = new User();
myUser.setFirstName(fName);
}
NOTE: This code is hand typed. There may be syntax errors. Please use it as starting point.
In my Java application's DAO layer I have two DAO classes EmployeeDAO and BankDAO. I need to control/handle their database transactions. I use connection pooling to get database connections.
EmployeeDAO class:
public class EmployeeDAO {
String name;
String empCode;
int age;
// Getters & Setters
}
BankDAO class:
public class BankDAO {
String bankName;
String acNo;
String empCode;
// Getters & Setters
}
Let's say I am going to store an Employee and Bank account details related to that employee in two database tables. First I save employee and second I save bank details and if an error occurs when storing bank details I need to rollback complete transaction.
How to manage this sort of transaction while using DAOs?
If you are using plain JDBC, what you could do is share the same instance of Connection in the two instances of the DAO classes.
public class EmployeeDAO {
private Connection conn;
public void setConnection(Connection conn) {
this.conn = conn;
}
...
}
public class BankDAO {
private Connection conn;
public void setConnection(Connection conn) {
this.conn = conn;
}
...
}
In the client code, first you need to create a Connection object instance. Next, you need start the transaction, with conn.setAutoCommit(false);. Pass the Connection object instance to the both DAO classes. If no errors occurs in any operation, conn.commit();, otherwise, conn.rollback();
e.g.:
Connection conn = null;
try {
// getConnection from pool
conn.setAutoCommit(false);
EmployeeDAO employeeDAO = new EmployeeDAO();
employeeDAO.setConnection(conn);
BankDAO bankDAO = new BankDAO();
bankDAO.setConnection(conn);
// save employee
// save bank details
conn.commit();
catch(Exception e) {
if (conn != null) {
conn.rollback();
}
} finally {
if (conn != null) {
conn.close();
}
}
When you open a connection from the database, you can start a new transaction using the method [Connection#setAutoCommit][1](false), do all your insert/update/delete operations and execute commit to save all these changes, in case of an error you can rollback all the actions or to a savepoint. Here is an exampleof what I'm saying:
public void saveSomeData(DAOClass daoObject) {
Connection con = null;
try {
con = getConnectionFromDBPool(); //get the connection from the connection pool
con.setAutoCommit(false);
//start your transaction
PreparedStatement ps = con.prepareCall("insert into tablex values(?, ?)");
ps.setInt(1, daoObject.getAttribute1());
ps.setString(2, daoObject.getAttribute2());
ps.execute();
//add another insert/update/delete operations...
//at the end, you commit the transaction
con.commit();
} catch (Exception e) {
//start a rollback
if (con != null) {
try {
con.rollback();
} catch (Exception ex) {
}
}
//handle the exception
e.printStackTrace();
} finally {
if (con != null) {
try {
con.close();
} catch (Exception e) {
}
}
}
}
Another hint: you should close all the resources manually before closing the connection. This code is just explanatory, but I have should close the prepared statement after using it.
More info about handling transactions:
Using Transactions