Spring JDBC Tutorial
Spring JDBC ist das Thema dieses Tutorials. Datenbanken sind ein integraler Bestandteil der meisten Unternehmensanwendungen. Daher ist eine gute Integration mit JDBC in einem Java EE-Framework sehr wichtig.
Spring JDBC
spring jdbc, spring jdbc Beispiel, spring JDBCTemplate, JDBCTemplateDas Spring Framework bietet eine hervorragende Integration mit der JDBC API und stellt die JdbcTemplate Hilfsklasse zur Verfügung, die wir verwenden können, um Boiler-Plate-Code aus unserer Datenbank-Operationslogik wie Öffnen/Schließen von Connection, ResultSet, PreparedStatement usw. zu vermeiden. Lassen Sie uns zuerst einen einfachen Spring JDBC Beispielanwendung anschauen und dann werden wir sehen, wie die JdbcTemplate Klasse uns helfen kann, modulareren Code mit Leichtigkeit zu schreiben, ohne sich Sorgen machen zu müssen, ob Ressourcen richtig geschlossen werden oder nicht. Spring Tool Suite zur Entwicklung von Spring-basierten Anwendungen ist sehr hilfreich, daher werden wir STS verwenden, um unsere Spring JDBC-Anwendung zu erstellen. Unsere endgültige Projektstruktur wird wie das folgende Bild aussehen.
Erstellen Sie ein einfaches Spring Maven-Projekt aus dem STS-Menü, Sie können einen beliebigen Namen wählen oder bei meinem Projektnamen SpringJDBCExample bleiben.
Spring JDBC Abhängigkeiten
Zunächst müssen wir Spring JDBC und Datenbanktreiber in die pom.xml-Datei des Maven-Projekts einbeziehen. Meine endgültige pom.xml-Datei sieht wie unten aus.
<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>
Spring JDBC Beispiel – Datenbank Setup
Lassen Sie uns eine einfache Tabelle erstellen, die wir in unserer Anwendung für das Beispiel von CRUD-Operationen verwenden werden.
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;
Spring JDBC Beispiel – Modelklasse
Wir werden das DAO-Muster für JDBC-Operationen verwenden, also lassen Sie uns ein Java-Bean erstellen, das unsere Employee-Tabelle modelliert.
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+"}";
}
}
Der größte Teil wird automatisch von STS generiert, jedoch habe ich die Spring Framework-Version auf die neueste Version 4.0.2.RELEASE aktualisiert. Außerdem haben wir die erforderlichen Artefakte spring-jdbc und mysql-connector-java hinzugefügt. Das erste enthält die Spring JDBC Supportklassen und das zweite ist der Datenbanktreiber. Ich verwende für unsere Testzwecke eine MySQL-Datenbank, daher habe ich MySQL JConnector jar-Abhängigkeiten hinzugefügt. Wenn Sie eine andere RDBMS verwenden, sollten Sie die entsprechenden Änderungen in den Abhängigkeiten vornehmen.
Spring JDBC Beispiel – DAO Schnittstelle und Implementierung
Für das DAO-Muster werden wir zunächst eine Schnittstelle erstellen, die alle Operationen deklariert, die wir implementieren wollen.
package com.journaldev.spring.jdbc.dao;
import java.util.List;
import com.journaldev.spring.jdbc.model.Employee;
//CRUD operations
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);
//Get All
public List<Employee> 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 getAll() {
String query = "select id, name, role from Employee";
List empList = new ArrayList();
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;
}
}
Die Implementierung der CRUD-Operationen ist einfach zu verstehen. Wenn Sie mehr über DataSource erfahren möchten, lesen Sie bitte das JDBC DataSource Beispiel.
Spring JDBC Beispiel – Bean-Konfiguration
Die Klassen des Spring JDBC-Frameworks kommen ins Spiel, wenn wir eine Spring Bean-Konfigurationsdatei erstellen und die Beans definieren. Wir werden die DataSource in der Spring Bean-Kontextdatei erstellen und sie unserer DAO-Implementierungsklasse zuweisen. Meine Spring Bean-Konfigurationsdatei sieht wie folgt aus.
<?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>
Zuerst erstellen wir ein DataSource-Objekt der Klasse DriverManagerDataSource. Diese Klasse bietet die grundlegende Implementierung von DataSource, die wir verwenden können. Wir übergeben die MySQL-Datenbank-URL, den Benutzernamen und das Passwort als Eigenschaften an das DataSource-Bean. Das dataSource-Bean wird dem EmployeeDAOImpl-Bean zugewiesen, wodurch unsere Spring JDBC-Implementierung vorbereitet wird. Diese Implementierung ist lose gekoppelt, und wenn wir zu einer anderen Implementierung wechseln oder zu einem anderen Datenbankserver umziehen möchten, müssen wir nur die entsprechenden Änderungen in den Bean-Konfigurationen vornehmen. Dies ist einer der großen Vorteile des Spring JDBC-Frameworks.
Spring JDBC Testklasse
Lassen Sie uns eine einfache Testklasse schreiben, um sicherzustellen, dass alles einwandfrei funktioniert.
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) {
//Get the Spring Context
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");
//Get the EmployeeDAO Bean
EmployeeDAO employeeDAO = ctx.getBean("employeeDAO", EmployeeDAO.class);
//Run some tests for JDBC CRUD operations
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);
//Get All
List empList = employeeDAO.getAll();
System.out.println(empList);
//Delete
employeeDAO.deleteById(rand);
//Close Spring Context
ctx.close();
System.out.println("DONE");
}
}
Ich verwende die Random-Klasse, um eine zufällige Nummer für die Mitarbeiter-ID zu generieren. Wenn wir das obige Programm ausführen, erhalten wir die folgende Ausgabe.
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
Spring JdbcTemplate Beispiel
Wenn Sie sich die DAO-Implementierungsklasse anschauen, gibt es viel Boiler-Plate-Code, bei dem wir Connection, PreparedStatements und ResultSet öffnen und schließen. Dies kann zu Ressourcenlecks führen, wenn jemand vergisst, die Ressourcen richtig zu schließen. Wir können die Klasse org.springframework.jdbc.core.JdbcTemplate verwenden, um diese Fehler zu vermeiden. Spring JdbcTemplate ist die zentrale Klasse im Spring JDBC-Core-Paket und bietet viele Methoden, um Abfragen auszuführen und ResultSet automatisch zu parsen, um das Objekt oder eine Liste von Objekten zu erhalten. Alles, was wir tun müssen, ist, die Argumente als Objektarray bereitzustellen und Callback-Schnittstellen wie PreparedStatementSetter und RowMapper zu implementieren, um Argumente zu mappen oder ResultSet-Daten in Bean-Objekte umzuwandeln. Lassen Sie uns eine andere Implementierung von EmployeeDAO betrachten, bei der wir die Spring JdbcTemplate-Klasse verwenden, um verschiedene Arten von Abfragen auszuführen.
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);
//using RowMapper anonymous class, we can create a separate RowMapper for reuse
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<Map<String,Object>> empRows = jdbcTemplate.queryForList(query);
for(Map<String,Object> 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;
}
}
Wichtige Punkte über Spring JdbcTemplate
- Verwendung eines Object-Arrays, um PreparedStatement-Argumente zu übergeben. Wir könnten auch die PreparedStatementSetter-Implementierung verwenden, aber die Verwendung eines Object-Arrays scheint einfacher zu sein.
- Kein Code zum Öffnen und Schließen von Verbindungen, Statements oder ResultSets. All das wird intern von der Spring JdbcTemplate-Klasse gehandhabt.
- Implementierung einer anonymen RowMapper-Klasse, um die ResultSet-Daten in der queryForObject()-Methode in ein Employee-Bean-Objekt zu mappen.
- Die Methode queryForList() gibt eine Liste von Maps zurück, wobei jede Map die Zeilendaten enthält, die mit dem Schlüssel als Spaltenname und dem Wert aus der Datenbankzeile, die den Kriterien entspricht, gemappt sind.
Um die Spring JdbcTemplate-Implementierung zu verwenden, müssen wir lediglich die employeeDAO-Klasse in der Spring Bean-Konfigurationsdatei ändern, wie unten gezeigt.
<bean id="employeeDAO" class="com.journaldev.spring.jdbc.dao.EmployeeDAOJDBCTemplateImpl">
<property name="dataSource" ref="dataSource" />
</bean>
Wenn Sie die Hauptklasse ausführen, wird die Ausgabe der Spring JdbcTemplate-Implementierung ähnlich der oben mit der normalen JDBC-Implementierung gesehenen sein. Das ist alles für das Spring JDBC-Beispiel-Tutorial.