咸鱼开发修炼之路

从零开始搭建REST风格的Spring项目(三)

Spring对多个持久化框架提供了支持,包括Hibernate、iBATIS、JDO(Java Data Objects)以及JPA(Java Persistence API)。
本节介绍如何在Spring项目中配置使用JPA对数据库进行操作。
07.jpg

简介

Java持久化API诞生在EJB2实体Bean的废墟之上,并成为了下一代Java持久化标准。JPA是基于POJO的持久化机制,它从Hibernate和JDO上借鉴了很多新理念并加入了Java5注解的特性。Spring2.0之后,Spring首次集成了JPA的功能。

maven配置相关架包

引入使用JPA所需要的架包:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.31</version>
<scope>runtime</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.8.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-orm -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>4.3.8.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate.javax.persistence/hibernate-jpa-2.1-api -->
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.1-api</artifactId>
<version>1.0.0.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.10.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-entitymanager -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.2.10.Final</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-c3p0 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>5.2.10.Final</version>
</dependency>

在maven中配置相关包之后,在Spring中使用JPA的第一步是在Spring应用上下文中将实体管理工厂(EntityManagerFactory)按照Bean的方式进行配置。

配置EntityManagerFactory

JPA定义了两种类型的实体管理器:

  • 应用程序管理类型 (Application-Managed):应用程序直接请求实体管理器
  • 容器管理类型(Container-Managed):应用程序访问JavaEE容器通过注入等方式获取实体管理器
    两种实体管理器实现了同一个EntityManager接口,两种方式创建和管理EntityManager的方式不同,应用程序管理类型 (Application-Managed)由EntityManagerFactory创建,EntityManagerFactory通过PersistenceProvider的createEntityManagerFactory()方法得到。而容器管理类型(Container-Managed)的EntityManagerFactory是通过PersistenceProvider的createContainerEntityManagerFactory()得到。在Spring中,EntityManagerFactory分别由对应的工厂Bean创建:
  • 应用程序管理类型 :LocalEntityManagerFactoryBean
  • 容器管理类型 :LocalContainerEntityManagerFactoryBean

在本项目中,我们采用容器管理类型的JPA,具体实现采用Hibernate,连接池采用c3p0,数据库使用MySQL。
以往常见的做法是需要一个persistence.xml文件来配置数据源,现在已经可以将数据源信息配置在Spring应用上下文中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/* JpaConfig.java */
@Configuration
@PropertySource(value = {"classpath:/jdbc.properties"})
public class JpaConfig {
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Value("${jdbc.driver}")
private String driver;
@Value("${hibernate.dialect}")
private String dialect;
@Bean
public DataSource dataSource() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource(); //JDBC连接池采用c3p0
dataSource.setDriverClass(driver);
dataSource.setJdbcUrl(url);
dataSource.setUser(username);
dataSource.setPassword(password);
return dataSource;
}
@Bean
public EntityManagerFactory entityManagerFactory() throws PropertyVetoException {
HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter(); //Hibernate适配器
adapter.setShowSql(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(adapter); //指定使用哪个厂商的JPA实现,本项目使用Hibernate
factory.setDataSource(dataSource()); //配置数据源
factory.setPackagesToScan("core"); //指定扫描实体的架包
factory.setJpaProperties(properties());
factory.afterPropertiesSet();
return factory.getObject();
}
private Properties properties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", dialect);
return properties;
}
}

将数据库登录账户密码等信息都配置在jdbc.properties文件中。
1
2
3
4
5
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ndtest?useUnicode=true&characterEncoding=UTF8
jdbc.username=root
jdbc.password=root
hibernate.dialect=org.hibernate.dialect.MySQL5Dialect

测试

在MySQL中创建一些测试数据。
微信截图_20170706002541.png

创建Goods实体:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Entity
@Table(name = "goods")
public class Goods {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "gid")
private Integer gid;
@Column(name = "gname")
private String gname;
public Integer getGid() {
return gid;
}
public void setGid(Integer gid) {
this.gid = gid;
}
public String getGname() {
return gname;
}
public void setGname(String gname) {
this.gname = gname;
}
}

通过EntityManager查询数据库:
1
2
3
4
5
6
7
8
9
@Service
public class GoodService {
@PersistenceContext
private EntityManager entityManager;
public List<Goods> findAllGoods(){
return entityManager.createQuery("FROM Goods g").getResultList();
}
}

编写Controller层接口:

1
2
3
4
5
6
@Autowired
private GoodService goodService;
@RequestMapping(value="/goods",method = RequestMethod.GET)
public List<Goods> postTest(){
return goodService.findAllGoods();
}

测试:
微信图片_20170706003143.png