快速入门spring-data-jpa,接口方法详解

时间:2022-09-11 16:31:11
一.spring-data简介

1.概括:

      spring家族中的一员,用来简化构建基于 Spring 框架应用的数据访问,包括关系型数据库,非关系型数据库、Map-Reduce 框架、云数据服务等等的访问支持


2.主要子项目:
Spring Data Commons----------------Core Spring概念支持每个Spring Data项目
Spring Data Gemfire------------------提供从Spring应用程序轻松配置和访问GemFire
Spring Data JPA-----------------------使其易于实现基于JPA的存储库(JPA 简化 DAO 的编写)
Spring Data KeyValue-----------------基于映射的存储库和SPI,可轻松构建一个用于键值存储的Spring数据模块
Spring Data LDAP---------------------为Spring LDAP提供Spring数据存储库支持
spring Data MogoDB-----------------MongoDB是基于Spring的对象文档支持和存储库
Spring Data REST----------------------将Spring数据存储库导出为超媒体驱动的RESTful资源
Spring Data Redis---------------------提供从Spring应用程序轻松配置和访问Redis
Spring Data for Apache Cassandra---Apache Cassandra的Spring数据模块
Spring Data Apache Solr--------------Apache Solr的Spring数据模块

上面是我对官网英语的小部分翻译,了解更多可以进入下面的官网地址查看
网址:http://projects.spring.io/spring-data-jpa/
其实spring data就是为我们提供一种编码格式,规范我们的API

3.所属jar包:
spring-data-commons:一套标准API
          包括:Repository,CrudRepository,PagingAndSortingRespsitory
spring-data-jpa:基于整合JPA的实现
          包括:JpaRepository,JpaSpecificationExcutor

二.使用spring-data-jpa的环境配置


1.maven坐标:

其他maven坐标没有写出,只写出了整合jpa需要的坐标

<!-- spring data jpa 数据库持久层 -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.9.0.RELEASE</version>
</dependency>

2.applicationContext-dataSource.xml配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}" />
<property name="jdbcUrl" value="${jdbc.url}" />

<property name="user" value="${jdbc.user}" />
<property name="password" value="${jdbc.password}" />
</bean>

<!-- 整合JPA配置 -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.yl.website.pojo" />
<property name="persistenceProvider">
<bean class="org.hibernate.jpa.HibernatePersistenceProvider" />
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true" />
<property name="database" value="MYSQL" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
<property name="showSql" value="true" />
</bean>
</property>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
<property name="jpaPropertyMap">
<map>
<entry key="hibernate.query.substitutions" value="true 1, false 0" />
<entry key="hibernate.default_batch_fetch_size" value="16" />
<entry key="hibernate.max_fetch_depth" value="2" />
<entry key="hibernate.generate_statistics" value="true" />
<entry key="hibernate.bytecode.use_reflection_optimizer" value="true" />
<entry key="hibernate.cache.use_second_level_cache" value="false" />
<entry key="hibernate.cache.use_query_cache" value="false" />
</map>
</property>
</bean>

<!-- JPA事务管理器 -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

<!-- 注解管理事务 -->
<tx:annotation-driven transaction-manager="transactionManager"/>

<!-- 整合spring data jpa -->
<jpa:repositories base-package="com.yl.website.dao" />
</beans>

3.applicationContext.xml配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

<!-- 扫描 @Server @Controller @Repository -->
<context:component-scan base-package="com.yl"/>

<!-- 加载properties文件 -->
<context:property-placeholder location="classpath:config.properties" />

<!-- 引入外部数据文件 -->
<import resource="applicationContext-dataSource.xml"/>

</beans>

4.config.properties配置:

jdbc.url = jdbc:mysql://localhost:3306/yl_web
jdbc.driver= com.mysql.jdbc.Driver
jdbc.user = root
jdbc.password = root

三.Repository接口详解


Repository接口的继承体系结构:

快速入门spring-data-jpa,接口方法详解

1.Repository:空接口,标记接口(没有包含方法声明的接口)
1)Repository接口是Spring Data的核心接口,不提供任何方法
      不需要对 DAO 接口做任何实现, 实际上 spring 会调用 SimpleJpaRepository 实现
2)T是实体类的名字,ID是实体类中的ID的类型:

public interface Repository<T, ID extends Serializable> {

}

      只要继承这个接口,spring就会把该接口纳入spring去管理

3)如果不继承就会报错,但是可以使用@RepositoryDefinition(domainClass = 实体类.class,idClass = 实体类中

     id的类型.class)可以代替继承

4)Repository查询方法遵循命名规则(自动生成查询语句):

快速入门spring-data-jpa,接口方法详解

快速入门spring-data-jpa,接口方法详解
举例:

