I am using the c3p0 library as my datasource object.
I want to create a JDBC helper class that helps reduce the boilerplate code that JDBC has and I am wondering if my implementation is correct and are following best practices? Also, if there is an already existing library that provides these functionalities, like QueryRunner, maybe?
Most of my queries returns a list of results of a specified column. Will it be okay if I use the following helper method for all my queries?
public List<String> retrieveSQLQuery(String sqlQuery, String column) {
List<String> values = new ArrayList<>();
try (Connection conn = getConnection();
PreparedStatement statement = conn.prepareStatement(sqlQuery);
ResultSet rs = statement.executeQuery(sqlQuery)) {
while (rs.next()) {
values.add(rs.getString(column));
}
} catch (SQLException e) {
e.printStackTrace();
}
return values;
}
The getConnection() method lives in a JDBCUtil class which provides the connection to the datasource object. This helper class will be extending JDBCUtil thus why it has access to that method.
I also know that frameworks like spring and Hibernate provide utilities, however, those frameworks are too large for my project.
Related
I'm learning about JDBC and I have learned the steps: open connection, execute statement, get result, etc. I know about Connection, Statements and the other interfaces, but I just found a tutorial with another class, the Connector class. And I don't understand what exactly we can do with this Connector class. I have made some app without this class and I don't understand why do I need the Connector class? Any feedback will be apreciated!
Here is the code:
public Set getAllUsers() {
Connector connector = new Connector();
Connection connection = connector.getConnection();
try {
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM user");
Set users = new HashSet();
while(rs.next())
{
User user = extractUserFromResultSet(rs);
users.add(user);
}
return users;
} catch (SQLException ex) {
ex.printStackTrace();
}
return null;
}
UPDATE:
This is the link where you can find the entire code: https://dzone.com/articles/building-simple-data-access-layer-using-jdbc
Your Connector is probably a class with a factory method:
the factory method pattern is a creational pattern that uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object that will be created.
Basically it is a utility class to create a Connection hiding the complexity of connection creation.
I am using Vaadin framework and following MVC design pattern to develop a web application project.
While implementing connection pooling feature for my project I encountered the following problem.
I am getting the ResultSet in one class(data class) and I am using that ResultSet in another class(Business Logic).
I have to close the connection object after using that ResultSet in the business logic class.
What may be the efficient way to achieve this without passing the connection object to the business logic class?
Please Explain.Thank You.
I would recommend that you write a Dao which returns a List of Business Objects and NOT the resultsets. The connection must be closed in the Dao itself. Below is an example
public class PersonDao {
private DataSource ds; //add a setter and inject the JDBC resource
public List<Person> getPersons() {
List<Person> personList = new ArrayList();
Connection con;
PreparedStatement pstmt;
try {
con = ds.getConnection(username, password);
pstmt = con.prepareStatement("SELECT * FROM PERSON");
ResultSet rs = pstmt.executeQuery(query);
//Fetch the resultset, iterate over it and populate the list
while (rs.next()) {
Person p = new Person();
p.setName(rs.getString("name");
personList.add(p);
}
} catch (Exception ex {
// ... code to handle exceptions
} finally {
if (con != null) con.close();
}
return personList;
}
If you can use Java 7, you can also use try with resource which would automatically handle the closing of connections for you. If you are not in a position to change the Dao interface, then it is a good idea to write a layer between the Dao and the business layer.
What is the best place to put PreparedStatement initialization, when i want to use it for all instances of given class?
My solution is so far to create static methods for opening and closing, but i don't find it quite the right choice:
class Person {
protected static PreparedStatement stmt1;
protected static PreparedStatement stmt2;
protected static void initStatements(Connection conn) {
stmt1 = conn.PrepareStatement("select job_id from persons where person_id=:person_id");
stmt2 = conn.PrepareStatement("update persons set job_id=:job_id where person_id=:person_id");
}
protected static void closeStatements() {
stmt1.close();
stmt2.close();
}
public void increaseSalary() {
stmt1.execute(); // just a example
stmt2.execute();
}
}
void main {
// create prepared statements
Person.initStatements(conn);
// for each person, increase do some action which require sql connection
for (Person p : getAllPersons()) {
p.increaseSalary();
}
// close statements
Person.closeStatements();
}
Isn't there any other way how to use PreparedStatements inside multiple instances of class?
Will person be your domain logic class? Then I recommend not to put the data access methods and PreparedStatements in there but in a separate data access object.
Will the DAO methods be called asynchronously for example in a web application? Then I recommend to not reuse either PreparedStatements or Connections between those calls at all. For Connections I'd use a Connection pool.
More on reusing PreparedStatements:
Reusing a PreparedStatement multiple times
Usually it is better to use a ConnectionSurvivalPack and give this to everyone involved:
Class SurvivalPack {
private Connection connection;
private PreparedStatement st1;
// add constructor and appropriate getter/setter
// getter for PreparedStatements could create statements on demand
void close(){
st1.close();
con.close();
}
}
void main(...){
SurvivalPack survivalPack = new SurvivalPack(conn);
for(Person p: getAllPersons()){
p.increaseSalary(survivalPack);
}
survivalPack.close();
}
Pros:
Multithreading is no problem, since the resources are not shared between threads.
All database resources are bundled in one place. This makes management of resources easier and more consistent.
It is much easier to follow the flow of the code and the involved resources because no side effects from semiglobal variables can happen.
I am trying to create a simple app with a SQLite database. I chose to use the SQLiteJDBC driver.
The code below is taken from the above website.
My question is about the line after public static void main...
It reads: Class.forName("org.sqlite.JDBC");
My question is, what does this line mean? And what does it do? It doesn't seem to be connected to the rest of the code. Class.forName() should return a class, but the line seems to stand alone inside the body. Whatever it returns isn't used by another part of the code, that I can see.
Please help clarify this. Thanks in advance.
public class Test {
public static void main(String[] args) throws Exception {
Class.forName("org.sqlite.JDBC");
Connection conn =
DriverManager.getConnection("jdbc:sqlite:test.db");
Statement stat = conn.createStatement();
stat.executeUpdate("drop table if exists people;");
stat.executeUpdate("create table people (name, occupation);");
PreparedStatement prep = conn.prepareStatement(
"insert into people values (?, ?);");
prep.setString(1, "Gandhi");
prep.setString(2, "politics");
prep.addBatch();
prep.setString(1, "Turing");
prep.setString(2, "computers");
prep.addBatch();
conn.setAutoCommit(false);
prep.executeBatch();
conn.setAutoCommit(true);
ResultSet rs = stat.executeQuery("select * from people;");
while (rs.next()) {
System.out.println("name = " + rs.getString("name"));
System.out.println("job = " + rs.getString("occupation"));
}
rs.close();
conn.close();
}
}
It loads a class dynamically. What does Class.forname method do? is a good article about it and it also explains why database drivers needs it:
Let's see why you need Class.forName() to load a driver into memory. All JDBC Drivers have a static block that registers itself with DriverManager and DriverManager has static an initializer only.
The MySQL JDBC Driver has a static initializer looks like this:
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
JVM executes the static block and the Driver registers itself with the DriverManager.
You need a database connection to manipulate the database. In order to create the connection to the database, the DriverManager class has to know which database driver you want to use. It does that by iterating over the array (internally a Vector) of drivers that have registered with it and calls the acceptsURL(url) method on each driver in the array, effectively asking the driver to tell it whether or not it can handle the JDBC URL.
The Class.forName statement is making sure that the class that implements the JDBC driver for sqlite3 is loaded and registered with the JDBC factory mechanism.
When you call DriverManager.getConnection(), it looks for classes that are registered and claim to be able to handle the connection string. If no such class is found, it can't create the connection.
I'm trying to generate some sql files in my java application.
The application will not execute any sql statements, just generate a file with sql statements and save it.
I'd like to use the java.sql.PreparedStatement to create my statements so that i don't have to validate every string etc. with my own methods.
Is there a way to use the PreparedStatement without the calling java.sql.Connection.prepareStatement(String) function, because I don't have a java.sql.Connection?
Take a look at this Java library: http://openhms.sourceforge.net/sqlbuilder/
I'm guessing that until you've got a sql connection, the parser won't know what rules to apply. I'm guessing that it's actually the SQL driver or even server that's compiling the sql statement.
Assuming your sql is simple enough, then how about using a cheap connection, like, say a sqlite connection.
SQLite will create a new database on the fly if the database you're attempting to connect to does not exist.
public Connection connectToDatabase() {
// connect to the database (creates new if not found)
try {
Class.forName("org.sqlite.JDBC");
conn = DriverManager.getConnection("jdbc:sqlite:mydatabase.db");
// initialise the tables if necessary
this.createDatabase(conn);
}
catch (java.lang.ClassNotFoundException e) {
System.out.println(e.getMessage());
}
catch (java.sql.SQLException e) {
System.out.println(e.getMessage());
}
return conn;
}
Not really. Preparing a statement in most cases means that it will be compiled by DBMS which is "hard" without connection.
http://java.sun.com/docs/books/tutorial/jdbc/basics/prepared.html
This is a dastardly devious problem, thankfully it's pretty easy to cope with:
public class PreparedStatementBuilder
{
private String sql; // the sql to be executed
public PreparedStatementBuilder(final String sql) { this.sql = sql; }
protected void preparePrepared(final PreparedStatement preparedStatement)
throws SQLException
{
// this virtual method lets us declare how, when we do generate our
// PreparedStatement, we want it to be setup.
// note that at the time this method is overridden, the
// PreparedStatement has not yet been created.
}
public PreparedStatement build(final Connection conn)
throws SQLException
{
// fetch the PreparedStatement
final PreparedStatement returnable = conn.prepareStatement(sql);
// perform our setup directives
preparePrepared(returnable);
return returnable;
}
}
To use, just write an anonymous class that overrides void preparePrepared(PreparedStatement):
final String sql = "SELECT * FROM FOO WHERE USER = ?";
PreparedStatementBuilder psBuilder = new PreparedStatementBuilder(sql){
#Override
protected void preparePrepared(PreparedStatement preparedStatement)
throws SQLException
{
preparedStatement.setString(1, "randal");
}};
return obtainResultSet(psBuilder);
Presto! You now have a way to work with a PreparedStatement without yet having built it. Here's an example showing the minimal boilerplate you'd otherwise have to copy paste to kingdom come, every time you wanted to write a different statement:
public ResultSet obtainResultSet(final PreparedStatementBuilder builder)
throws SQLException {
final Connection conn = this.connectionSource.getConnection();
try
{
// your "virtual" preparePrepared is called here, doing the work
// you've laid out for your PreparedStatement now that it's time
// to actually build it.
return builder.build(conn).executeQuery();
}
finally
{
try { conn.close(); }
catch (SQLException e) { log.error("f7u12!", e); }
}
}
You really really don't want to be copy pasting that everywhere, do you?
Try implementing PreparedStatement.
Example : class YourOwnClass implements PreparedStatement {
// 1. Do implement all the methods ,
2. Get the minimal logic to implement from OraclePreparedStatement(classes12.jar) or
sun.jdbc.odbc.JdbcOdbcCallableStatement
}