Spring ORM示例 - JPA,Hibernate,Transaction
欢迎来到Spring ORM示例教程。今天我们将使用Hibernate JPA事务管理来研究Spring ORM示例。我将向您展示一个具有以下功能的Spring独立应用程序的一个非常简单的示例。
- 依赖注入(@Autowired annotation)
- JPA EntityManager(由Hibernate提供)
- 带注释的事务方法(@Transactional注释)
目录[ 隐藏 ]
Spring ORM示例
我在Spring ORM示例中使用了内存数据库,因此不需要任何数据库设置(但您可以将其更改为spring.xml数据源部分中的任何其他数据库)。这是一个Spring ORM独立应用程序,可以最大限度地减少所有依赖项(但如果您熟悉spring,则可以通过配置轻松地将其更改为Web项目)。
注意:对于基于Spring AOP的Transactional(没有@Transactional注释)方法解析方法,请查看本教程:Spring ORM AOP事务管理。
下图显示了我们最终的Spring ORM示例项目。
让我们逐个浏览每个Spring ORM示例项目组件。
Spring ORM Maven依赖项
下面是我们最终的具有Spring ORM依赖项的pom.xml文件。我们在Spring ORM示例中使用了Spring 4和Hibernate 4。
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://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
这个原因我们不必将hibernate-core明确地放在pom.xml中。它通过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 Class
我们创建了一个非常简单的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="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://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配置文件中定义的datasource。
- 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) {
//Create Spring application context
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/spring.xml");
//Get service from context. (service's dependency (ProductDAO) is autowired in ProductService)
ProductService productService = ctx.getBean(ProductService.class);
//Do some data operation
productService.add(new Product(1, "Bulb"));
productService.add(new Product(2, "Dijone mustard"));
System.out.println("listAll: " + productService.listAll());
//Test transaction rollback (duplicated key)
try {
productService.addAll(Arrays.asList(new Product(3, "Book"), new Product(4, "Soap"), new Product(1, "Computer")));
} catch (DataAccessException dataAccessException) {
}
//Test element list after rollback
System.out.println("listAll: " + productService.listAll());
ctx.close();
}
}
您可以看到我们可以轻松地从main方法启动Spring容器。我们得到了第一个依赖注入入口点,即服务类实例。初始化spring上下文后ProductDao
注入类的类引用ProductService
。
在我们得到ProducService
实例之后,我们可以测试它的方法,由于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
来自附加源的文件,您可以看到幕后发生了什么。
参考文献:http:
//docs.spring.io/spring/docs/current/spring-framework-reference/html/orm.html
您可以从下面的链接下载最终的Spring ORM JPA Hibernate示例项目,并使用它来了解更多信息。