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中的表對于關系一樣,一對多的情況下使用的是延遲加載,對一的情況使用立即加載