转载

JPA + SpringData 操作数据库

编辑推荐:

本文主要讲解SpringData 概述 ,db.properties 文件 ,配置 JPA 的 EntityManagerFactory,配置 JPA 的事务管理器和支持注解的事务等希望对您能有所帮助。

本文来自于csdn,由火龙果软件Delores编辑推荐

一、SpringData 概述

1. SpringData:Spring 的一个子项目。用于简化数据库访问,支持NoSQL 和 关系数据存储。其主要目标是使数据库的访问变得方便快捷。

2.JPA Spring Data:致力于减少数据访问层 (DAO) 的开发量. 开发者唯一要做的,就只是声明持久层的接口,其他都交给 Spring Data JPA 来完成!

二、Spring Data JPA 的 Helloworld

1.环境搭建:

1)新建 Java Project:springdata

2)当前工程下新建 lib 目录

3)加入 Spring 的 jar 包:spring-framework-4.0.0.RELEASE/required 目录下所有

4)加入 Hibernate 和 JPA 的 jar 包:hibernate-release-4.2.4.Final/lib/required 和 hibernate-release-4.2.4.Final/lib/jpa 目录下的所有

5)加入 c3p0 和 MqSQL 的驱动

6)手动进行 Build Path

2.新建 Spring 的配置文件 applicationContext.xml,并进行数据源的配置

1) db.properties 文件

jdbc.user=root
 jdbc.password=qiqingqing
 jdbc.driverClass=com.mysql.jdbc.Driver
 jdbc.jdbcUrl=jdbc:mysql://
localhost:3306/springdata

2)applicationContext.xml 文件中:

<!-- 配置自动扫描的包 -->
 <context:component-scan base-package
="com.software.springdata">
</context:component-scan> 
<!-- 1.配置数据源 -->
 <context:property-placeholder
 location="classpath:db.properties"/>
 <bean id="dataSource" class=
"com.mchange.v2.c3p0.ComboPooledDataSource">
 <property name="user" value="${jdbc.user}">
</property>
 <property name="password"
 value="${jdbc.password}"></property>
 <property name="driverClass" 
value="${jdbc.driverClass}"></property>
 <property name="jdbcUrl" 
value="${jdbc.jdbcUrl}"></property>
 </bean>

3)注意:希望大家能够养成良好的单元测试的习惯,以便及时发现问题,及时解决:测试数据源是否获取成功,新建一个 SpringDataTest 单元测试类

private ApplicationContext ctx = null; 
 {
 ctx = new ClassPathXmlApplicationContext
("applicationContext.xml");
 } 
 //测试数据源是否获取成功
 @Test
 public void testDataSource() 
throws SQLException {
 DataSource dataSource = ctx.
getBean(DataSource.class);
 System.out.println
(dataSource.getConnection());
 }

只要输出数据库连接的信息,那就证明我们数据源的的配置没有问题了。

3.配置 JPA 的 EntityManagerFactory

<!-- 2.配置 JPA 的 EntityManagerFactory -->
 <bean id="entityManagerFactory"
 class="org.springframework.orm.jpa.
 LocalContainerEntityManagerFactoryBean">
 <!-- 配置数据源 --> 
 <property name="dataSource" ref="dataSource"
 ></property>
 <!-- 配置 JPA 提供商的适配器 -->
 <property name="jpaVendorAdapter">
 <bean class="org.springframework.orm.
 jpa.vendor.HibernateJpaVendorAdapter"></bean>
 </property>
 <!-- 配置实体类所在包 -->
 <property name="packagesToScan" 
 value="com.software.springdata"></property>
 <!-- 配置 JPA 实现产品的基本属性 -->
 <property name="jpaProperties">
 <props>
 <!-- 生成的数据表的列的映射策略 -->
 <prop key="hibernate.ejb.naming_strategy">
 org.hibernate.cfg.ImprovedNamingStrategy</prop>
 <!-- hibernate 基本属性 -->
 <prop key="hibernate.dialect">
 org.hibernate.dialect.MySQL5InnoDBDialect</prop>
 <prop key="hibernate.show_sql">true</prop>
 <prop key="hibernate.format_sql">true</prop>
 <prop key="hibernate.hbm2ddl.auto">update</prop>
 </props>
 </property>
 </bean>

