一、Spring Data概述

1、SpringData:Spring的一个子项目。用于简化数据库的访问,支持NoSQL关系数据存储。其主要目标是使数据库的访问变得方便快捷。
2、SpringData项目所支持NoSQL存储
(1)MongoDB(文档数据库)
(2)Neo4j(图形数据库)
(3)Redis(键/值存储)
(4)Hbase(列族数据库)
3、SpringData项目所支持的关系数据库存储技术 (1)JDBC
(2)JPA

二、JPA Spring Data概述

1、JPA Spring Data:致力于减少数据访问层(Dao)的开发量。开发者唯一要做的就是声明持久层的接口,其他的交给SpringDataJPA来帮你完成。
2、框架怎么可能代替开发者实现业务逻辑呢?比如:当有一个UserDao.findUserById()这样一个方法声明,大致应该能判断这是根据给定条件ID查询满足条件的User对象。Spring Data JPA做的便是规范方法的名字,根据规范的名字来确定方法需要什么样的逻辑。
2、JPQL和SQL
(1)JPQL和SQL很像,查询关键字都是一样的
(2)唯一的区别是:JPQL是面向对象的
3、JPQL书写规则
JPA的查询语言,类似于sql
(1)里面不能出现表名,列名,只能出现java的类名,属性名,区分大小写
(2)出现的sql关键字是一样的意思,关键字不区分大小写
(3)不能写select * 要写select 别名

三、使用Spring Data JPA进行持久层开发

1、步骤
(1)配置Spring整合JPA
(2)在Spring配置文件中配置SpringData,让Spring为声明的接口创建代理对象。配置了jsp:repositories后,Spring初始化容器时将会扫描base-package指定的包目录及其子目录,为继承Repository或其子接口的接口创建代理对象,并将代理对象注册为SpringBean,业务层便可以通过Spring自动封装的特性来直接使用该对象。
(3)声明持久层的接口,该接口继承Repository**,Repository是一个标记型接口,它不包含任何方法,如必要,Spring Data 可实现Repsitory其他子接口,其中定义了一些常用的增删改查,以及分页相关的方法。
(4)在接口中声明需要的方法。Spring Data将根据给定的策略来为其生成实现代码。

2、Repository接口
(1)Repository是一个空接口。即是一个标记接口。
(2)若我们定义的接口继承了Repository,则此接口会被IOC容器识别为一个Repository-Bean,纳入到IOC容器中,进而可以在此接口中定义满足一定规范的方法。
(3)实际上,也可以通过@RepositoryDefinition(dmainClass=Person.class,idClass=Integer.calss)注解来替代继承Repository接口。(dmainClass指定处理持久化类的类型,idClass指定主键的类型)
(4)Repository的子接口
A、Repository:仅仅是一个标识,表明任何继承它的均为仓库接口类。
B、CrudRepository:继承Repository,实现了一组CRUD相关的方法。
C、PagingAndSortingRepository:继承CrudRepository,实现了一组分页排序相关的方法。
D、JpaRepository:继承了PagingAndSortingRepository,实现一组JPA规范相关的方法。
E、自定义的XxxRepository需要继承JpaRepository,这样XxxRepository接口就具备了通用的数据访问控制层的能力。
F、JpaSpecificationExecutor:不属于Repository体系,实现一组JPA Criteria查询相关的方法。

3、SpringData Repository查询方法定义规范
(1)在Repository子接口中声明方法
A、不是随便声明的,而要符合一定的规范
B、简单条件查询:查询某一个实体类或者集合
a、按照SpringData规范,查询方法以find | read | get开头,涉及条件查询时,条件的属性用条件关键字连接,需要注意的是:条件属性以首字母大写。
例:定义一个Entity实体类

class User{
	private String firstName;
	private String lastName; 	 	 	 	
}

使用And条件连接时,应该这样写:
findByLastNameAndFirstName(String lastName,String FirstName); 条件的属性名称与个数要与参数的位置与个数一一对应。
(2)支持的关键字
A、直接在接口中定义查询方法,如果是符合规范的,可以不用写实现,目前支持的关键字写法如下:

关键字

方法命名

sql where字句

And

findByNameAndPwd

where name= ? and pwd =?

