. Spring ORM Beispiel – JPA, Hibernate, Transaktion

Willkommen zum Spring ORM Beispiel Tutorial. Heute werden wir uns ein Spring ORM Beispiel mit Hibernate JPA-Transaktionsverwaltung ansehen. Ich werde Ihnen ein sehr einfaches Beispiel einer eigenständigen Spring-Anwendung mit folgenden Funktionen zeigen.

  • Dependency Injection (@Autowired Annotation)
  • JPA EntityManager (bereitgestellt von Hibernate)
  • Annotationen für transaktionale Methoden (@Transactional Annotation)

Spring ORM Beispiel

Ich habe für das Spring ORM-Beispiel eine In-Memory-Datenbank verwendet, daher ist keine Datenbankeinrichtung erforderlich (aber Sie können sie in der spring.xml-Datenquellenabschnitt problemlos auf eine andere Datenbank ändern). Dies ist eine eigenständige Spring-ORM-Anwendung, um alle Abhängigkeiten zu minimieren (aber Sie können sie durch Konfiguration leicht in ein Webprojekt ändern, wenn Sie sich mit Spring vertraut machen). HINWEIS: Für Spring AOP-basiertes Transaktionsmanagement (ohne @Transactional-Annotation) überprüfen Sie bitte dieses Tutorial: Spring ORM AOP Transaction Management. Das folgende Bild zeigt unser endgültiges Spring-ORM-Beispielprojekt. Lassen Sie uns jeden der Komponenten des Spring-ORM-Beispielprojekts nacheinander durchgehen.

Spring ORM Maven-Abhängigkeiten

Unten befindet sich unsere endgültige pom.xml-Datei mit den Spring-ORM-Abhängigkeiten. Wir haben Spring 4 und Hibernate 4 in unserem Spring-ORM-Beispiel verwendet.

<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>hu.daniel.hari.learn.spring</groupId>
	<artifactId>Tutorial-SpringORMwithTX</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<properties>
		<!-- Generic properties -->
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<java.version>1.7</java.version>

		<!-- SPRING & HIBERNATE / JPA -->
		<spring.version>4.0.0.RELEASE</spring.version>
		<hibernate.version>4.1.9.Final</hibernate.version>

	</properties>

	<dependencies>
		<!-- LOG -->
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.17</version>
		</dependency>

		<!-- Spring -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<!-- JPA Vendor -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-entitymanager</artifactId>
			<version>${hibernate.version}</version>
		</dependency>

		<!-- IN MEMORY Database and JDBC Driver -->
		<dependency>
			<groupId>hsqldb</groupId>
			<artifactId>hsqldb</artifactId>
			<version>1.8.0.7</version>
		</dependency>

	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.1</version>
				<configuration>
					<source>${java.version}</source>
					<target>${java.version}</target>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>
  • Wir benötigen spring-context und spring-orm als Spring-Abhängigkeiten.
  • Wir verwenden hibernate-entitymanager für Hibernate als JPA-Implementierung. hibernate-entitymanager ist abhängig von hibernate-core, deshalb müssen wir hibernate-core nicht explizit in der pom.xml angeben. Es wird automatisch über die Maven-Transitivabhängigkeiten in unser Projekt eingebunden.
  • Wir benötigen auch den JDBC-Treiber als Abhängigkeit für den Datenbankzugriff. Wir verwenden HSQLDB, die den JDBC-Treiber und eine funktionierende In-Memory-Datenbank enthält.

Spring ORM Modelklasse

Wir können Standard-JPA-Annotationen für die Abbildung in unseren Modell-Beans verwenden, da Hibernate eine JPA-Implementierung bereitstellt.

package hu.daniel.hari.learn.spring.orm.model;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Product {

	@Id
	private Integer id;
	private String name;

	public Product() {
	}

	public Product(Integer id, String name) {
		this.id = id;
		this.name = name;
	}
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "Product [id=" + id + ", name=" + name + "]";
	}

}

Wir verwenden die Annotationen @Entity und @Id JPA, um unser POJO als Entität zu kennzeichnen und seinen Primärschlüssel zu definieren.

Spring ORM DAO-Klasse

Wir erstellen eine sehr einfache DAO-Klasse, die die Methoden persist und findAll bereitstellt.

package hu.daniel.hari.learn.spring.orm.dao;

