Spring 框架入门教程
1. 1. Spring 框架 2. 2. Spring 5 3. 3. Spring WebFlux 4. 4. 先介绍一下 Spring 5. 5. 什么是 Spring 依赖注入 6. 6. 什么是 Spring IoC 容器 和 Bean 7. 7. Spring Bean 的生命周期 8. 8. Spring REST 开发 9. 9. Spring REST XML 10. 10. Spring RestTemplate 开发 11. 11. Spring AOP 切面编程 12. 12. Spring AOP 方法调优 13. 13. Spring 注解详解 14. 14. Spring 核心注解之 @Autowired 15. 15. Spring 核心注解之 @RequestMapping 16. 16. Spring MVC 开发样例 17. 17. Spring MVC 开发指南 18. 18. Spring MVC 异常处理机制 19. 19. Spring MVC Validator 20. 20. Spring MVC 拦截器 21. 21. Spring MVC 文件上传 22. 22. Spring MVC 国际化(i18n) 23. 23. Spring MVC Hibernate MqSQL 24. 24. Spring ORM 25. 25. Spring ORM JPA 26. 26. Spring Data JPA 27. 27. Spring 事务管理 28. 28. 常用的 Spring JdbcTemplate 29. 29. Spring Security 简介 30. 30. Spring Security 教程 31. 31. Spring Security UserDetailsService 32. 32. Spring MVC 登录注销简单案例 33. 33. Spring Security Roles 34. 34. Spring Boot Tutorial 35. 35. Spring Boot Components 36. 36. Spring Boot CLI Hello World 37. 37. Spring Boot Initilizr Web 38. 38. Spring Boot Initilizr IDE 39. 39. Spring Boot Initilizr CLI 40. 40. Spring Boot Initilizr Tools 41. 41. Spring Boot MongoDB 42. 42. Spring Boot Redis Cache 43. 43. Spring Boot 常见面试问题 44. 44. Spring Batch 45. 45. Spring Batch 批处理示例 46. 46. Spring AMQP 47. 47. Spring RabbitMQ 48. 48. Spring AMQP RabbitMQ 49. 49. Apache ActiveMQ 安装与启动 50. 50. Spring ActiveMQ 教程 51. 51. Spring ActiveMQ 示例 52. 52. Spring JDBC 53. 53. Spring DataSource JNDI 54. 54. Spring Hibernate 55. 55. Spring Primefaces JPA 56. 56. Spring Primefaces MongoDB 57. 57. Spring Primefaces Hibernate 58. 58. SpringRoo Primefaces Hibernate 59. 59. Spring JSF 60. 60. Spring JDF Hibernate 61. 61. Spring Data MongoDB 62. 62. Spring 常见面试问题

24. Spring ORM

欢迎使用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 and spring-orm as Spring dependencies.
  • 我们使用hibernate-entitymanager for Hibernate as JPA implementation. hibernate-entitymanager is dependent on hibernate-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>
  1. 首先,我们告诉spring,我们希望对spring组件(服务、dao)使用类路径扫描,而不是在springxml中逐个定义它们。我们还启用了Spring注解检测。
  2. 添加数据源,即当前的HSQLDB内存数据库。
  3. 我们设立了JPAEntityManagerFactory that will used by the application to obtain an EntityManager. Spring supports 3 different ways to do this, we have used LocalContainerEntityManagerFactoryBean for full JPA capabilities.

    我们出发了LocalContainerEntityManagerFactoryBean attributes as:

    1. packagesToScan属性,它指向我们的模型类包。
    2. spring配置文件中先前定义的数据源。
    3. jpaventoradapter作为Hibernate并设置一些Hibernate属性。
  4. 我们将springplatformtransactionmanager实例创建为JpaTransactionManager。此事务管理器适用于使用单个JPA EntityManagerFactory进行事务数据访问的应用程序。
  5. 我们启用基于注解的事务行为配置,并设置创建的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.

参考文献:

精选推荐