歡迎來到Spring ORM範例教程。 今天我們將介紹使用Hibernate JPA事務管理的Spring ORM範例。 我將展示一個非常簡單的Spring獨立應用程序示例,具有以下功能。
- 依賴注入( @Autowired 注釋)
- JPA實體管理器(由Hibernate提供)
- 注釋的事務方法( @Transactional 注釋)
Spring ORM範例
我已經在Spring ORM示例中使用了內存數據庫,因此不需要任何數據庫設置(但您可以在spring.xml數據源部分更改為任何其他數據庫)。這是一個Spring ORM獨立應用程序,以最小化所有依賴關係(但如果您熟悉spring,您可以輕松地通過配置將其更改為Web項目)。 注意:對於基於Spring AOP的事務(不帶@Transactional註釋)方法解析方法,請參閱本教程:Spring ORM AOP事務管理。下面的圖像顯示了我們的最終Spring ORM示例項目。
讓我們逐一介紹每個Spring ORM示例項目組件。
Spring ORM Maven依賴項
以下是我們的最終pom.xml文件,其中包含Spring ORM依賴項。我們在我們的Spring ORM示例中使用了Spring 4和Hibernate 4。
<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>
- 我們需要
spring-context
和spring-orm
作為 Spring 依賴。 - 我們使用
hibernate-entitymanager
作為 Hibernate 的 JPA 實現。hibernate-entitymanager
依賴於hibernate-core
,這就是為什麼我們不需要在 pom.xml 中明確地加入 hibernate-core。它是通過 Maven 的傳遞依賴將其引入到我們的項目中的。 - 我們還需要 JDBC 驅動程序作為數據庫訪問的依賴。我們使用包含 JDBC 驅動程序和一個工作在內存中的數據庫的 HSQLDB。
Spring ORM 模型類
我們可以使用標準的 JPA 注釋來對我們的模型 bean 進行映射,因為 Hibernate 提供了 JPA 實現。
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 + "]";
}
}
我們使用 @Entity
和 @Id
JPA 注釋來將我們的 POJO 定義為實體並定義其主鍵。
Spring ORM DAO 類
我們創建一個非常簡單的 DAO 類,提供 persist 和 findALL 方法。
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 是 Spring 的注釋,告訴 Spring 容器我們可以通過 Spring IoC(依賴注入)使用這個類。
- 我們使用 JPA `@PersistenceContext` 註釋來指示對 EntityManager 的依賴注入。Spring 根據 spring.xml 配置向服務類注入一個合適的 EntityManager 實例。
Spring ORM 服務類
我們簡單的服務類有 2 個寫入方法和 1 個讀取方法 – add、addAll 和 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();
}
}
- 我們使用 Spring `@Autowired` 註釋將 ProductDao 注入我們的服務類中。
- 我們想要使用事務管理,所以方法被標記了 `@Transactional` Spring 註釋。listAll 方法僅讀取數據庫,因此我們將 `@Transactional` 註釋設置為只讀,以進行優化。
Spring ORM 示例 Bean 配置 XML
我們的 Spring ORM 示例項目 Java 類已經準備好,現在讓我們來看看我們的 Spring Bean 配置文件吧。`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>
- 首先,我們告訴 Spring 我們希望使用類路徑掃描來掃描 Spring 組件(服務、DAO),而不是在 spring xml 中逐個定義它們。我們還啟用了 Spring 註釋檢測。
- 添加数据源,目前是HSQLDB内存数据库。
- 我们设置了一个JPA
EntityManagerFactory
,应用程序将使用它来获取一个EntityManager。Spring支持3种不同的方式来做到这一点,我们使用了LocalContainerEntityManagerFactoryBean
来实现完整的JPA功能。我们将LocalContainerEntityManagerFactoryBean
的属性设置为:- packagesToScan属性指向我们的模型类所在的包。
- 之前在Spring配置文件中定义的数据源。
- jpaVendorAdapter为Hibernate,并设置一些Hibernate属性。
- 我们创建一个Spring PlatformTransactionManager实例作为JpaTransactionManager。这个事务管理器适用于使用单个JPA EntityManagerFactory进行事务性数据访问的应用程序。
- 我们启用基于注解的事务行为配置,并设置我们创建的transactionManager。
Spring ORM Hibernate JPA示例测试程序
我们的Spring ORM JPA Hibernate示例项目已经准备好了,现在让我们为我们的应用程序编写一个测试程序。
public class SpringOrmMain {
public static void main(String[] args) {
//創建Spring應用程式上下文
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/spring.xml");
//從上下文中獲取服務(服務的依賴關係(ProductDAO)在ProductService中自動裝配)
ProductService productService = ctx.getBean(ProductService.class);
//進行一些數據操作
productService.add(new Product(1, "Bulb"));
productService.add(new Product(2, "Dijone mustard"));
System.out.println("listAll: " + productService.listAll());
//測試事務回滾(重複鍵)
try {
productService.addAll(Arrays.asList(new Product(3, "Book"), new Product(4, "Soap"), new Product(1, "Computer")));
} catch (DataAccessException dataAccessException) {
}
//回滾後測試元素列表
System.out.println("listAll: " + productService.listAll());
ctx.close();
}
}
您可以看到我們如何輕鬆地從主方法啟動Spring容器。我們正在獲取我們的第一個依賴注入的入口點,服務類實例。 ProductDao
類引用在初始化Spring上下文後注入到 ProductService
類中。在我們得到 ProducService
實例後,我們可以測試它的方法,由於Spring的代理機制,所有方法調用將是事務性的。我們還在這個例子中測試了回滾。如果您運行上面的Spring ORM示例測試程序,您將獲得以下日誌。
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]]
請注意,第二個事務已經回滾,這就是為什麼產品列表沒有更改的原因。如果您使用附帶源代碼的 log4j.properties
文件,您可以看到底層發生了什麼。參考資料:https://docs.spring.io/spring/docs/current/spring-framework-reference/html/orm.html 您可以從下面的鏈接下載最終的Spring ORM JPA Hibernate示例項目並進行更多操作以進行學習。
Source:
https://www.digitalocean.com/community/tutorials/spring-orm-example-jpa-hibernate-transaction