import hu.daniel.hari.learn.spring.orm.model.Product;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.springframework.stereotype.Component;

@Component
public class ProductDao {

	@PersistenceContext
	private EntityManager em;

	public void persist(Product product) {
		em.persist(product);
	}

	public List<Product> findAll() {
		return em.createQuery("SELECT p FROM Product p").getResultList();
	}

}
  • @Component ist eine Spring-Annotation, die dem Spring-Container mitteilt, dass wir diese Klasse über Spring IoC (Dependency Injection) verwenden können.
  • Wir verwenden die JPA @PersistenceContext-Annotation, die auf Dependency Injection zu einem EntityManager hinweist. Spring fügt gemäß der spring.xml-Konfiguration eine geeignete Instanz des EntityManagers ein.

Spring ORM Serviceklasse

Unsere einfache Serviceklasse verfügt über 2 Schreib- und 1 Lese-Methode – add, addAll und listAll.

package hu.daniel.hari.learn.spring.orm.service;

import hu.daniel.hari.learn.spring.orm.dao.ProductDao;
import hu.daniel.hari.learn.spring.orm.model.Product;

import java.util.Collection;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component
public class ProductService {

	@Autowired
	private ProductDao productDao;

	@Transactional
	public void add(Product product) {
		productDao.persist(product);
	}
	
	@Transactional
	public void addAll(Collection<Product> products) {
		for (Product product : products) {
			productDao.persist(product);
		}
	}

	@Transactional(readOnly = true)
	public List<Product> listAll() {
		return productDao.findAll();

	}

}
  • Wir verwenden die Spring @Autowired-Annotation, um ProductDao in unserer Serviceklasse einzufügen.
  • Wir möchten die Transaktionsverwaltung verwenden, daher sind die Methoden mit der @Transactional-Spring-Annotation annotiert. Die listAll-Methode liest nur aus der Datenbank, daher setzen wir die @Transactional-Annotation für Optimierung auf schreibgeschützt.

Spring ORM Beispiel Bean-Konfigurations-XML

Unsere Spring-ORM-Beispielprojektklassen sind bereit. Schauen wir uns jetzt unsere Spring-Bean-Konfigurationsdatei an. spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans" 
	xmlns:p="https://www.springframework.org/schema/p"
	xmlns:context="https://www.springframework.org/schema/context" 
	xmlns:tx="https://www.springframework.org/schema/tx" 
	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-3.0.xsd
		https://www.springframework.org/schema/context
		https://www.springframework.org/schema/context/spring-context-3.0.xsd
		https://www.springframework.org/schema/tx
		https://www.springframework.org/schema/tx/spring-tx.xsd
		">
	
	<!-- Scans the classpath for annotated components that will be auto-registered as Spring beans -->
	<context:component-scan base-package="hu.daniel.hari.learn.spring" />
	<!-- Activates various annotations to be detected in bean classes e.g: @Autowired -->
	<context:annotation-config />

	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
		<property name="url" value="jdbc:hsqldb:mem://productDb" />
		<property name="username" value="sa" />
		<property name="password" value="" />
	</bean>
	
	<bean id="entityManagerFactory" 
			class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
			p:packagesToScan="hu.daniel.hari.learn.spring.orm.model"
            p:dataSource-ref="dataSource"
			>
		<property name="jpaVendorAdapter">
			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
				<property name="generateDdl" value="true" />
				<property name="showSql" value="true" />
			</bean>
		</property>
	</bean>

	<!-- Transactions -->
	<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>
	<!-- enable the configuration of transactional behavior based on annotations -->
	<tx:annotation-driven transaction-manager="transactionManager" />

