Exemplo do Spring JDBC

Primavera JDBCSpring JDBC é o é tópico deste tutorial. Bancos o de t dadosó sãop parteico deste tutorial integral. Banc daos maioria das de Ap dadoslica são parteções integral Emp daresariais. mai Portanto,oria quando se trata das de Ap umlicações framework Java Emp EEres,aria teris uma boa. integ Portraanto, quandoção se trata de com um framework Java JDBC é EE muito, importante ter uma. boa integ Springra JDBCção com JDBC é muito importante.

Spring JDBC

O Framework Spring oferece uma excelente integração com a API JDBC e fornece a classe de utilidade JdbcTemplate que podemos usar para evitar códigos repetitivos em nossa lógica de operações de banco de dados, como Abrir/Fechar Conexão, ResultSet, PreparedStatement, etc. Vamos primeiro analisar um exemplo simples de aplicativo Spring JDBC e depois veremos como a classe JdbcTemplate pode nos ajudar a escrever código modular com facilidade, sem se preocupar se os recursos estão sendo fechados corretamente ou não. O Spring Tool Suite, para o desenvolvimento de aplicativos baseados em Spring, é muito útil, então usaremos o STS para criar nosso aplicativo Spring JDBC. A estrutura final do nosso projeto ficará como na imagem abaixo. Crie um Projeto Maven Spring simples no Menu do 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 de banco de dados no arquivo pom.xml do projeto Maven. Meu arquivo pom.xml final parece com o seguinte.

<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 utilizar a versão mais recente, que é a 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 usando o banco de dados MySQL para nossos propósitos de teste, então adicionei as dependências do MySQL JConnector jar. Se estiver usando 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 para 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 usar o padrão DAO para operações JDBC, então vamos criar um bean Java que 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 desejamos 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 JDBC DataSource.

Exemplo de Spring JDBC – Configuração de Bean

Se você observar todas as classes acima, elas estão utilizando 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 configurá-lo para a nossa classe de implementação DAO. Meu arquivo de configuração de Bean do Spring parece com o exemplo abaixo.

<?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>

Primeiro de tudo, estamos criando um objeto DataSource da classe DriverManagerDataSource. Esta classe fornece a implementação básica do DataSource que podemos usar. 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 como o bean EmployeeDAOImpl e estamos prontos com nossa implementação do Spring JDBC. A implementação é fracamente acoplada e se quisermos mudar para alguma outra implementação ou mudar 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 Spring JDBC

Vamos escrever uma classe de teste simples para garantir que tudo esteja funcionando bem.

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 Spring
		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");
		
		// Obter o Bean EmployeeDAO
		EmployeeDAO employeeDAO = ctx.getBean("employeeDAO", EmployeeDAO.class);
		
		// Executar alguns testes para operações JDBC CRUD
		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 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 JdbcTemplate do Spring

Se você olhar para a classe de implementação do DAO, há muito código boilerplate 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 principal do Spring JDBC e fornece muitos métodos para executar consultas e analisar automaticamente 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 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> empRows = jdbcTemplate.queryForList(query);
		
		for(Map empRow : empRows){
			Employee emp = new Employee();
			emp.setId(Integer.parseInt(String.valueOf(empRow.get("id"))));
			emp.setName(String.valueOf(empRow.get("name")));
			emp.setRole(String.valueOf(empRow.get("role")));
			empList.add(emp);
		}
		return empList;
	}

}

Pontos importantes a serem observados no código acima para Spring JdbcTemplate são:

  • Uso de um array de objetos para passar argumentos do PreparedStatement, também poderíamos usar uma implementação de PreparedStatementSetter, mas passar um array de objetos parece mais fácil de usar.
  • Nenhum 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 bean no método queryForObject().
  • O método queryForList() 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 ao critério.

Para usar a implementação 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>

Ao executar a classe principal, a saída da implementação Spring JdbcTemplate será semelhante à vista acima com a implementação normal do JDBC. Isso é tudo para o tutorial de exemplo do Spring JDBC, baixe o projeto de exemplo no link abaixo e explore para aprender mais.

Download do Projeto Spring JDBC

Source:
https://www.digitalocean.com/community/tutorials/spring-jdbc-example