测试 JPA 是否配置成功:

新建一个实体类 Person,添加必要的 JPA 注解,创建一个空的 JPA 的测试方法,执行此方法,查看是否生成数据表

package com.software.springdata; 
 import java.util.Date; 
import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.GeneratedValue;
 import javax.persistence.Id;
 import javax.persistence.JoinColumn;
 import javax.persistence.ManyToOne;
 import javax.persistence.Table;
 import javax.persistence.Temporal;
 import javax.persistence.TemporalType; 
@Table(name="JPA_PERSONS")
 @Entity
 public class Person {
 private Integer id;
 private String lastName;
 private String email;
 private Date birth;
 private Integer addressId;
 @Column(name="ADD_ID")
 public Integer getAddressId() {
 return addressId;
 } 
 public void setAddressId
(Integer addressId) {
 this.addressId = addressId;
 } 
 private Address address;
 @JoinColumn(name="ADDRESS_ID")
 @ManyToOne
 public Address getAddress() {
 return address;
 } 
 public void setAddress
(Address address) {
 this.address = address;
 } 
 @GeneratedValue
 @Id
 public Integer getId() {
 return id;
 } 
public void setId(Integer id) {
 this.id = id;
 } 
 @Column(name="LAST_NAME")
 public String getLastName() {
 return lastName;
 } 
 public void setLastName
(String lastName) {
 this.lastName = lastName;
 } 
 public String getEmail() {
 return email;
 } 
 public void setEmail(String email) {
 this.email = email;
 } 
 @Temporal(TemporalType.DATE)
 public Date getBirth() {
 return birth;
 } 
 public void setBirth(Date birth) {
 this.birth = birth;
 } 
 @Override
 public String toString() {
 return "Person [id=" + id + ", 
 lastName=" + lastName + ", email="
 + email + ", birth=" + birth + "]";
 }
 }

4.配置 JPA 的事务管理器和支持注解的事务

<!-- 3.配置 JPA 的事务管理器 -->
 <bean id="transactionManager" 
 class="org.springframework.orm.jpa.
 JpaTransactionManager">
 <property name="entityManagerFactory" ref="entityManagerFactory"></property>
 </bean>
 <!-- 4.配置支持注解的事务 -->
 <tx:annotation-driven 
 transaction-manager="transactionManager"/>

5.配置 SpringData

1)加入 SpringData 的 jar 包:spring-data-jpa/required 目录下所有(自创建的目录),手动 Build Path

JPA + SpringData 操作数据库

还要加入 SpringData 依赖的日志包 slf4j

2)加入 jpa 的命名空间,左下角 Namespaces 中添加

JPA + SpringData 操作数据库

配置 SpringData 扫描的包和 EntityManagerFactory

<!-- 5.配置 Spring Data -->
 <!-- 加入 jpa 的命名空间:左下角 
 Namespaces 中加入 -->
 <!-- 配置 Spring Data 扫描的包和 
 EntityManagerFactory -->
 <!-- base-package:扫描 Repository Bean
 所在的 package -->
 <jpa:repositories base-package=
 "com.software.springdata"
 entity-manager-factory-ref=
 "entityManagerFactory"></jpa:repositories>

6.编写 SpringData 的代码,测试 HelloWorld

1)创建一个 PersonRepsotory 接口继承 Repository 接口,声明一个方法

JPA + SpringData 操作数据库

2)编写测试方法:需要在测试类中引入 PersonRepository 的实例,通过 ctx.getBean(PersonRepository.class); 获取,以后不再赘述。

//测试 Spring Data 的 Helloworld
 @Test
 public void 
testSpringDataHelloworld() {
 Person person = repository.
getByLastName("AA");
 System.out.println(person);
 }

