概述:
Spring Data Jpa是Spring基于ORM框架、JPA规范的基础上封装的一套JPA应用框架,可使开发者用极简的代码实现对数据库的访问和操作。
依赖:
<properties>
<spring.version>4.2.4.RELEASE</spring.version>
<hibernate.version>5.0.7.Final</hibernate.version>
<slf4j.version>1.7.30</slf4j.version>
<log4j.version>2.12.1</log4j.version>
<c3p0.version>0.9.1.2</c3p0.version>
<mysql.version>8.0.16</mysql.version>
</properties>
<dependencies>
<!-- junit单元测试 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- spring beg -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.8</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- spring end -->
<!-- hibernate beg -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.1.Final</version>
</dependency>
<!-- hibernate end -->
<!-- c3p0 beg -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>${c3p0.version}</version>
</dependency>
<!-- c3p0 end -->
<!-- log end -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- log end -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.9.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- el beg 使用spring data jpa 必须引入 -->
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>2.2.4</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>javax.el</artifactId>
<version>2.2.4</version>
</dependency>
<!-- el end -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
</dependencies>
重要依赖:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.9.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.3.6.Final</version>
</dependency>
配置文件:beans,context,tx,jpa
<?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">
<!--spring data jpa的配置-->
<!--创建EntityManagerFactory对象交给容器来管理-->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<!--配置数据源-->
<property name="dataSource" ref="dataSource"/>
<!--配置实体类的扫描包-->
<property name="packagesToScan" value="com.hzp.entity"/>
<!--Jpa的实现厂家-->
<property name="persistenceProvider">
<bean class="org.hibernate.jpa.HibernatePersistenceProvider"/>
</property>
<!--Jpa的供应商适配器-->
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<!--配置是否自动创建数据库表-->
<property name="generateDdl" value="false"/>
<!--指定数据库的类型-->
<property name="database" value="MYSQL"/>
<!--指定方言,独有的语法-->
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"/>
<!--显示sql-->
<property name="showSql" value="true"/>
</bean>
</property>
<!--Jpa的方言:高级特性-->
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
</property>
</bean>
<!--数据源-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="user" value="root"/>
<property name="password" value="123456"/>
<property name="jdbcUrl" value="jdbc:mysql:///jpa"/>
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
</bean>
<!--整合Spring Data Jpa-->
<!--
base-package指定dao接口所在的包
-->
<jpa:repositories base-package="com.hzp.dao" transaction-manager-ref="transactionManager"
entity-manager-factory-ref="entityManagerFactory"/>
<!--事务管理器-->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<!--声明式事务-->
<!--包扫描-->
<context:component-scan base-package="com.hzp"/>
</beans>
编写符合Spring Data Jpa的dao接口
/**
* 符合Spring Data Jpa的接口
* 1、继承JpaRepository接口,它需要两个泛型,第一个是实体类类型,第二个是实体类主键属性的类型
* 封装了基本的CRUD
* 2、继承JpaSpecificationExecutor接口,它需要一个泛型,表示实体类类型
* 封装了复杂查询(分页)
*/
//Repository 标记接口
//@RepositoryDefinition(domainClass = Employee.class,idClass = Integer.class)
public interface EmployeeRepository extends Repository <Employee,Integer>{
public Employee findByName(String name);
}
测试:
public class EmployeeRepositoryTest {
private ApplicationContext ctx = null;
private EmployeeRepository employeeRepository;
@Before
public void setup(){
ctx= new ClassPathXmlApplicationContext("beans.xml");
ctx.getBean(EmployeeRepository.class);
System.out.println("setup");
}
@After
public void tearDown(){
ctx=null;
System.out.println("tearDown");
}
@Test
public void testFindByName(){
Employee zhangsan = employeeRepository.findByName("zhangsan");
System.out.println(zhangsan.getId()+":"+zhangsan.getName()+":"+zhangsan.getAge());
}
}
查询方法定义规则和使用:
@RepositoryDefinition(domainClass = Employee.class,idClass = Integer.class)
public interface EmployeeRepository{
public List<Employee> findByNameStartingWithAndAgeLessThan(String name,Integer age);
}
测试:
@Test
public void testFindByNameStartingWithAndAgeLessThan(){
List<Employee> employees = employeeRepository.findByNameStartingWithAndAgeLessThan("test", 22);
for (Employee employee : employees) {
System.out.println(employee);
}
}
查询注解:@Query
@RepositoryDefinition(domainClass = Employee.class,idClass = Integer.class)
public interface EmployeeRepository{
@Query("select o from Employee o where id=(select max(id) from Employee t1)")
public Employee getEmployeeByMaxId();
//占位符,索引参数
@Query("select o from Employee o where o.name = ?1 and o.age = ?2")
public List<Employee> queryParams1(String name,Integer age);
//命名参数
@Query("select o from Employee o where o.name = :name and o.age = :age")
public List<Employee> queryParams2(@Param("name") String name, @Param("age")Integer age);
@Query("select o from Employee o where o.name like %?1% ")
public List<Employee> queryLike1(String name);
@Query("select o from Employee o where o.name like %:name% ")
public List<Employee> queryLike1(@Param("name")(String name);
//原生态查询
@Query(nativeQuery = true,value = "select count(1) from employee")
public long getCount();
}
测试:
@Test
public void testGetEmployeeByMaxId(){
Employee employee = employeeRepository.getEmployeeByMaxId();
}
@Test
public void testQueryParams1(){
List<Employee> employees = employeeRepository.queryParams1("zhangsan", 21);
for (Employee employee : employees) {
System.out.println(employee);
}
}
@Test
public void testQueryParams2(){
List<Employee> employees = employeeRepository.queryParams1("zhangsan", 21);
for (Employee employee : employees) {
System.out.println(employee);
}
}
@Test
public void testQueryLike1(){
List<Employee> employees = employeeRepository.queryLike1("test");
for (Employee employee : employees) {
System.out.println(employee);
}
}
更新删除整合事务
@Modifying结合@Query注解执行更新操作
@RepositoryDefinition(domainClass = Employee.class,idClass = Integer.class)
public interface EmployeeRepository{
@Query("update Employee o set o.age=:age where o.id=:id")
@Modifying//允许修改
public void update(@Param("id")Integer id,@Param("age")Integer age);
}
编写service层事务
@Service
public class EmployeeService {
@Autowired
private EmployeeRepository employeeRepository;
@Transactional
public void update(Integer id,Integer age){
employeeRepository.update(id,age);
}
}
测试:
@RunWith(SpringJUnit4ClassRunner.class) //使用junit4进行测试
@ContextConfiguration(locations = {"classpath:beans.xml"}) //加载配置文件
public class EmployeeServiceTest {
@Autowired
EmployeeService employeeService;
@Before
public void setup(){
System.out.println("setup");
}
@After
public void tearDown(){
System.out.println("tearDown");
}
@Test
public void testUpdate(){
employeeService.update(1,55);
}
}
CrudRepository接口
Repository
public interface EmployeeCrudRepository extends CrudRepository <Employee,Integer>{
}
Service
@Service
public class EmployeeService {
@Autowired
private EmployeeCrudRepository employeeCrudRepository;
@Transactional
public void save(List<Employee> employees){
employeeCrudRepository.saveAll(employees);
}
}
测试:
public class EmployeeCrudRepositoryTest {
private ApplicationContext ctx = null;
private EmployeeService employeeService=null;
@Before
public void setup(){
ctx= new ClassPathXmlApplicationContext("beans.xml");
employeeService = ctx.getBean(EmployeeService.class);
System.out.println("setup");
}
@After
public void tearDown(){
ctx=null;
System.out.println("tearDown");
}
@Test
public void testFindByName(){
ArrayList<Employee> employees = new ArrayList<Employee>();
Employee employee=null;
for (int i =0;i<100;i++){
employee = new Employee();
employee.setName("test"+i);
employee.setAge(100-i);
employees.add(employee);
}
employeeService.save(employees);
}
}
PagingAndSortingRespository接口使用详解
1.该接口包含分页和排序的功能
2.带排序的查询: findAll(Sort sort)
3.带排序的分页查询: findAll(Pageable pageable)
public interface EmployeePagingAndSortingRepository extends PagingAndSortingRepository<Employee,Integer> {
}
public class EmployeePagingAndSortingRepositoryTest {
private ApplicationContext ctx = null;
private EmployeePagingAndSortingRepository employeePagingAndSortingRepository=null;
@Before
public void setup(){
ctx= new ClassPathXmlApplicationContext("beans.xml");
employeePagingAndSortingRepository = ctx.getBean(EmployeePagingAndSortingRepository.class);
System.out.println("setup");
}
@After
public void tearDown(){
ctx=null;
System.out.println("tearDown");
}
@Test
public void testPage(){
//page index从0开始
Pageable pageable=PageRequest.of(0,5);
Page <Employee> page= employeePagingAndSortingRepository.findAll(pageable);
System.out.println("查询的总页数" + page.getTotalPages()) ;
System.out.println("查询的总记录数" + page.getTotalElements());
System.out.println("查询的当前第几页" + page.getNumber()+1) ;
System.out.println("查询的当前页面的集合" + page.getContent());
System.out.println("查询的当前页面的记录数" + page.getNumberOfElements());
}
@Test
public void testPageAndSort(){
//根据id降序排
Sort.Order order = new Sort.Order(Sort.Direction.DESC, "id");
//springboot2.2.1(含)以上的版本Sort已经不能再实例化了,构造方法已经是私有的了!
Sort sort =Sort.by(order);
//page index从0开始
Pageable pageable=PageRequest.of(0,5,sort);
Page <Employee> page= employeePagingAndSortingRepository.findAll(pageable);
System.out.println("查询的总页数" + page.getTotalPages()) ;
System.out.println("查询的总记录数" + page.getTotalElements());
System.out.println("查询的当前第几页" + page.getNumber()+1) ;
System.out.println("查询的当前页面的集合" + page.getContent());
System.out.println("查询的当前页面的记录数" + page.getNumberOfElements());
}
}
JpaRepository
public interface EmployeeJpaRepository extends JpaRepository<Employee,Integer> {
}
@Test
public void testFind(){
Optional<Employee> employee = employeeJpaRepository.findById(99);
boolean existsById = employeeJpaRepository.existsById(50);
System.out.println(employee);
System.out.println(existsById);
}
JpaSpecificationExecutor
封装了JPA Criteria查询条件
需要子类是现实的主要方法是 toPredicate
Root var1: 代表了可以查询和操作的实体对象的根,如果将实体对象比喻成表名,那root里面就是这张表里面的字段,是JPQL的实体字段,通过Pathget(String var0)来获得操作的字段
CriteriaQuery<?> var2: 代表一个specific的顶层查询对象,它包含着查询的各个部分,如: select、form、where、group by、order by 等,它提供了查询var1的的方法,常用的有 where、select、having
CriteriaBuilder var3: 用来构建CriteriaQuery的构建器对象Predicate ,其实就相当于条件或条件组合
public interface EmployeeJpaSpecificationExecutor
extends JpaRepository<Employee,Integer>, JpaSpecificationExecutor<Employee>{
}
public class EmployeeJpaSpecificationExecutorTest {
private ApplicationContext ctx = null;
private EmployeeJpaSpecificationExecutor employeeJpaSpecificationExecutor=null;
@Before
public void setup(){
ctx= new ClassPathXmlApplicationContext("beans.xml");
employeeJpaSpecificationExecutor = ctx.getBean(EmployeeJpaSpecificationExecutor.class);
System.out.println("setup");
}
@After
public void tearDown(){
ctx=null;
System.out.println("tearDown");
}
@Test
public void testPageAndSort(){
//根据id升序排
Sort.Order order = new Sort.Order(Sort.Direction.ASC, "id");
//springboot2.2.1(含)以上的版本Sort已经不能再实例化了,构造方法已经是私有的了!
Sort sort =Sort.by(order);
//page index从0开始
Pageable pageable= PageRequest.of(0,5,sort);
//Predicate查询条件 ,年龄大于50
Specification<Employee> specification = new Specification<Employee>(){
@Override
public Predicate toPredicate(Root<Employee> root,
CriteriaQuery<?> criteriaQuery,
CriteriaBuilder criteriaBuilder) {
//root(Employee(age))
Path path = root.get("age");
return criteriaBuilder.gt(path,50);
}
};
Page<Employee> page= employeeJpaSpecificationExecutor.findAll(specification,pageable);
System.out.println("查询的总页数" + page.getTotalPages()) ;
System.out.println("查询的总记录数" + page.getTotalElements());
System.out.println("查询的当前第几页" + page.getNumber()+1) ;
System.out.println("查询的当前页面的集合" + page.getContent());
System.out.println("查询的当前页面的记录数" + page.getNumberOfElements());
}
}