欢迎使用Spring Orm示例教程。今天,我们将研究使用Hibernate Jpa事务管理的Spring Orm示例。我将向您展示一个非常简单的Spring独立应用程序示例,它具有以下特性。
- 依赖注入(@Autowired annotation)
- JPA EntityManager(由Hibernate提供)
- 带注解的事务方法(@transactional annotation)
目录
Spring ORM示例
我在Spring Orm示例中使用了内存数据库,因此不需要任何数据库设置(但是您可以在spring.xml文件数据源部分)。这是一个Spring Orm独立应用程序,可以最小化所有依赖项(但是如果熟悉Spring,可以通过配置轻松地将其更改为web项目)。
注意:对于基于Spring AOP的事务(不带@Transactional annotation)方法解析方法,请查看本教程:Spring ORM AOP事务管理.
下图显示了最后一个Spring Orm示例项目。
让我们逐一浏览Spring Orm示例项目组件。
Spring-ORM-Maven依赖关系
下面是我们的决赛pom.xml文件具有Spring Orm依赖关系的文件。我们在Spring Orm示例中使用了spring4和hibernate4。
<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
andspring-orm
as Spring dependencies. - 我们使用
hibernate-entitymanager
for Hibernate as JPA implementation.hibernate-entitymanager
is dependent onhibernate-core
this why we don’t have to put Hibernate核心在pom.xml文件明确地。它通过maven传递依赖关系被引入到我们的项目中。 - 我们还需要JDBC驱动程序作为数据库访问的依赖项。我们使用的是HSQLDB,它包含JDBC驱动程序和一个在内存中工作的数据库。
Spring ORM模型类
我们可以在模型bean中使用标准的JPA注解进行映射,因为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
and @Id
JPA annotations to qualify our POJO as an Entity and to define it’s primary key.
春ORM刀类
我们创建了一个非常简单的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();
}
}
- @组件是Spring注解,它告诉Spring容器我们可以通过Spring Ioc(依赖注入)使用这个类。
- 我们使用JPA
@PersistenceContext
annotation that indicate dependency injection to an EntityManager. Spring injects a proper instance of EntityManager according to the spring.xml configuration.
Spring Orm服务类
我们的简单服务类有2个write和1个read方法&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 annotation. The listAll method only reads the database so we set the @Transactional annotation to read-only for optimisation.
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">
<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"
p:packagesToScan="hu.daniel.hari.learn.spring.orm.model"
p:dataSource-ref="dataSource"
>
<property name="jpaVendorAdapter">
<bean>
<property name="generateDdl" value="true" />
<property name="showSql" value="true" />
</bean>
</property>
</bean>
<!-- Transactions -->
<bean id="transactionManager">
<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)使用类路径扫描,而不是在springxml中逐个定义它们。我们还启用了Spring注解检测。
- 添加数据源,即当前的HSQLDB内存数据库。
- 我们设立了JPA
EntityManagerFactory
that will used by the application to obtain an EntityManager. Spring supports 3 different ways to do this, we have usedLocalContainerEntityManagerFactoryBean
for full JPA capabilities.我们出发了
LocalContainerEntityManagerFactoryBean
attributes as:- packagesToScan属性,它指向我们的模型类包。
- spring配置文件中先前定义的数据源。
- jpaventoradapter作为Hibernate并设置一些Hibernate属性。
- 我们将springplatformtransactionmanager实例创建为JpaTransactionManager。此事务管理器适用于使用单个JPA EntityManagerFactory进行事务数据访问的应用程序。
- 我们启用基于注解的事务行为配置,并设置创建的transactionManager。
Spring Ormhibernate JPA示例测试程序
我们的Spring Ormjpahbernate示例项目已经准备好了,所以让我们为我们的应用程序编写一个测试程序。
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();
}
}
从一个容器的方法我们可以很容易的看出从一个主容器开始。我们得到了第一个依赖注入入口点,服务类实例。ProductDao
class reference injected to the ProductService
class after the spring context is initialized.
在我们得到ProducService
instance, we can test it’s methods, all method call will be transactional due to Spring’s proxy mechanism. We also test rollback in this example.
如果您在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
file from attached source, you can see what’s going on under the hood.
参考文献: