Spring JDBC é o tema deste tutorial. Bancos de dados são parte integrante da maioria das Aplicações Empresariais. Portanto, quando se trata de um framework Java EE, ter uma boa integração com JDBC é muito importante.
Spring JDBC
O Framework Spring oferece uma excelente integração com a API JDBC e fornece a classe de utilitário
JdbcTemplate
que podemos usar para evitar código boilerplate em nossa lógica de operações de banco de dados, como Abrir/Fechar Conexão, ResultSet, PreparedStatement etc. Vamos primeiro ver um exemplo simples de aplicação Spring JDBC e então veremos como a classe JdbcTemplate pode nos ajudar a escrever código modular com facilidade, sem nos preocuparmos se os recursos estão sendo fechados corretamente ou não. A Spring Tool Suite para desenvolver aplicações baseadas em Spring é muito útil, então usaremos o STS para criar nossa aplicação Spring JDBC. Nossa estrutura de projeto final ficará como na imagem abaixo. Crie um Projeto Maven Spring simples a partir do Menu STS, você pode escolher qualquer nome que desejar ou seguir com o nome do meu projeto como SpringJDBCExample.
Dependências do Spring JDBC
Primeiramente, precisamos incluir o Spring JDBC e os drivers do banco de dados no arquivo pom.xml do projeto Maven. Meu arquivo pom.xml final se parece com abaixo.
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.samples</groupId>
<artifactId>SpringJDBCExample</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<!-- Generic properties -->
<java.version>1.6</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- Spring -->
<spring-framework.version>4.0.2.RELEASE</spring-framework.version>
<!-- Logging -->
<logback.version>1.0.13</logback.version>
<slf4j.version>1.7.5</slf4j.version>
</properties>
<dependencies>
<!-- Spring and Transactions -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<!-- Spring JDBC Support -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<!-- MySQL Driver -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.0.5</version>
</dependency>
<!-- Logging with SLF4J & LogBack -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>
A maioria da parte é gerada automaticamente pelo STS, no entanto, atualizei a versão do Spring Framework para a versão mais recente, 4.0.2.RELEASE. Além disso, adicionamos os artefatos necessários spring-jdbc e mysql-connector-java. O primeiro contém as classes de suporte do Spring JDBC e o segundo é o driver do banco de dados. Estou utilizando o banco de dados MySQL para nossos propósitos de teste, então adicionei as dependências do JConnector do MySQL. Se estiver utilizando outro SGBD, você deve fazer as alterações correspondentes nas dependências.
Exemplo de Spring JDBC – Configuração do Banco de Dados
Vamos criar uma tabela simples que usaremos em nossa aplicação como exemplo de operações CRUD.
CREATE TABLE `Employee` (
`id` int(11) unsigned NOT NULL,
`name` varchar(20) DEFAULT NULL,
`role` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Exemplo de Spring JDBC – Classe de Modelo
Vamos utilizar o padrão DAO para operações JDBC, então vamos criar um bean java que irá modelar nossa tabela de Funcionários.
package com.journaldev.spring.jdbc.model;
public class Employee {
private int id;
private String name;
private String role;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
@Override
public String toString(){
return "{ID="+id+",Name="+name+",Role="+role+"}";
}
}
Exemplo de Spring JDBC – Interface e Implementação do DAO
Para o padrão DAO, primeiro teremos uma interface declarando todas as operações que queremos implementar.
package com.journaldev.spring.jdbc.dao;
import java.util.List;
import com.journaldev.spring.jdbc.model.Employee;
//Operações CRUD
public interface EmployeeDAO {
//Create
public void save(Employee employee);
//Read
public Employee getById(int id);
//Update
public void update(Employee employee);
//Delete
public void deleteById(int id);
//Obter Todos
public List getAll();
}
package com.journaldev.spring.jdbc.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.sql.DataSource;
import com.journaldev.spring.jdbc.model.Employee;
public class EmployeeDAOImpl implements EmployeeDAO {
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public void save(Employee employee) {
String query = "insert into Employee (id, name, role) values (?,?,?)";
Connection con = null;
PreparedStatement ps = null;
try{
con = dataSource.getConnection();
ps = con.prepareStatement(query);
ps.setInt(1, employee.getId());
ps.setString(2, employee.getName());
ps.setString(3, employee.getRole());
int out = ps.executeUpdate();
if(out !=0){
System.out.println("Employee saved with id="+employee.getId());
}else System.out.println("Employee save failed with id="+employee.getId());
}catch(SQLException e){
e.printStackTrace();
}finally{
try {
ps.close();
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
@Override
public Employee getById(int id) {
String query = "select name, role from Employee where id = ?";
Employee emp = null;
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try{
con = dataSource.getConnection();
ps = con.prepareStatement(query);
ps.setInt(1, id);
rs = ps.executeQuery();
if(rs.next()){
emp = new Employee();
emp.setId(id);
emp.setName(rs.getString("name"));
emp.setRole(rs.getString("role"));
System.out.println("Employee Found::"+emp);
}else{
System.out.println("No Employee found with id="+id);
}
}catch(SQLException e){
e.printStackTrace();
}finally{
try {
rs.close();
ps.close();
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return emp;
}
@Override
public void update(Employee employee) {
String query = "update Employee set name=?, role=? where id=?";
Connection con = null;
PreparedStatement ps = null;
try{
con = dataSource.getConnection();
ps = con.prepareStatement(query);
ps.setString(1, employee.getName());
ps.setString(2, employee.getRole());
ps.setInt(3, employee.getId());
int out = ps.executeUpdate();
if(out !=0){
System.out.println("Employee updated with id="+employee.getId());
}else System.out.println("No Employee found with id="+employee.getId());
}catch(SQLException e){
e.printStackTrace();
}finally{
try {
ps.close();
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
@Override
public void deleteById(int id) {
String query = "delete from Employee where id=?";
Connection con = null;
PreparedStatement ps = null;
try{
con = dataSource.getConnection();
ps = con.prepareStatement(query);
ps.setInt(1, id);
int out = ps.executeUpdate();
if(out !=0){
System.out.println("Employee deleted with id="+id);
}else System.out.println("No Employee found with id="+id);
}catch(SQLException e){
e.printStackTrace();
}finally{
try {
ps.close();
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
@Override
public List<Employee> getAll() {
String query = "select id, name, role from Employee";
List<Employee> empList = new ArrayList<Employee>();
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try{
con = dataSource.getConnection();
ps = con.prepareStatement(query);
rs = ps.executeQuery();
while(rs.next()){
Employee emp = new Employee();
emp.setId(rs.getInt("id"));
emp.setName(rs.getString("name"));
emp.setRole(rs.getString("role"));
empList.add(emp);
}
}catch(SQLException e){
e.printStackTrace();
}finally{
try {
rs.close();
ps.close();
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return empList;
}
}
A implementação das operações CRUD é simples de entender. Se você deseja aprender mais sobre DataSource, por favor, leia Exemplo de DataSource JDBC.
Exemplo de JDBC do Spring – Configuração de Beans
Se você olhar todas as classes acima, elas estão usando a API JDBC padrão e não há referência ao framework Spring JDBC. As classes do framework Spring JDBC entram em cena quando criamos o arquivo de configuração de Bean do Spring e definimos os beans. Vamos criar o DataSource no arquivo de contexto de Bean do Spring e definir isso para nossa classe de implementação DAO. Meu arquivo de configuração de Bean do Spring parece com o seguinte.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="employeeDAO" class="com.journaldev.spring.jdbc.dao.EmployeeDAOImpl">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/TestDB" />
<property name="username" value="pankaj" />
<property name="password" value="pankaj123" />
</bean>
</beans>
Primeiramente, estamos criando um objeto DataSource da classe DriverManagerDataSource
. Esta classe fornece a implementação básica do DataSource que podemos utilizar. Estamos passando a URL do banco de dados MySQL, o nome de usuário e a senha como propriedades para o bean DataSource. Novamente, o bean do dataSource é definido para o bean EmployeeDAOImpl
e estamos prontos com nossa implementação Spring JDBC. A implementação é fracamente acoplada e, se quisermos mudar para alguma outra implementação ou migrar para outro servidor de banco de dados, tudo o que precisamos fazer é fazer as alterações correspondentes nas configurações do bean. Esta é uma das principais vantagens fornecidas pelo framework Spring JDBC.
Classe de Teste do Spring JDBC
Vamos escrever uma classe de teste simples para garantir que tudo esteja funcionando corretamente.
package com.journaldev.spring.jdbc.main;
import java.util.List;
import java.util.Random;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.journaldev.spring.jdbc.dao.EmployeeDAO;
import com.journaldev.spring.jdbc.model.Employee;
public class SpringMain {
public static void main(String[] args) {
//Obter o Contexto do Spring
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");
//Obter o Bean EmployeeDAO
EmployeeDAO employeeDAO = ctx.getBean("employeeDAO", EmployeeDAO.class);
//Executar alguns testes para operações CRUD do JDBC
Employee emp = new Employee();
int rand = new Random().nextInt(1000);
emp.setId(rand);
emp.setName("Pankaj");
emp.setRole("Java Developer");
//Create
employeeDAO.save(emp);
//Read
Employee emp1 = employeeDAO.getById(rand);
System.out.println("Employee Retrieved::"+emp1);
//Update
emp.setRole("CEO");
employeeDAO.update(emp);
//Obter Todos
List empList = employeeDAO.getAll();
System.out.println(empList);
//Delete
employeeDAO.deleteById(rand);
//Fechar o Contexto do Spring
ctx.close();
System.out.println("DONE");
}
}
I am using Random Class to generate random number for employee id. When we run above program, we get following output.
Mar 25, 2014 12:54:18 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@4b9af9a9: startup date [Tue Mar 25 12:54:18 PDT 2014]; root of context hierarchy
Mar 25, 2014 12:54:18 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [spring.xml]
Mar 25, 2014 12:54:19 PM org.springframework.jdbc.datasource.DriverManagerDataSource setDriverClassName
INFO: Loaded JDBC driver: com.mysql.jdbc.Driver
Employee saved with id=726
Employee Found::{ID=726,Name=Pankaj,Role=Java Developer}
Employee Retrieved::{ID=726,Name=Pankaj,Role=Java Developer}
Employee updated with id=726
[{ID=726,Name=Pankaj,Role=CEO}]
Employee deleted with id=726
Mar 25, 2014 12:54:19 PM org.springframework.context.support.ClassPathXmlApplicationContext doClose
INFO: Closing org.springframework.context.support.ClassPathXmlApplicationContext@4b9af9a9: startup date [Tue Mar 25 12:54:18 PDT 2014]; root of context hierarchy
DONE
Exemplo de Spring JdbcTemplate
Se você olhar a classe de implementação do DAO, há muitos códigos padrão onde estamos abrindo e fechando Connection, PreparedStatements e ResultSet. Isso pode levar a vazamento de recursos se alguém esquecer de fechar os recursos corretamente. Podemos usar a classe org.springframework.jdbc.core.JdbcTemplate
para evitar esses erros. O Spring JdbcTemplate é a classe central no pacote core do Spring JDBC e fornece muitos métodos para executar consultas e automaticamente analisar o ResultSet para obter o objeto ou lista de objetos. Tudo o que precisamos fazer é fornecer os argumentos como um array de objetos e implementar interfaces de Callback, como PreparedStatementSetter
e RowMapper
, para mapear argumentos ou converter dados do ResultSet em objetos de bean. Vamos dar uma olhada em outra implementação do EmployeeDAO onde usaremos a classe Spring JdbcTemplate para executar diferentes tipos de consultas.
package com.journaldev.spring.jdbc.dao;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import com.journaldev.spring.jdbc.model.Employee;
public class EmployeeDAOJDBCTemplateImpl implements EmployeeDAO {
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public void save(Employee employee) {
String query = "insert into Employee (id, name, role) values (?,?,?)";
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
Object[] args = new Object[] {employee.getId(), employee.getName(), employee.getRole()};
int out = jdbcTemplate.update(query, args);
if(out !=0){
System.out.println("Employee saved with id="+employee.getId());
}else System.out.println("Employee save failed with id="+employee.getId());
}
@Override
public Employee getById(int id) {
String query = "select id, name, role from Employee where id = ?";
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
// usando uma classe anônima RowMapper, podemos criar um RowMapper separado para reutilização
Employee emp = jdbcTemplate.queryForObject(query, new Object[]{id}, new RowMapper(){
@Override
public Employee mapRow(ResultSet rs, int rowNum)
throws SQLException {
Employee emp = new Employee();
emp.setId(rs.getInt("id"));
emp.setName(rs.getString("name"));
emp.setRole(rs.getString("role"));
return emp;
}});
return emp;
}
@Override
public void update(Employee employee) {
String query = "update Employee set name=?, role=? where id=?";
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
Object[] args = new Object[] {employee.getName(), employee.getRole(), employee.getId()};
int out = jdbcTemplate.update(query, args);
if(out !=0){
System.out.println("Employee updated with id="+employee.getId());
}else System.out.println("No Employee found with id="+employee.getId());
}
@Override
public void deleteById(int id) {
String query = "delete from Employee where id=?";
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
int out = jdbcTemplate.update(query, id);
if(out !=0){
System.out.println("Employee deleted with id="+id);
}else System.out.println("No Employee found with id="+id);
}
@Override
public List getAll() {
String query = "select id, name, role from Employee";
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
List empList = new ArrayList();
List
Pontos importantes para observar no código acima para o Spring JdbcTemplate são:
- Uso de um array de objetos para passar argumentos do PreparedStatement, também poderíamos usar a implementação do PreparedStatementSetter, mas passar um array de objetos parece mais fácil de usar.
- Sem código relacionado à abertura e fechamento de conexões, declarações ou conjunto de resultados. Tudo isso é tratado internamente pela classe Spring JdbcTemplate.
- Implementação de uma classe anônima RowMapper para mapear os dados do ResultSet para o objeto Employee em queryForObject() método.
- queryForList() método retorna uma lista de Mapas, onde o Mapa contém os dados da linha mapeados com a chave como o nome da coluna e o valor da linha do banco de dados correspondente aos critérios.
Para usar a implementação do Spring JdbcTemplate, tudo o que precisamos fazer é alterar a classe employeeDAO no arquivo de configuração do Spring Bean, conforme mostrado abaixo.
<bean id="employeeDAO" class="com.journaldev.spring.jdbc.dao.EmployeeDAOJDBCTemplateImpl">
<property name="dataSource" ref="dataSource" />
</bean>
Quando você executar a classe principal, a saída da implementação do Spring JdbcTemplate será semelhante à vista acima com a implementação normal do JDBC. Isso é tudo para o tutorial de exemplo do Spring JDBC, faça o download do projeto de exemplo a partir do link abaixo e brinque com ele para aprender mais.
Source:
https://www.digitalocean.com/community/tutorials/spring-jdbc-example