天天看點

Spring Data JPA學習(2.0)

Spring Data JPA概述:

​ 基本:封裝了JPA規範的架構

​ 極大的簡化了資料庫通路層代碼,SpringDataJpa我們的Dao層隻需要寫接口,就自動有了增删改查、分頁查詢等方法;

​ 特性:

  • 提供統一的接口,可避免我們再次重複編寫基礎的DAO類
  • 遵循JPA規範,同時也提供了靈活的資料通路方式;
  • 通過方法名即可自動生成HQL語句;
  • 通過接口自動注入實作類,實作非常簡單
Spring Data JAP 和JPA規範和hibernate的關系:
Spring Data JPA學習(2.0)

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:
  1. 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'}
               
  2. save():此方法針對于儲存實體和更新實體,判斷依據是根據送出的主鍵進行判斷,具有主鍵則是修改
  3. ​ delete方法()
Spring Data JPA的運作過程和原理剖析:

接口不發揮作用,實際是接口的實作類,接口在執行的過程中動态的生成了實作類對象

​ 使用的動态代理實作建立實作類對象

Spring Data JPA學習(2.0)

Spring内部借助JdkDynamicAopProxy建立建立了一個叫SimpleJpaRepository對象 ,

此實作了JpaRepository接口和JpaSpecificationExecutor接口,是以就是此對象進行實作操作

然後使用JPA的實作架構Hibernate去操作資料庫

Spring Data JPA學習(2.0)

JPSQL的查詢方式

JPA Query Language 查詢的是類和類中的屬性

沒有SQL語句的select *操作

  1. 需要將JPQL語句配置到接口的方法上
    1. 特有的查詢:需要在dao接口上配置方法
    2. 在新添加的方法上,使用注解的方式配置JPQL查詢語句**@Query** 結合Mybatis注解配置的@Select等等
    3. @Query(value = "from Customer where custName = ? ")
      public Customer findByName(String name);
                 
    4. 多占位符的指派
      1. 根據名稱和id查詢實體:占位符需要和參數相同(預設方式) 可以改變問号占位符和參數的位置,隻需要在占位符後面說明第幾個就可以(一般沒必要)
        1. @Query(value = "from Customer where custName = ? and custId = ?")
          public  Customer findByNameId(String name,Long id);
                     
        2. //順序可變  在?之後寫位置
          @Query(value = "from Customer where custName = ?2 and custId = ?1")
          public  Customer findByNameId(String name,Long id);
                     
    5. 完成更新操作
      1. id更新名稱

        @Query是查詢操作,更新和删除操作需要新注解@Modfing,在修改的方法上面添加;而且還需要手動在測試方法上加入@Transactional注解添加事務的支援,且預設會手動執行完畢復原事務,是以要加上@Rollback注解設定自動復原為false

        1. @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);
               }
          
          
                     
    6. JPQL裡的SQL語句的查詢 使用sql查詢是一個裝有Object數組的集合 在JPQL語句中使用SQL語句
    7. nativeQuery屬性:false(預設值,不适應本地查詢,使用JPQL查詢)|true(使用本地查詢,sql查詢)
    8. //下面展示的是基本查詢和一個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));
              }
                 
  2. 方法名稱規則查詢
    1. 是對JPQL查詢更加深層的封裝,隻需要SpringDataJpa提供的方法名稱規則定義方法,不需要配置jpql就可以完成查詢
    2. 命名規則
      1. findBy:代表查詢
        1. 對象的屬性名(首字母大寫):查詢的條件 例如 :findByCustName
        2. SpringDataJpa運作時會解析 findBy from xxx(實體類) 屬性名 where custName = ?
        3. //隻需要寫方法即可查詢出來
           public Customer findByCustName(String name);
          //Customer{custId=1, custName='2', custSource='2', custIndustry='aa', custLevel='2', custAddress='a', custPhone='2'}
                     
        4. 模糊比對 上述基礎上繼續添加 例如 findByCustNameLike
        5. 多條件比對 findByCustNameLikeAndCustAddressAndCustPhone 參數順序保持一緻
          1. 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);
                    }
                       

Spring Data JPA中的複雜查詢:

  1. 借助接口定義好的方法完成查詢
    1. findOne()方法
  2. findOne()方法和GetOne()方法的差別
    1. 單元測試getOne方法,需要加入@Transactional注解保證方法正常運, SimpleJpaRepository調用em.GetReference方法,延遲加載,傳回動态代理對象,什麼時候用,什麼時候查
    2. findOne方法:SimpleJpaRepository使用的是em.find方法 ,立即加載
    3. 類似和Mybatis中的表對于關系一樣,一對多的情況下使用的是延遲加載,對一的情況使用立即加載