springdata和mysql_JPA + SpringData 操作数据库 ---- 深入了解 SpringData

本文详述了SpringData JPA的使用,包括SpringData概述、环境搭建、配置JPA、事务管理、Repository接口规范及自定义方法等,通过实例展示了如何简化数据库访问操作。
摘要由CSDN通过智能技术生成

----------------------------------------------------------------------------------------------------------------------------------------------------------

笔记中提供了大量的代码示例,需要说明的是,大部分代码示例都是本人所敲代码并进行测试,不足之处,请大家指正~

本博客中所有言论仅代表博主本人观点,若有疑惑或者需要本系列分享中的资料工具,敬请联系 qingqing_crawl@163.com

-----------------------------------------------------------------------------------------------------------------------------------------------------------

前言:之前为大家详细介绍了 JPA 的知识,之前提到 JPA 和 SpringData 结合才能发挥出无比巨大的威力。那么,今天楼主开始介绍 SpringData,写此篇的目的主要是为了复习,如果能帮助到有需要的朋友,那再好不过了。

一、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 文件中:

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

private ApplicationContext ctx = null;

{

ctx= new ClassPathXmlApplicationContext("applicationContext.xml");

}//测试数据源是否获取成功

@Testpublic void testDataSource() throwsSQLException {

DataSource dataSource= ctx.getBean(DataSource.class);

System.out.println(dataSource.getConnection());

}

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

3.配置 JPA 的 EntityManagerFactory

class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">

org.hibernate.cfg.ImprovedNamingStrategy

org.hibernate.dialect.MySQL5InnoDBDialect

true

true

update

测试 JPA 是否配置成功:

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

packagecom.software.springdata;importjava.util.Date;importjavax.persistence.Column;importjavax.persistence.Entity;importjavax.persistence.GeneratedValue;importjavax.persistence.Id;importjavax.persistence.JoinColumn;importjavax.persistence.ManyToOne;importjavax.persistence.Table;importjavax.persistence.Temporal;importjavax.persistence.TemporalType;

@Table(name="JPA_PERSONS")

@Entitypublic classPerson {privateInteger id;privateString lastName;privateString email;privateDate birth;privateInteger addressId;

@Column(name="ADD_ID")publicInteger getAddressId() {returnaddressId;

}public voidsetAddressId(Integer addressId) {this.addressId =addressId;

}privateAddress address;

@JoinColumn(name="ADDRESS_ID")

@ManyToOnepublicAddress getAddress() {returnaddress;

}public voidsetAddress(Address address) {this.address =address;

}

@GeneratedValue

@IdpublicInteger getId() {returnid;

}public voidsetId(Integer id) {this.id =id;

}

@Column(name="LAST_NAME")publicString getLastName() {returnlastName;

}public voidsetLastName(String lastName) {this.lastName =lastName;

}publicString getEmail() {returnemail;

}public voidsetEmail(String email) {this.email =email;

}

@Temporal(TemporalType.DATE)publicDate getBirth() {returnbirth;

}public voidsetBirth(Date birth) {this.birth =birth;

}

@OverridepublicString toString() {return "Person [id=" + id + ", lastName=" + lastName + ", email="

+ email + ", birth=" + birth + "]";

}

}

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

5.配置 SpringData

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

aa9a3134d5c4837333ae5ac77309c083.png

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

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

61731eab777d222caeb6b0cbb6149049.png

配置 SpringData 扫描的包和 EntityManagerFactory

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

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

6512d016fd33fdf8f4a6465d96c2facd.png

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

1 //测试 Spring Data 的 Helloworld

2 @Test3 public voidtestSpringDataHelloworld() {4 Person person = repository.getByLastName("AA");5 System.out.println(person);6 }

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

三、Repository 接口

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

6f4afe76ccb74bced0853340a2e9ade9.png

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

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

cdf39493f204e1803bd9b723b74fcbd3.png

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 支持的关键字

04e248537d83344d5cb8403c35606b29.png

4fa919b4e35f3e47026d07d90da260d2.png

2)举例:

1 //WHERE lastName like %? AND id < ?

2 ListgetByLastNameEndingWithAndIdLessThan(String lastName, Integer age);3

4 //WHERE lastName like ?% AND id > ?

5 ListgetByLastNameStartingWithAndIdGreaterThan(String lastName, Integer age);6

7 //WHERE email IN(?,?,?) OR birth < ?

8 List

getByEmailInOrBirthLessThan

(List emails, Date date);

测试:

1 //测试 SpringData 支持的关键字

2 @Test3 public voidtestKeyWords() {4 List persons = repository.getByLastNameEndingWithAndIdLessThan("A", 5);5 System.out.println(persons);6

7 persons = repository.getByLastNameStartingWithAndIdGreaterThan("A", 1);8 System.out.println(persons);9

10 persons = repository.getByEmailInOrBirthLessThan(Arrays.asList("aa@163.com", "cc@163.com",11 "ee@163.com"), newDate());12 System.out.println(persons.size());13 }

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

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

bf6cf7d77354c2485aa1478b0e65f7a1.png

bd45ab484626be490b115b5805ab9bd7.png

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

3c5a93005c19c40429a5505bbb24c0c2.png

a7beda7ab66615a79339160758abc537.png

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

e405cbde9ebc58e660339491d293dd89.png

08b1f055a7ad8e2ca29cd1b06eb0ba26.png

五、@Query 注解

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

定义方法:

1 //查询 id 值最大的 Person2 //使用 @Query 注解可以自定义 JPQL 语句实现更加灵活的查询

3 @Query("SELECT p FROM Person p WHERE p.id = (SELECT max(p2.id) FROM Person p2)")4 Person getMaxIdPerson();