public interface StudentRepotory  extends Repository<Student,Integer>{  

//where name = ?
Student findByName(String name);

//Where name like ?%
List<Student> findByNameLike(String name)


//Where lastName like ?% and id<?
List<Student> getByLastNameEndingWithAndIdLessThan(String lastName,Integer id);

//where username = ? and password = ?
Student findByUsernameAndPassword(String username,String password);

}

5)Repository查询方法不遵循命名规则(配置@Query绑定JAPL语句或者SQL语句查询):

   只需要把@Query定义在Repository中的方法名之上

public interface StudentRepotory  extends Repository<Student,Integer>{  

@Query("select o from Student o where o.name=?1 and 0.age=?2")
List<Student> queryStudent1(String name,Integer age);

@Query("select o from Student o where o.name=:name and 0.age=:age")
List<Student> queryStudent2(@Param("name")String name,@Param("age")Integer age);

@Query("select o from Student o where o.name like %?1%")
List<Student> queryStudentLike1(String name);

 @Query("select o from Student o where o.name like %:name%")
List<Student> queryStudentLike2(@Param("name")String name);

@Query("select o from Student o where id=(select min(id) from Stduent t1)")
Student getStudentMinId();

//nativeQuery为false配置的是JPQL,为true配置的是SQL
@Query(nativeQuery = true ,value = "select count(1) from student")
long getCount1();

@Query(nativeQuery = false ,value = "from Student where name =?")
List<Student> queryName(String name);
}

6)Repository查询方法不遵循命名规则(配置@Query 没写语句 ):

    配置@Query定义在Repository中的方法名之上,实体类 上@NamedQuery 定义

//Dao层:

@Query
public List<Student> queryName(String name);

//实体类:

@NameQueries({
@NamedQuery(name="Student.queryName",query="from Student where name=?")})
public class Student{
实体类对象
}

7)Repository带有条件的修改和删除操作:

   使用@Query 注解 , 搭配使用@Modifying 标记是修改、删除操作

//将id为?1的最大长度改为?2
@Query(value="update Standard set maxLength=?2 where id =?1")
@Modifying
public List<Student> updateMaxLength(Integer id,Tnteger maxLength);

2. CrudRepository:继承Repository接口,实现了基本增删改查的方法
1)常用方法:
                save(entity),save(entities):保存一个实体对象或多个实体对象
                findOne(id):根据id找到一个实体对象
                exists(id):根据id判断一个实体对象是否存在
                findAll():找到所有的实体对象
                delete(id),delete(entity),delete(entities),deleteAll():根据id,一个实体对象,很多实体对象来删除实体,或者删除全部的实体

2)通过save方法来举例,其他方法的使用方法类似:

//Dao层:

public interface SidebarRepository extends CrudRepository<StudentsInf, Integer> {

}

//Service接口:

public interface SidebarService {

void save(StudentsInf studentsInf);

}

//Service实现类:

@Service
@Transactional
public class SidebarServiceImpl implements SidebarService {

@Autowired
private SidebarRepository sidebarRepository;

@Override
public void save(StudentsInf studentsInf) {
sidebarRepository.save(studentsInf);
}

}

//controller层:

@Controller
public class SidebarController {

@Autowired
private SidebarService sidebarService;

@RequestMapping("/studentSave")
public String save(StudentsInf studentsInf) {
sidebarService.save(studentsInf);
return "studentSave"
}

}

3.PagingAndSortingRespsitory:继承了CrudRepository接口,实现了分页排序的方法

       带排序的查询:findAll(Sort sort)
                           (查询全部,并传入排序的字段Sort)
       带排序的分页查询:findAll(Pageable pageable)
                            (需要分页,就必须传入一个可以分页的对象Pageable)

分页举例:

//Contorller层
@Controller
public class TeacherController {

@Autowired
private TeacherService teacherService;

@RequestMapping("/teacherShow")
public String studentIntroduce(Integer page,Integer size){
Page<Teacher> teacherPage = teacherService.getTeacherList(page,size);
System.out.println("总页数:"+teacherPage.getTotalPages());
System.out.println("总记录数:"+teacherPage.getTotalElements());
System.out.println("当前第几页:"+(teacherPage.getNumber()+1));
System.out.println("当前页面的集合"+teacherPage.getContent());
System.out.println("当前页面的记录数"+teacherPage.getNumberOfElements());
return "teacherShow";
}
}


//Service层
public interface TeacherService {

Page<Teacher> getTeacherList(Integer page,Integer size);

}

