Pages

Saturday, July 31, 2010

Spring - JdbcTemplate Example


Spring provides a simplification in handling database access with the Spring JDBC Template.


The Spring JDBC Template has the following advantages compared with standard JDBC.

  • The JdbcTemplate class is the central class in the JDBC core package. 
  • The Spring JDBC template allows to clean-up the resources automatically, It simplifies the use of JDBC since it handles the creation and release of resources. This helps to avoid common errors such as forgetting to always close the connection
  • The Spring JDBC template converts the standard JDBC SQLExceptions into RuntimeExceptions. This allows the programmer to react more flexible to the errors. The Spring JDBC template converts also the vendor specific error messages into better understandable error messages.
  • The Spring JDBC template offers several ways to query the database. queryForList() returns a list of HashMaps. The name of the column is the key in the hashmap for the values in the table.
  • More convenient is the usage of ResultSetExtractor or RowMapper which allows to translates the SQL result direct into an object (ResultSetExtractor) or a list of objects (RowMapper). Both these methods will be demonstrated in the coding.
In Spring framework, the JdbcTemplate and JdbcDaoSupport classes are used to simplify the overall database operation processes. The last tutorial, Spring + Jdbc example will be reuse to compare the different between a project before and after JdbcTemplate support.

No JdbcTemplate


In the last example (Spring-Jdbc Example), you need to create many redundant codes (create connection , close the connection , handle the exception) in all the DAO persist methods – insert, update and delete. It’s not efficient, ugly, error prone and tedious.


private DataSource dataSource;
 public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public void insert(Customer customer){
String sql = "INSERT INTO CUSTOMER " +
"(ID, NAME, AGE) VALUES (?, ?, ?)";
Connection conn = null;
  try {
conn = dataSource.getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, customer.getCustId());
ps.setString(2, customer.getName());
ps.setInt(3, customer.getAge());
ps.executeUpdate();
ps.close();
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {}
}
}
}

Use JdbcTemplate

By extended the JdbcDaoSupport, set the datasource and JdbcTemplate in your class is no longer required, you just need to wire the datasource into JdbcCustomerDAO. The JdbcDaoSupport will handle it, and you can get the JdbcTemplate by using a getJdbcTemplate() method.