Or

findByNameOrSex

where name= ? or sex=?

Is,Equals

findById,findByIdEquals

where id= ?

Between

findByIdBetween

where id between ? and ?

LessThan

findByIdLessThan

where id < ?

LessThanEquals

findByIdLessThanEquals

where id <= ?

GreaterThan

findByIdGreaterThan

where id > ?

GreaterThanEquals

findByIdGreaterThanEquals

where id > = ?

After

findByIdAfter

where id > ?

Before

findByIdBefore

where id < ?

IsNull

findByNameIsNull

where name is null

isNotNull,NotNull

findByNameNotNull

where name is not null

Like

findByNameLike

where name like ?

NotLike

findByNameNotLike

where name not like ?

StartingWith

findByNameStartingWith

where name like ‘?%’

EndingWith

findByNameEndingWith

where name like ‘%?’

Containing

findByNameContaining

where name like ‘%?%’

OrderBy

findByIdOrderByXDesc

where id=? order by x desc

Not

findByNameNot

where name <> ?

In

findByIdIn(Collection<?> c)

where id in (?)

NotIn

findByIdNotIn(Collection<?> c)

where id not in (?)

True

findByAaaTue

where aaa = true

False

findByAaaFalse

where aaa = false

IgnoreCase

findByNameIgnoreCase

where UPPER(name)=UPPER(?)

Count

countByFirstName

select count(*) from … where x.firstName = ?1

Exists

existsByFirstName

like the dao.exists(Example),judge by attribution of firstName:select keyindex0_.id as col_0_0_ from key_index keyindex0_ where keyindex0_.name=? limit ?

(3)支持级联查询,但是若果当前类有符合条件的属性,则优先类属性忽略级联属性。若需要使用级联属性则属性之间用‘_’进行连接。
例如

class Person{
	private Integer addressId;
	private Address address;
	//setter方法
	@Column(name="ADD_ID")
	public int getAddressId(){
		return addressId;
	}
	//其他getter方法
}
class Address{
	//..
	private Integer id;
}

当请求:

List<Person> getByAddressIdGreaterThan(Integer id);//会请求Person类中的addressId属性而不是级联属性。

如果需要使用级联属性:

List<Person> getByAddress_IdGreaterThan(Integer id);

4、SpringData @Query注解
(1)使用@Query注解可以自定义JPQL语句以实现更灵活的查询.
(2)@Query注解传递参数的方式1:使用占位符
例:

@Query("Select p FROM Person p WHERE p.lastName = ?1 AND p.email = ?2")
List<Person> testQueryAnnotationParams1(String lastName,String email);//参数需按照1.2...顺序

(3)@Query注解传递参数的方式2:命名参数
例:

@Query("Select p FROM Person p WHERE p.lastName = :lastName AND p.email = :email")
List<Person> testQueryAnnotationParams1(@Param("email")String email,@Param("lastName")String lastName);//这时参数的顺序不影响,只需参数名跟‘:’后一致就可以。

:SpringData允许占位符上添加%%
A、方式1:

@Query("Select p FROM Person p WHERE p.lastName LIKE %?1% OR p.email LIKE %?2%")
List<Person> testQueryAnnotationParams1(String lastName,String email);//参数需按照1.2...顺序

B、方式2:

@Query("Select p FROM Person p WHERE p.lastName LIKE %:lastName% OR p.email LIKE %:email%")
List<Person> testQueryAnnotationParams1(@Param("email")String email,@Param("lastName")String lastName);//这时参数的顺序不影响,只需参数名跟‘:’后一致就可以。

(4)设置nativeQuery=true即可使用原生的SQL查询
例:

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

5、SpringData @Modifying注解
(1)可以通过自定义的JPQL完成UPDATE、和DELETE操作。注意:JPQL不支持INSERT
(2)在@Query中编写JPQL语句,但必须使用@Modifying进行修饰(通知SpringData这是一个UPDATE或DELETE操作)。
(3)UPDATE或DELETE操作需要使用事务,此时需要在Service层上面添加事务操作。
(4)默认情况下,SpringData的每个方法上都有事务,但是一个只读事务,它们不足以完成修改删除操作。
例:

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

6、JpaRepository接口