测试方法:

//测试 @Query 注解

@Testpublic voidtestQueryAnnotation() {

Person person=repository.getMaxIdPerson();

System.out.println(person);

}

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

1)使用占位符:

1 //为 @Query 注解传递参数的方式1:使用占位符, 此方式要求形参与定义的 JPQL 的参数位置一致

2 @Query("SELECT p FROM Person p WHERE p.lastName = ?1 AND p.email = ?2")3 List testQueryAnnotationParam1(String lastName, String email);

测试:

1 //测试向 @Query 注解传参

2 @Test3 public voidtestQueryAnnotationParam1() {4 List persons = repository.testQueryAnnotationParam1("AA", "aa@163.com");5 System.out.println(persons);6 }

2)使用命名参数:

1 //为 @Query 注解传递参数的方式2:使用命名参数, 此方式形参与定义的 JPQL 的参数位置不必一致

2 @Query("SELECT p FROM Person p WHERE p.lastName = :lastName AND p.email = :email")3 List testQueryAnnotationParam2(@Param("email") String email, @Param("lastName") String lastName);

1 //测试向 @Query 注解传参

2 @Test3 public voidtestQueryAnnotationParam2() {4 List persons = repository.testQueryAnnotationParam2("aa@163.com", "AA");5 System.out.println(persons);6 }

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

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

1 //带有 LIKE 关键字的 @Query 注解

2 @Query("SELECT p FROM Person p WHERE p.lastName LIKE ?1 AND p.email LIKE ?2")3 List testQueryAnnotationLikeParam(String lastName, String email);

1 //测试带有 LIKE 关键字的 @Query 注解

2 @Test3 public voidtestQueryAnnotationLikeParam() {4 List persons = repository.testQueryAnnotationLikeParam("%A%", "%aa%");5 System.out.println(persons);6 }

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

1 //带有 LIKE 关键字的 @Query 注解:SpringData 允许在占位符上添加 %

2 @Query("SELECT p FROM Person p WHERE p.lastName LIKE %?1% AND p.email LIKE %?2%")3 List testQueryAnnotationLikeParam2(String lastName, String email);

1 //测试带有 LIKE 关键字的 @Query 注解

2 @Test3 public voidtestQueryAnnotationLikeParam2() {4 List persons = repository.testQueryAnnotationLikeParam2("A", "aa");5 System.out.println(persons);6 }

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

//带有 LIKE 关键字的 @Query 注解:SpringData 允许在命名参数上添加 %

@Query("SELECT p FROM Person p WHERE p.lastName LIKE %:lastName% AND p.email LIKE %:email%")

List testQueryAnnotationLikeParam3(@Param("lastName") String lastName, @Param("email") String email);

1 //测试带有 LIKE 关键字的 @Query 注解

2 @Test3 public voidtestQueryAnnotationLikeParam3() {4 List persons = repository.testQueryAnnotationLikeParam3("A", "aa");5 System.out.println(persons);6 }

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

//本地 SQL 查询:设置 nativeQuery=true 即可执行本地查询

@Query(value="SELECT count(id) FROM jpa_persons", nativeQuery=true)long getTotalCount();

1 //测试本地 SQL 查询

2 @Test3 public voidtestNativeQuery() {4 long count =repository.getTotalCount();5 System.out.println(count);6 }

六、@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.示例:

1 /*

2 * 可以通过自定义 JPQL 完成 UPDATE 和 DELETE 操作,注:JPQL 不支持使用 INSERT3 * 在 @Query 中编写 JPQL 语句,但必须使用 @Modifying 注解修饰,以通知 SpringData 此操作是一个 UPDATE 或 DELETE 操作4 * UPDATE 或 DELETE 操作需要使用事务,所以需要定义 service 层,在 service 层方法上添加事务操作5 * 默认情况下,SpringData 的每个方法上都有事务,但都是只读事务,他们不能完成修改操作6 */

7 @Modifying8 @Query("UPDATE Person p SET p.email = :email WHERE p.id = :id")9 void updatePersonEmail(@Param("id") Integer id, @Param("email") String email);

70005e961c22a71eef9bf333baf159da.png

a77d714b2273a84c473dffa6e9b37f17.png

七、Repository 接口的子接口

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

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

419f4a44002ca067f4a00af2bdcbd0bb.png

2)Service 层:需要事务

f44ef0a99b31cbe803efd8e503769ace.png

3)测试:

e4aba051e1dd9b844760a38cd04b7e26.png

2. PagingAndSortingRepository 接口

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

03013cd423b7bdd7f5e36c6fa037558d.png

//测试 PagingAndSortRepository 的 findAll(Pageable pageable) 方法,进行分页

@Testpublic voidtestPagingAndSortingRepository() {//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= newSort(order1, order2);//Pageable 接口通常使用其 PageRequest 实现类,其中封装了需要分页的信息

PageRequest pageable = newPageRequest(pageNo, pageSize, sort);

Page 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 笔记

3fa6ac34cccd1fd67974af770b87ce83.png

0568f537c9a1285f976656ab6d44a0dc.png

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

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

50e8257786a22a02e46c77b9f7e08959.png

d3f02e76a7fdc52cbd8d1563ee101d45.png

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

1.步骤:

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

7da73d7270840883e2922e56054e877f.png

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

596dcfcfe232fabe2d545b13dc599f55.png

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

f592c7604dc93c29602c25ee4c6dc0de.png

4)测试使用:

4c6ec4239d42194ddc5d9264ff43d284.png

----------------------------------------------------------------------------------------------------------------

相关链接:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值