</beans>
  1. Zuerst teilen wir Spring mit, dass wir die Klassenzuordnung für Spring-Komponenten (Services, DAOs) über die classpath-Scans verwenden möchten, anstatt sie einzeln in der Spring-XML zu definieren. Wir haben auch die Erkennung von Spring-Annotationen aktiviert.
  2. Hinzufügen des Datenquellen, die derzeit HSQLDB im Speicherdatenbank ist.
  3. Wir richten eine JPA EntityManagerFactory ein, die von der Anwendung verwendet wird, um einen EntityManager zu erhalten. Spring unterstützt 3 verschiedene Möglichkeiten, dies zu tun. Wir haben LocalContainerEntityManagerFactoryBean für volle JPA-Fähigkeiten verwendet. Wir setzen die Attribute von LocalContainerEntityManagerFactoryBean wie folgt:
    1. Das packagesToScan-Attribut, das auf unser Paket mit Modellklassen zeigt.
    2. Die zuvor in der Spring-Konfigurationsdatei definierte Datenquelle.
    3. jpaVendorAdapter als Hibernate und Einstellung einiger Hibernate-Eigenschaften.
  4. Wir erstellen eine Spring PlatformTransactionManager-Instanz als JpaTransactionManager. Dieser Transaktionsmanager ist für Anwendungen geeignet, die eine einzige JPA-EntityManagerFactory für den transaktionalen Datenzugriff verwenden.
  5. Wir aktivieren die Konfiguration des transaktionalen Verhaltens basierend auf Annotationen, und wir setzen den von uns erstellten transactionManager.

Spring ORM Hibernate JPA Beispiel Testprogramm

Unser Spring-ORM-JPA-Hibernate-Beispielprojekt ist bereit, also schreiben wir ein Testprogramm für unsere Anwendung.

public class SpringOrmMain {
	
	public static void main(String[] args) {
		
		//Erstellen Sie den Spring-Anwendungskontext
		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/spring.xml");
		
		//Holen Sie den Service aus dem Kontext. (Die Abhängigkeit des Dienstes (ProductDAO) ist im ProductService mit @Autowired verdrahtet)
		ProductService productService = ctx.getBean(ProductService.class);
		
		//Führen Sie einige Datenoperationen durch
		
		productService.add(new Product(1, "Bulb"));
		productService.add(new Product(2, "Dijone mustard"));
		
		System.out.println("listAll: " + productService.listAll());
		
		//Testen Sie den Transaktionsrollback (doppelter Schlüssel)
		
		try {
			productService.addAll(Arrays.asList(new Product(3, "Book"), new Product(4, "Soap"), new Product(1, "Computer")));
		} catch (DataAccessException dataAccessException) {
		}
		
		//Testen Sie die Elementliste nach dem Rollback
		System.out.println("listAll: " + productService.listAll());
		
		ctx.close();
		
	}
}

Sie können sehen, wie einfach wir den Spring-Container von einer Hauptmethode aus starten können. Wir erhalten unseren ersten abhängigkeitsinjizierten Einstiegspunkt, die Instanz der Serviceklasse. Die Referenz zur Klasse ProductDao wird nach Initialisierung des Spring-Kontexts in die Klasse ProductService injiziert. Nachdem wir die Instanz von ProductService erhalten haben, können wir die Methoden testen. Alle Methodenaufrufe werden aufgrund des Spring-Proxy-Mechanismus transaktional sein. Wir testen auch den Rollback in diesem Beispiel. Wenn Sie das obige Testprogramm für das Spring-ORM-Beispiel ausführen, erhalten Sie die folgenden Protokolle.

Hibernate: insert into Product (name, id) values (?, ?)
Hibernate: insert into Product (name, id) values (?, ?)
Hibernate: select product0_.id as id0_, product0_.name as name0_ from Product product0_
listAll: [Product [id=1, name=Bulb], Product [id=2, name=Dijone mustard]]
Hibernate: insert into Product (name, id) values (?, ?)
Hibernate: insert into Product (name, id) values (?, ?)
Hibernate: insert into Product (name, id) values (?, ?)
Hibernate: select product0_.id as id0_, product0_.name as name0_ from Product product0_
listAll: [Product [id=1, name=Bulb], Product [id=2, name=Dijone mustard]]

Beachten Sie, dass die zweite Transaktion zurückgerollt wird, deshalb hat sich die Produktliste nicht geändert. Wenn Sie die Datei log4j.properties aus der beigefügten Quelle verwenden, können Sie sehen, was hinter den Kulissen passiert. Referenzen: https://docs.spring.io/spring/docs/current/spring-framework-reference/html/orm.html Sie können das endgültige Spring-ORM-JPA-Hibernate-Beispielprojekt über den unten stehenden Link herunterladen und damit experimentieren, um mehr zu erfahren.

Spring ORM mit Transaktionsprojekt herunterladen

Source:
https://www.digitalocean.com/community/tutorials/spring-orm-example-jpa-hibernate-transaction