Spring Data JPA概述:
基本:封装了JPA规范的框架
极大的简化了数据库访问层代码,SpringDataJpa我们的Dao层只需要写接口,就自动有了增删改查、分页查询等方法;
特性:
- 提供统一的接口,可避免我们再次重复编写基础的DAO类
- 遵循JPA规范,同时也提供了灵活的数据访问方式;
- 通过方法名即可自动生成HQL语句;
- 通过接口自动注入实现类,实现非常简单
Spring Data JAP 和JPA规范和hibernate的关系:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cs0TPn5EMnRVTwkFROBDOsJGcohVYsR2MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLwQzN0ATNxgTM1EzNwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
JPA是一套具有ORM思想的规范,内部是抽象类和接口组成的。Hibernate是一套成熟的ORM框架,并且实现了JPA规范,Hibernate是JPA的一种实现方式;
SpringDataJPA是Spring提供一套对JPA操作更高级的封装,是在JPA规范下的专门用来进行数据的持久化操作的
Spring Data JPA入门操作:
搭建环境
需要配置Spring的配置文件(配置Spring Data 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和Spring Data JPA的配置-->
<!--数据库的配置-->
<bean id="ds" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="jdbcUrl" value="jdbc:mysql:///xxxx"></property>
<property name="driverClass" value="com.mysql.jdbc.driver"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<!--实体管理
需要数据库配置、扫描对应的实体包、JPA实现的厂家、高级特性 JPA方言 默认具有HibernateJPADialect的特性
-->
<bean id="enetityManagerFactory class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean>
<!--数据库-->
<property name="datasource" ref="ds"></property>
<!--扫描的包-->
<property name="packagesToScan" value="com.xxx.domain"></property>
<!--JPA实现的厂家-->
<property name="persistenceProvider" class="org.hibernate.jpa.HibernatePersistenceProvider"></property>
<!--JPA的供应商适配器-->
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<!--是否创建表-->
<property name="generatedDdl" value="false"></property>
<!--使用的数据库配置-->
<property name="database" value="MYSQL"></property>
<!--数据库方言-->
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"></property>
<!--展示sql语句-->
<property name="showSQL" value="true"></property>
</bean>
</property>
<perperty name="JpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"></bean>
</perperty>
</bean>
<!--总的整合Spring Data JPA-->
<jpa:repositories base-package="com.xxx.dao" transcation-mamnager-ref="transactionManager" entity-Manager-factory-ref="entityManagerFactory"></jpa:repositories>
<!--事务配置 使用JPA操作数据库 就使用JPA的事务-->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"></property>
</bean>
<!--Spring的声明式事务-->
<!--开启配置扫描包 -->
<context:component-scan base-package="com.xxx"></context:component-scan>
</beans>
实体类且JPA注解完成映射关系
//实体类
@Entity //声明实体类
@Table(name="cst_customer") //建立实体类和表的映射关系
public class Customer {
@Id//声明当前私有属性为主键
@GeneratedValue(strategy= GenerationType.IDENTITY) //配置主键的生成策略
@Column(name="cust_id") //指定和表中cust_id字段的映射关系
private Long custId;
@Column(name="cust_name") //指定和表中cust_name字段的映射关系
private String custName;
@Column(name="cust_source")//指定和表中cust_source字段的映射关系
private String custSource;
@Column(name="cust_industry")//指定和表中cust_industry字段的映射关系
private String custIndustry;
@Column(name="cust_level")//指定和表中cust_level字段的映射关系
private String custLevel;
@Column(name="cust_address")//指定和表中cust_address字段的映射关系
private String custAddress;
@Column(name="cust_phone")//指定和表中cust_phone字段的映射关系
private String custPhone;
编写一个符合Spring Data Jpa的Dao层接口
//dao接口 不需要实现类只需要接口
public interface CustomerDao extends JpaRepository<Customer,Long>, JpaSpecificationExecutor<Customer>{
}
//有规范
//继承两个接口
1.JpaRepository:封装了基本的CRUD操作
参数:实体类和对应主键的类型
2.JpaSpecificationExecutor:封装了复杂操作(分页查询等等)
参数:实体类
Spring Data JPA的CURD:
- findOne()
Customer one = customerDao.findOne(2l); System.out.println(one); //打印的日志信息 //给每一个表起了别名 核心操作还是select * from xxx where id=? select customer0_.cust_id as cust_id1_0_0_, customer0_.cust_address as cust_add2_0_0_, customer0_.cust_industry as cust_ind3_0_0_, customer0_.cust_level as cust_lev4_0_0_, customer0_.cust_name as cust_nam5_0_0_, customer0_.cust_phone as cust_pho6_0_0_, customer0_.cust_source as cust_sou7_0_0_ from cst_customer customer0_ where customer0_.cust_id=? //执行操作返回的结果 Customer{custId=2, custName='3', custSource='4', custIndustry='4', custLevel='4', custAddress='3', custPhone='4'}
- save():此方法针对于保存实体和更新实体,判断依据是根据提交的主键进行判断,具有主键则是修改
- delete方法()
Spring Data JPA的运行过程和原理剖析:
接口不发挥作用,实际是接口的实现类,接口在执行的过程中动态的生成了实现类对象
使用的动态代理实现创建实现类对象
Spring内部借助JdkDynamicAopProxy创建创建了一个叫SimpleJpaRepository对象 ,
此实现了JpaRepository接口和JpaSpecificationExecutor接口,所以就是此对象进行实现操作
然后使用JPA的实现框架Hibernate去操作数据库
JPSQL的查询方式
JPA Query Language 查询的是类和类中的属性
没有SQL语句的select *操作
- 需要將JPQL语句配置到接口的方法上
- 特有的查询:需要在dao接口上配置方法
- 在新添加的方法上,使用注解的方式配置JPQL查询语句**@Query** 结合Mybatis注解配置的@Select等等
-
@Query(value = "from Customer where custName = ? ") public Customer findByName(String name);
- 多占位符的赋值
- 根据名称和id查询实体:占位符需要和参数相同(默认方式) 可以改变问号占位符和参数的位置,只需要在占位符后面说明第几个就可以(一般没必要)
-
@Query(value = "from Customer where custName = ? and custId = ?") public Customer findByNameId(String name,Long id);
-
//顺序可变 在?之后写位置 @Query(value = "from Customer where custName = ?2 and custId = ?1") public Customer findByNameId(String name,Long id);
-
- 根据名称和id查询实体:占位符需要和参数相同(默认方式) 可以改变问号占位符和参数的位置,只需要在占位符后面说明第几个就可以(一般没必要)
- 完成更新操作
-
id更新名称
@Query是查询操作,更新和删除操作需要新注解@Modfing,在修改的方法上面添加;而且还需要手动在测试方法上加入@Transactional注解添加事务的支持,且默认会手动执行完毕回滚事务,所以要加上@Rollback注解设置自动回滚为false
-
@Query(value = "update Customer set custName=? where custId = ?") @Modifying public void updateById(String name,Long id); @Test @Transactional//添加事务 @Rollback(value = false)//设置自动回滚操作为false public void test() { customerDao.updateById("2",2l); }
-
-
- JPQL里的SQL语句的查询 使用sql查询是一个装有Object数组的集合 在JPQL语句中使用SQL语句
- nativeQuery属性:false(默认值,不适应本地查询,使用JPQL查询)|true(使用本地查询,sql查询)
-
//下面展示的是基本查询和一个like的模糊查询 @Query(value = "select * from cst_customer",nativeQuery = true) //条件查询 //@Query(value = "select * from cst_customer where cust_name like ?",nativeQuery = true) public List<Object []> UseSqlFindAll(); //public List<Object []> UseSqlFindAll(String name); //List<Object[]> list = customerDao.UseSqlFindAll("xxx"); List<Object[]> list = customerDao.UseSqlFindAll(); for (Object[] object : list) { System.out.println(Arrays.toString(object)); }
- 方法名称规则查询
- 是对JPQL查询更加深层的封装,只需要SpringDataJpa提供的方法名称规则定义方法,不需要配置jpql就可以完成查询
- 命名规则
- findBy:代表查询
- 对象的属性名(首字母大写):查询的条件 例如 :findByCustName
- SpringDataJpa运行时会解析 findBy from xxx(实体类) 属性名 where custName = ?
-
//只需要写方法即可查询出来 public Customer findByCustName(String name); //Customer{custId=1, custName='2', custSource='2', custIndustry='aa', custLevel='2', custAddress='a', custPhone='2'}
- 模糊匹配 上述基础上继续添加 例如 findByCustNameLike
- 多条件匹配 findByCustNameLikeAndCustAddressAndCustPhone 参数顺序保持一致
-
public List<Customer> findByCustNameLikeAndCustAddressAndCustPhone(String name,String address,String phone); List<Customer> byCustNameLikeAndCustAddressLikeCustPhone = customerDao.findByCustNameLikeAndCustAddressAndCustPhone("%shi%", "xiao", "sanzu"); for (Customer customer : byCustNameLikeAndCustAddressLikeCustPhone) { System.out.println(customer); }
-
- findBy:代表查询
Spring Data JPA中的复杂查询:
- 借助接口定义好的方法完成查询
- findOne()方法
- findOne()方法和GetOne()方法的区别
- 单元测试getOne方法,需要加入@Transactional注解保证方法正常运, SimpleJpaRepository调用em.GetReference方法,延迟加载,返回动态代理对象,什么时候用,什么时候查
- findOne方法:SimpleJpaRepository使用的是em.find方法 ,立即加载
- 类似和Mybatis中的表对于关系一样,一对多的情况下使用的是延迟加载,对一的情况使用立即加载