这样便会获取 LastName 为 AA 的数据库中的那条记录。

三、Repository 接口

1. Repository 是一个空接口,即是一个标记接口。源码

JPA + SpringData 操作数据库

2.若我们定义的接口实现了 Repository,则该接口会被 IOC 容器识别为一个 Repository Bean,纳入到 IOC 容器中,进而可以在该接口中定义一些符合规范的方法

3.还可以通过 @RepositoryDefinition 注解来替代继承 Repository 接口

JPA + SpringData 操作数据库

4.Repository 接口的实现类:

1)CrudRepository: 继承 Repository,实现了一组 CRUD 相关的方法

2)PagingAndSortingRepository: 继承 CrudRepository,实现了一组分页排序相关的方法

3)JpaRepository: 继承 PagingAndSortingRepository,实现一组 JPA 规范相关的方法

4)自定义的 XxxxRepository 需要继承 JpaRepository,这样的 XxxxRepository 接口就具备了通用的数据访问控制层的能力。

注:JpaSpecificationExecutor: 不属于Repository体系,实现一组 JPA Criteria 查询相关的方法

四、SpringData 的方法定义规范SpringData 的方法定义规范

1.不能随便声明,需要符合一定的规范

2.查询的方法以 find、read、get 开头

3.涉及条件查询时条件的属性要以关键字连接,条件属性首字母大写

1)SpringData 支持的关键字

JPA + SpringData 操作数据库

JPA + SpringData 操作数据库

2)举例:

//WHERE lastName like %? AND id < ?
 List<Person> getByLastNameEnding
WithAndIdLessThan
(String lastName, Integer age);
 //WHERE lastName like ?% AND id > ?
 List<Person> getByLastNameStarting
WithAndIdGreaterThan
(String lastName, Integer age);
 //WHERE email IN(?,?,?) OR birth < ?
 List<Person> 
 getByEmailInOrBirthLessThan
 (List<String> emails, Date date);

测试:

//测试 SpringData 支持的关键字
 @Test
 public void testKeyWords() {
 List<Person> persons = repository.
getByLastNameEnding
WithAndIdLessThan("A", 5);
 System.out.println(persons);
 persons = repository.getByLastName
StartingWithAndIdGreaterThan("A", 1);
 System.out.println(persons);
 persons = repository.getByEmailInOrBirthLessThan
(Arrays.asList("aa@163.com", "cc@163.com",
 "ee@163.com"), new Date());
 System.out.println(persons.size());
 }

4.支持级联查询,若当前类有符合条件的查询,则优先使用,而不使用级联查询,若需要使用级联查询,则属性之间需要使用 _ (下划线)来连接

1)创建 Address 类,添加对应的 JPA 注解,在 Person 类中添加 Address 类的引用,使用 @ManyToOne 映射,生成对应的数据表

JPA + SpringData 操作数据库

JPA + SpringData 操作数据库

2)创建测试方法:此时为级联查询

JPA + SpringData 操作数据库

JPA + SpringData 操作数据库

3)为 Person 类添加 addressId 属性后,若再进行相同的测试,则不是级联查询了,而查询条件为 Person 类中的 addressId 属性。若要再进行级联查询,需要在属性之间需要使用 _ (下划线)来连接

JPA + SpringData 操作数据库

JPA + SpringData 操作数据库

五、@Query 注解

1.使用 @Query 注解可以自定义 JPQL 语句实现更加灵活的查询

定义方法:

//查询 id 值最大的 Person
 //使用 @Query 注解可以自定义 JPQL 
语句实现更加灵活的查询
 @Query("SELECT p FROM Person p WHERE
 p.id = (SELECT max(p2.id) FROM Person p2)")
 Person getMaxIdPerson();

测试方法:

//测试 @Query 注解
 @Test
 public void testQueryAnnotation() {
 Person person = repository.
getMaxIdPerson();
 System.out.println(person);
 }

2.为 @Query 注解传递参数的两种方式

1)使用占位符:

 //为 @Query 注解传递参数的方式1:
使用占位符, 此方式要求形参与定义的
 JPQL 的参数位置一致
 @Query("SELECT p FROM Person p 
WHERE p.lastName = ?1 AND p.email = ?2")
 List<Person> testQueryAnnotationParam1
(String lastName, String email);

测试:

 //测试向 @Query 注解传参
 @Test
 public void testQueryAnnotationParam1(){
 List<Person> persons = repository.
testQueryAnnotationParam1
("AA", "aa@163.com");
 System.out.println(persons);
 }

2)使用命名参数:

 //为 @Query 注解传递参数的方式2:
使用命名参数, 此方式形参与定义的 JPQL
 的参数位置不必一致
 @Query("SELECT p FROM Person 
p WHERE 
p.lastName = :lastName AND p.email = :email")
 List<Person> testQueryAnnotationParam2
(@Param("email") String email,
 @Param("lastName") String lastName);
//测试向 @Query 注解传参
 @Test
 public void testQueryAnnotationParam2() {
 List<Person> persons = 
repository.testQueryAnnotationParam2
("aa@163.com", "AA");
 System.out.println(persons);
 }

3.带有 LIKE 关键字的 @Query 注解

1)需要在测试方法中手动加上 %,不推荐

//带有 LIKE 关键字的 @Query 注解
 @Query("SELECT p FROM Person p WHERE 
p.lastName LIKE ?1 AND p.email LIKE ?2")
 List<Person> testQueryAnnotationLikeParam
(String lastName, String email);
//测试带有 LIKE 关键字的 @Query 注解
 @Test
 public void testQueryAnnotationLikeParam() {
 List<Person> persons = repository.
testQueryAnnotationLikeParam("%A%", "%aa%");
 System.out.println(persons);
 }

2)SpringData 允许在占位符上添加 %

//带有 LIKE 关键字的 @Query 注解:
SpringData 允许在占位符上添加 %
 @Query("SELECT p FROM Person p WHERE
 p.lastName LIKE %?1% AND p.email LIKE %?2%")
 List<Person> testQueryAnnotationLikeParam2
(String lastName, String email);
//测试带有 LIKE 关键字的 @Query 注解
 @Test
 public void testQueryAnnotationLikeParam2() {
 List<Person> persons = repository.
testQueryAnnotationLikeParam2("A", "aa");
 System.out.println(persons);
 }

3)SpringData 允许在命名参数上添加 %

//带有 LIKE 关键字的 @Query 注解:
SpringData 允许在命名参数上添加 %
 @Query("SELECT p FROM Person p WHERE 
p.lastName LIKE %:lastName% AND
 p.email LIKE %:email%")
 List<Person> testQueryAnnotationLikeParam3
(@Param("lastName") String lastName,
 @Param("email") String email);
//测试带有 LIKE 关键字的 @Query 注解
 @Test
 public void testQueryAnnotationLikeParam3(){
 List<Person> persons = 
repository.testQueryAnnotationLikeParam3
("A", "aa");
 System.out.println(persons);
 }

4.使用 @Query 执行本地 SQL 查询,在 @Query 注解中添加参数 nativeQuery=true

//本地 SQL 查询:设置 nativeQuery=true 
即可执行本地查询
 @Query(value="SELECT count(id) FROM
 jpa_persons", nativeQuery=true)
 long getTotalCount();
//测试本地 SQL 查询
 @Test
 public void testNativeQuery() {
 long count = repository.getTotalCount();
 System.out.println(count);
 }

六、@Modifying 注解

1.使用 @Modifying 配合 @Query 可以完成 UPDATE 和 DELETE 操作

2.可以通过自定义 JPQL 完成 UPDATE 和 DELETE 操作,注:JPQL 不支持使用 INSERT

3.在 @Query 中编写 JPQL 语句,但必须使用 @Modifying 注解修饰,以通知 SpringData 此操作是一个 UPDATE 或 DELETE 操作

4.UPDATE 或 DELETE 操作需要使用事务,所以需要定义 service 层,在 service 层方法上添加事务操作

5.示例:

/*
 * 可以通过自定义 JPQL 完成 UPDATE 和 
DELETE 操作,注:JPQL 不支持使用 INSERT
 * 在 @Query 中编写 JPQL 语句,但必须使用 
@Modifying 注解修饰,以通知 SpringData 
此操作是一个 UPDATE 或 DELETE 操作
 * UPDATE 或 DELETE 操作需要使用事务,
所以需要定义 service 层,在 service 层
方法上添加事务操作
 * 默认情况下,SpringData 的每个方法上都有事务,
但都是只读事务,他们不能完成修改操作
 */
 @Modifying
 @Query("UPDATE Person p SET
 p.email = :email WHERE p.id = :id")
 void updatePersonEmail(@Param("id") 
 Integer id, @Param("email") String email);

JPA + SpringData 操作数据库

JPA + SpringData 操作数据库

七、Repository 接口的子接口

1、CrudRepository 接口;测试此接口的 save(Iterable<S > entities) 方法进行批量保存

1)使自定义的接口继承 CrudRepository 接口

JPA + SpringData 操作数据库

2)Service 层:需要事务

JPA + SpringData 操作数据库

3)测试:

JPA + SpringData 操作数据库

2. PagingAndSortingRepository 接口

1)实现分页操作(带排序):(只读事务,不需要再 service 层中编写)

JPA + SpringData 操作数据库

//测试 PagingAndSortRepository 的
 findAll(Pageable pageable) 方法,进行分页
 @Test
 public void testPagingAndSortingRepository() {
 //pageNo 从 0 开始
 int pageNo = 3 - 1;
 int pageSize = 5;
 //Sort 封装了排序信息,Order 
指明具体是根据哪一个属性进行升序或者降序
 Order order1 = new Order(Direction.DESC, "id");
 Order order2 = new Order(Direction.ASC, "email");
 Sort sort = new Sort(order1, order2);
 //Pageable 接口通常使用其 PageRequest 
实现类,其中封装了需要分页的信息
 PageRequest pageable = new PageRequest
(pageNo, pageSize, sort);
 Page<Person> page = pagingAndSortingRepository.
findAll(pageable);
 System.out.println("总共有 " 
+ page.getTotalElements() + " 条记录");
 System.out.println("总共有 " 
+ page.getTotalPages() + " 页");
 System.out.println("当前页为:" 
+ (page.getNumber() + 1));
 System.out.println("当前的 List: " 
+ page.getContent());
 System.out.println("当前页的总记录数为:" 
+ page.getNumberOfElements());
 }

3. JpaRepository 接口:测试此接口的 saveAndFlush() 方法,此方法相当于 JPA 中的 merge() 方法,详见 JPA 笔记

JPA + SpringData 操作数据库

JPA + SpringData 操作数据库

补:JpaSpecificationExecutor 接口,不属于Repository体系,实现一组 JPA Criteria 查询相关的方法 ,即带条件的分页查询

1)自定义的接口必须实现 Repository 或 Repository 的子接口 还有 JpaSpecificationExecutor 接口

JPA + SpringData 操作数据库

JPA + SpringData 操作数据库

八、自定义 Repository 方法:为某一个 Repository 上添加自定义方法

1.步骤:

1)定义一个接口: 声明要添加的, 并自实现的方法

JPA + SpringData 操作数据库

2)提供该接口的实现类: 类名需在要声明的 Repository(以 PersonRepository 为例) 后添加 Impl, 并实现方法

JPA + SpringData 操作数据库

3)声明 Repository 接口(即 PersonRepository 接口), 并继承 1) 声明的接口

JPA + SpringData 操作数据库

4)测试使用:

JPA + SpringData 操作数据库

原文  http://www.uml.org.cn/j2ee/202003114.asp?artid=23049
正文到此结束
Loading...