public class JdbcCustomerDAO extends JdbcDaoSupport implements CustomerDAO
{
//no need to set datasource here
   public void insert(Customer customer){
String sql = "INSERT INTO CUSTOMER (ID, NAME, AGE) VALUES (?, ?, ?)";
getJdbcTemplate().update(sql, new Object[] { customer.getCustId(),
customer.getName(),customer.getAge()  
});
  }

Conclusion
 In Spring JDBC programming, It’s always recommend to use JdbcTemplate and JdbcDaoSupport to simplify the overall processes and make your code more reusable.

If you want to see the output, please refer previous example (Spring -Jdbc Example) and copy the above JdbcCustomerDAO and paste it in the previous example.

Spring - JDBC Example

To run the below example you need below jar files in your class path
  • derbyclient.jar
  • spring-dao.jar
  • spring-jdbc.jar


Customer Table
CREATE TABLE `customer` (
  `ID` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `NAME` varchar(100) NOT NULL,
  `AGE` int(10) UNSIGNED NOT NULL,
  PRIMARY KEY (`CUST_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;


Customer.java
Add a customer model to store the customer’s data.

package com;
public class Customer {
private int custId;
private String name;
private int age;
public Customer(int custId, String name, int age) {
super();
this.custId = custId;
this.name = name;
this.age = age;
}
/**
* @return the custId
*/
public int getCustId() {
return custId;
}
/**
* @param custId the custId to set
*/
public void setCustId(int custId) {
this.custId = custId;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the age
*/
public int getAge() {
return age;
}
/**
* @param age the age to set
*/
public void setAge(int age) {
this.age = age;
}
}
ICustomerDAO.java
Add dao layer for the Customer.

package com;
public interface ICustomerDAO {
public void insert(Customer customer);
public Customer findByCustomerId(int custId);
}

JdbcCustomerDAOImpl.java
DAO JDBC implementation with a simple insert and select statement.

package com;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.sql.DataSource;
public class JdbcCustomerDAOImpl implements ICustomerDAO {
private DataSource dataSource;
 public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public void insert(Customer customer){
  String sql = "INSERT INTO CUSTOMER (ID, NAME, AGE) VALUES (?, ?, ?)";
Connection conn = null;
  try {
conn = dataSource.getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, customer.getCustId());
ps.setString(2, customer.getName());
ps.setInt(3, customer.getAge());
ps.executeUpdate();
ps.close();
  } catch (SQLException e) {
throw new RuntimeException(e);
  } finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {}
}
}
}
  public Customer findByCustomerId(int custId){
  String sql = "SELECT * FROM CUSTOMER WHERE ID = ?";
  Connection conn = null;
  try {
conn = dataSource.getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, custId);
Customer customer = null;
ResultSet rs = ps.executeQuery();
if (rs.next()) {
customer = new Customer(
rs.getInt("ID"),
rs.getString("NAME"), 
rs.getInt("Age")
);
}
rs.close();
ps.close();
return customer;
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {}
}
}
}
}

applicationContext.xml
Create the Spring bean configuration file for customerDAO and datasource.

<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  <property name="location">
<value&gt;ApplicationProperties.properties</value>
</property>
</bean>

<bean id="customerDAO" class="com.JdbcCustomerDAOImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>

<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
</beans>

ApplicationProperties.properties

jdbc.driverClassName=org.apache.derby.jdbc.ClientDriver
jdbc.url=jdbc:derby://localhost:1527/myeclipse
jdbc.username=myblog
jdbc.password=myblog

Test.java
package com;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
ApplicationContext context = new ClassPathXmlApplicationContext("/applicationContext.xml");
         ICustomerDAO customerDAO = (ICustomerDAO) context.getBean("customerDAO");
        Customer customer = new Customer(1, "Vardhan",27);
        customerDAO.insert(customer);
        Customer customer1 = customerDAO.findByCustomerId(2);
        System.out.println(" ::: Customer Record From DataBase ::: ");
        System.out.println(" Customer ID ::: "+customer1.getCustId());
        System.out.println(" Customer Name ::: "+customer1.getName());
        System.out.println(" Customer Age ::: "+customer1.getAge());
}
}

OutPut
 ::: Customer Record From DataBase ::: 
 Customer ID ::: 1
 Customer Name ::: Vardhan
 Customer Age ::: 27



Spring – PropertyPlaceholderConfigurer example

Often times, most Spring developers just put the deployment details (database details, log file path) in the bean configuration file as following :


<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.apache.derby.jdbc.ClientDriver" />
<property name="url" value="jdbc:derby://localhost:1527/myeclipse" />
<property name="username" value="classiccars" />
<property name="password" value="classiccars" />
</bean>


In a corporate environment, the deployment detail is usually only can ‘touch’ by your system or database administrator, they just refuse to access your bean configuration file instead of request a new separate file for the deployment configuration.
In Spring, you can use PropertyPlaceholderConfigurer class to externalize the deployment details into a properties file, and access from bean configuration file via a special format – ${variable}.
To run the below example you need below jar files in your class path
  • derbyclient.jar
  • spring-dao.jar
  • spring-jdbc.jar

ApplicationProperties.properties
Create a properties file (ApplicationProperties.properties) and include your deployment details, put it into your project class path.
jdbc.driverClassName=org.apache.derby.jdbc.ClientDriver
jdbc.url=jdbc:derby://localhost:1527/myeclipse
jdbc.username=classiccars
jdbc.password=classiccars
applicationContext.xml
Declare PropertyPlaceholderConfigurer in bean configuration file and map to the ‘ApplicationProperties.properties’ properties file you created just now.
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  <property name="location">
<value>ApplicationProperties.properties</value>
</property>
</bean>
<bean id="customerDAO" class="com.SimpleJdbcCustomerDAO">
  <property name="dataSource" ref="dataSource" />
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
</beans>
SimpleJdbcCustomerDAO.java
package com;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
public class SimpleJdbcCustomerDAO {
private DriverManagerDataSource dataSource;
/**
* @return the dataSource
*/
public DriverManagerDataSource getDataSource() {
return dataSource;
}
/**
* @param dataSource the dataSource to set
*/
public void setDataSource(DriverManagerDataSource dataSource) {
this.dataSource = dataSource;
}
}

Test.java
package com;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

public class Test {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
ApplicationContext context = new ClassPathXmlApplicationContext("/applicationContext.xml");
SimpleJdbcCustomerDAO customerDao = (SimpleJdbcCustomerDAO)context.getBean("customerDAO");
DriverManagerDataSource dataSource = customerDao.getDataSource();
System.out.println("Driver Class Name :::  "+ dataSource.getDriverClassName());
System.out.println("Url :::  "+ dataSource.getUrl());
System.out.println("User Name :::  "+ dataSource.getUsername());
System.out.println("Password :::  "+ dataSource.getPassword());
}
}

Out Put

Driver Class Name :::  org.apache.derby.jdbc.ClientDriver
Url :::  jdbc:derby://localhost:1527/myeclipse
User Name :::  classiccars
Password :::  classiccars