//ServiceImp层
@Service
@Transactional
public class TeacherServiceImpl implements TeacherService {

@Autowired
private TeacherRepository teacherRepository;

//分页
@Override
public Page<Teacher> getTeacherList(Integer page,Integer size) {
//page是基于0开始的页数,size是每页显示多少条
//page的index是从0开始的,不是从1开始的
Pageable pageable = new PageRequest(page, size);
Page<Teacher> teacherPage = teacherRepository.findAll(pageable);
return teacherPage;
}

}

//Dao层
public interface TeacherRepository extends PagingAndSortingRepository<Teacher, Integer> {

}

排序举例:

//Contorller层
@Controller
public class TeacherController {

@Autowired
private TeacherService teacherService;

@RequestMapping("/teacherShow")
public String studentIntroduce(Integer page,Integer size){

Page<Teacher> teacherPage = teacherService.getTeacherList(page,size);

return "teacherShow";
}
}


//Service层
public interface TeacherService {

Page<Teacher> getTeacherList(Integer page,Integer size);

}

//ServiceImp层
@Service
@Transactional
public class TeacherServiceImpl implements TeacherService {

@Autowired
private TeacherRepository teacherRepository;

//分页+排序
@Override
public Page<Teacher> getTeacherList(Integer page,Integer size) {
//排序(根据id降序排)
Sort.Order order = new Sort.Order(Sort.Direction.DESC,"id")
Sort sort = new Sort(order);
//分页
Pageable pageable = new PageRequest(page, size,sort);
Page<Teacher> teacherPage = teacherRepository.findAll(pageable);
return teacherPage;
}

}

//Dao层
public interface TeacherRepository extends PagingAndSortingRepository<Teacher, Integer> {

}

4.JpaRepository:继承PagingAndSortingRespsitory接口,通过JPA规范实现了扩展的增删该查,批量操作的方法

               findAll():找到所有的实体对象
               findAll(Sort sort):找到所有的实体对象并且进行排序
               save(entities):保存多个实体对象
               flush():客户端对实体类中数据的任何改变和手写的任何SQL都是保存在客户端的内存当中,
                          只有执行flush()后,对数据库的修改就发送到数据库服务器端的数据高速缓冲区,而非数据文件中
               deleteInBatch(entities):这个批次里面删除哪些实体
   和CrudRepository中的举例是一样的,参照上面的方法就可以了,这里不再举例

   总结:

          JpaRepository继承PagingAndSortingRepository,PagingAndSortingRepository又继承 

    CrudRepository,CrudRepository又继承了Repository,总的来说,我们平时在开发中只要继承JpaRepository接口,父接口有

    的方法它都有,就相当于拥有了增删查改,分页排序等功能

5. JpaSpecificationExcutor:没有继承Repository或者他的子接口,它不属于前面接口的子接口,只是通过JPA规范

   实现了查询的方法

          (Specification是Spring Data JPA提供的一个查询规范,要做复杂的查询,类使hibernate的QBC查询)

举例:

//Contorller层
@Controller
public class TeacherController {

@Autowired
private TeacherService teacherService;

@RequestMapping("/teacherShow")
public String studentIntroduce(Integer page,Integer size){

Page<Teacher> teacherPage = teacherService.getTeacherList(page,size);
return "teacherShow";
}
}


//Service层
public interface TeacherService {

Page<Teacher> getTeacherList(Integer page,Integer size);

}

//ServiceImp层
@Service
@Transactional
public class TeacherServiceImpl implements TeacherService {

@Autowired
private TeacherRepository teacherRepository;

//分页+排序
@Override
public Page<Teacher> getTeacherList(Integer page,Integer size) {
//排序(根据id降序排)
Sort.Order order = new Sort.Order(Sort.Direction.DESC,"id")
Sort sort = new Sort(order);
//分页
Pageable pageable = new PageRequest(page, size,sort);
//查询
/*
*root:就是我们要查询的类型(Teacher)
*query:添加查询的条件
*cb:构建Predicate
*/
Specification<Teacher> specification = new Specification<Teacher>(){
@Override
public Predicate toPredicate(Root<Teacher> root,
CriteriaQuery<?> query,
CriteriaBuilder cb){
//path可以获取到age属性的路径,相当于root基面包含teacher,teacher里面包含age
Path path = root,get("age");
//gt代表大约,表示的是返回大约30岁的
return cb.get(path,30);
}
};
Page<Teacher> teacherPage = teacherRepository.findAll(specification,pageable);
return teacherPage;
}

}

public interface TeacherRepository extends JpaRepository<Teacher, Integer>,
JpaSpecificationExecutor<Teacher> {

}

但是本人觉得这样写还不如自己直接写sql语句来的更快,看到大家自己的喜好选择


PS:

       这是本人对spring-data-jpa的部分见解,还有许多不足的地方,有好的意见,欢迎留言一起讨论