天天看点

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中的表对于关系一样,一对多的情况下使用的是延迟加载,对一的情况使用立即加载