一、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接口