Spring JDBC Beispiel

Frühling JDBC ist das Thema dieses Tutorials. Datenbanken sind ein wesentlicher Bestandteil der meisten Unternehmensanwendungen. Daher ist es bei einem Java EE-Framework sehr wichtig, eine gute Integration mit JDBC zu haben.

Spring JDBC

Das Spring Framework bietet eine ausgezeichnete Integration mit der JDBC-API und stellt die Hilfsklasse JdbcTemplate bereit, die wir verwenden können, um boilerplate Code aus unserer Datenbankbetriebslogik wie das Öffnen/Schließen einer Verbindung, ResultSet, PreparedStatement usw. zu vermeiden. Lassen Sie uns zunächst ein einfaches Beispiel für eine Spring JDBC-Anwendung betrachten und dann sehen, wie uns die Klasse JdbcTemplate dabei helfen kann, modulareren Code mit Leichtigkeit zu schreiben, ohne uns Gedanken darüber machen zu müssen, ob Ressourcen ordnungsgemäß geschlossen werden oder nicht. Das Spring Tool Suite zur Entwicklung von auf Spring basierenden Anwendungen ist sehr hilfreich, daher werden wir STS verwenden, um unsere Spring JDBC-Anwendung zu erstellen. Die endgültige Projektstruktur wird wie auf dem folgenden 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 aufnehmen. Meine endgültige pom.xml-Datei sieht wie folgt 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>

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. Der erste enthält die Spring JDBC-Unterstützungsklassen und der zweite ist der Datenbanktreiber. Ich verwende MySQL-Datenbank zu Testzwecken, daher habe ich MySQL JConnector-Jar-Abhängigkeiten hinzugefügt. Wenn Sie ein anderes RDBMS verwenden, sollten Sie entsprechende Änderungen an den Abhängigkeiten vornehmen.

Spring JDBC-Beispiel – Datenbank Setup

Erstellen wir eine einfache Tabelle, die wir in unserer Anwendung für 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 – Model-Klasse

Wir werden das DAO-Muster für JDBC-Operationen verwenden, also erstellen wir eine Java-Bean, die 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+"}";
	}
}

Spring JDBC-Beispiel – DAO-Schnittstelle und Implementierung

Für das DAO-Muster werden wir zuerst eine Schnittstelle haben, die alle Operationen deklariert, die wir implementieren möchten.

package com.journaldev.spring.jdbc.dao;

import java.util.List;

import com.journaldev.spring.jdbc.model.Employee;

//CRUD-Operationen
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);
	//Alle abrufen
	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;
	}

}

Die Implementierung der CRUD-Operationen ist einfach zu verstehen. Wenn Sie mehr über DataSource erfahren möchten, lesen Sie bitte JDBC DataSource Beispiel.

Spring JDBC Beispiel – Bean-Konfiguration

Wenn Sie sich alle oben genannten Klassen ansehen, verwenden sie alle die standardmäßige JDBC-API und es gibt keinen Verweis auf das Spring JDBC-Framework. Spring JDBC-Framework-Klassen 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>

Zunächst 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 erneut auf das EmployeeDAOImpl-Bean gesetzt, und wir sind bereit mit unserer Spring JDBC-Implementierung. Die Implementierung ist lose gekoppelt, und wenn wir zu einer anderen Implementierung wechseln oder zu einem anderen Datenbankserver wechseln möchten, müssen wir lediglich entsprechende Änderungen in den Bean-Konfigurationen vornehmen. Dies ist einer der Hauptvorteile des Spring JDBC-Frameworks.

Spring JDBC-Testklasse

Schreiben wir eine einfache Testklasse, um sicherzustellen, dass alles 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) {
		// Holen des Spring-Kontexts
		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");
		
		// Holen des EmployeeDAO-Beans
		EmployeeDAO employeeDAO = ctx.getBean("employeeDAO", EmployeeDAO.class);
		
		// Führen Sie einige Tests für JDBC-CRUD-Operationen aus
		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);
		
		// Alles abrufen
		List empList = employeeDAO.getAll();
		System.out.println(empList);
		
		//Delete
		employeeDAO.deleteById(rand);
		
		// Spring-Kontext schließen
		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

Spring JdbcTemplate Beispiel

Wenn Sie sich die DAO-Implementierungsklasse ansehen, gibt es viel Boilerplate-Code, bei dem wir Connections, PreparedStatements und ResultSet öffnen und schließen. Dies kann zu Ressourcenlecks führen, wenn jemand vergisst, die Ressourcen ordnungsgemäß 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-Kernpaket und bietet viele Methoden zum Ausführen von Abfragen und zum automatischen Parsen von ResultSet, um das Objekt oder die Liste von Objekten zu erhalten. Alles, was wir tun müssen, ist, die Argumente als Objektarray bereitzustellen und Callback-Schnittstellen wie PreparedStatementSetter und RowMapper für die Zuordnung von Argumenten oder die Konvertierung von ResultSet-Daten in Bean-Objekte zu implementieren. Schauen wir uns eine andere Implementierung von EmployeeDAO an, 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);
		
		// Mit RowMapper Anonymous Class können wir einen separaten RowMapper für die Wiederverwendung erstellen
		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;
	}

}

Wichtige Punkte, die im obigen Code für Spring JdbcTemplate zu beachten sind:

  • Verwendung eines Objektarrays, um PreparedStatement-Argumente zu übergeben. Wir könnten auch eine Implementierung von PreparedStatementSetter verwenden, aber die Verwendung eines Objektarrays scheint einfacher.
  • Kein Code in Bezug auf das Öffnen und Schließen von Verbindungen, Anweisungen oder ResultSets. All das wird intern von der Spring JdbcTemplate-Klasse behandelt.
  • Implementierung der RowMapper Anonymous Class zum Zuordnen der ResultSet-Daten zum Employee-Bean-Objekt in der Methode queryForObject().
  • queryForList()-Methode gibt eine Liste von Maps zurück, wobei jede Map die Zeilendaten mit dem Spaltennamen als Schlüssel und dem Wert aus der Datenbankzeile enthält, die den Kriterien entspricht.

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 wie bei der normalen JDBC-Implementierung sein. Das ist alles für das Beispiel des Spring JDBC. Laden Sie das Beispielsprojekt über den untenstehenden Link herunter und experimentieren Sie damit, um mehr zu erfahren.

Spring JDBC-Projekt herunterladen

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