SpringDataJPA入门学习总结笔记

JPA相关的基础概念


ORM思想

  • Object-Relational Mapping 表示对象关系映射,在面向对象的软件开发中,通过ORM,就可以把对象映射到关系型数据库中。
  • 主要目的:
    操作实体类就相当于操作数据库表,不再重点关注sql语句
  • 建立两个映射关系:
    实体类和表的映射关系
    实体类中属性和表中字段的映射关系
  • 实现了ORM思想的框架:
    Mybatis、Hibernate

Hibernate框架

  • 一个开放源代码的对象关系映射框架
  • 对JDBC进行了非常轻量级的对象封装
  • 将POJO与数据库表建立映射关系,是一个全自动的ORM框架

JPA规范

  • JPA的全称是Java Persistence API, 即Java持久化API,是SUN公司推出的一套基于ORM的规范,内部是由一系列的接口和抽象类构成。

  • JPA通过JDK 5.0注解描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。

  • 优点:
    ①标准化
    任何声称符合 JPA 标准的框架都遵循同样的架构,提供相同的访问API,这保证了基于JPA开发的企业应用能够经过少量的修改就能够在不同的JPA框架下运行。
    ②容器级特性支持
    JPA框架中支持大数据集、事务、并发等容器级事务,这使得 JPA 超越了简单持久化框架的局限,在企业应用发挥更大的作用。
    ③简单方便
    在JPA框架下创建实体和创建Java 类一样简单,没有任何的约束和限制,只需要使用 javax.persistence.Entity进行注释,JPA的框架和接口也都非常简单,没有太多特别的规则和设计模式的要求,开发者可以很容易的掌握。
    ④ 查询能力
    JPA的查询语言是面向对象而非面向数据库的,JPA定义了独特的JPQL(Java Persistence Query Language),它是针对实体的一种查询语言,操作对象是实体,能够支持批量更新和修改、JOIN、GROUP BY、HAVING 等通常只有 SQL 才能够提供的高级查询特性,甚至还能够支持子查询。
    ⑤高级特性
    JPA 中能够支持面向对象的高级特性,如类之间的继承、多态和类之间的复杂关系,这样的支持能够让开发者最大限度的使用面向对象的模型设计企业应用,而不需要自行处理这些特性在关系数据库的持久化。

  • JPA与hibernate的关系
    JPA规范本质上就是一种ORM规范,注意不是ORM框架——JPA并未提供ORM实现,它只是制订了规范,提供了编程的API接口,具体实现则由服务厂商来提供。

    JPA和Hibernate的关系就像JDBC和JDBC驱动的关系,JPA是规范,Hibernate除了作为ORM框架之外,它也是一种JPA实现。如果使用JPA规范进行数据库操作,底层需要hibernate作为其实现类完成数据持久化工作。
    SpringDataJPA入门学习总结笔记_第1张图片


JPA入门案例

保存客户

创建maven工程,导入坐标

	<properties>
        <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
        <project.hibernate.version>5.0.12.Finalproject.hibernate.version>
    properties>

    <dependencies>
        
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.12version>
            <scope>testscope>
        dependency>

        
        <dependency>
            <groupId>org.hibernategroupId>
            <artifactId>hibernate-entitymanagerartifactId>
            <version>${project.hibernate.version}version>
        dependency>

        
        <dependency>
            <groupId>org.hibernategroupId>
            <artifactId>hibernate-c3p0artifactId>
            <version>${project.hibernate.version}version>
        dependency>

        
        <dependency>
            <groupId>log4jgroupId>
            <artifactId>log4jartifactId>
            <version>1.2.17version>
        dependency>

        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>5.1.44version>
        dependency>

    dependencies>

创建jpa核心配置文件
要求 必须在resources/META-INF目录下,文件名叫persistence.xml
SpringDataJPA入门学习总结笔记_第2张图片


<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
    
    <persistence-unit name="myJPA" transaction-type="RESOURCE_LOCAL">
        
        <provider>org.hibernate.jpa.HibernatePersistenceProviderprovider>

        <properties>
            
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql:///test"/>
            <property name="javax.persistence.jdbc.user" value="root"/>
            <property name="javax.persistence.jdbc.password" value=""/>
            
            
            <property name="hibernate.show_sql" value="true"/>
            
            <property name="hibernate.hbm2ddl.auto" value="create"/>
        properties>

    persistence-unit>
persistence>

创建客户的数据库表

/*创建客户表*/
CREATE TABLE customer (
	cust_id BIGINT(32) PRIMARY KEY AUTO_INCREMENT COMMENT '客户编号(主键)',
	cust_name VARCHAR(32) NOT NULL COMMENT '客户名称(公司名称)',
	cust_source VARCHAR(32) DEFAULT NULL COMMENT '客户信息来源',
	cust_industry VARCHAR(32) DEFAULT NULL COMMENT '客户所属行业',
	cust_level VARCHAR(32) DEFAULT NULL COMMENT '客户级别',
	cust_address VARCHAR(128) DEFAULT NULL COMMENT '客户联系地址',
	cust_phone VARCHAR(64) DEFAULT NULL COMMENT '客户联系电话'
);

创建对应数据库表的客户实体类

package com.pojo;

public class Customer {
    private Long id;//主键    
    private String name;//名称
    private String source;//来源
    private String industry;//行业
    private String level;//级别
    private String address;//地址
    private String phone;//联系方式

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSource() {
        return source;
    }

    public void setSource(String source) {
        this.source = source;
    }

    public String getIndustry() {
        return industry;
    }

    public void setIndustry(String industry) {
        this.industry = industry;
    }

    public String getLevel() {
        return level;
    }

    public void setLevel(String level) {
        this.level = level;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    @Override
    public String toString() {
        return "Customer{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", source='" + source + '\'' +
                ", industry='" + industry + '\'' +
                ", level='" + level + '\'' +
                ", address='" + address + '\'' +
                ", phone='" + phone + '\'' +
                '}';
    }
}

配置映射关系
实体类和表的关系
在这里插入图片描述
实体类中属性和表字段的映射关系
SpringDataJPA入门学习总结笔记_第3张图片


创建测试类

public class JpaTest {
  

    //测试jpa的保存
    @Test
    public void save(){
        //创建工厂对象
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJPA");
        //获取实体管理器
        EntityManager manager = factory.createEntityManager();
        //获取事务对象,开启事务
        EntityTransaction transaction = manager.getTransaction();
        transaction.begin();
        //保存操作实现
        Customer customer=new Customer();
        customer.setName("kobe");
        customer.setIndustry("nba");
        manager.persist(customer);
        //提交事务
        transaction.commit();
        //释放资源
        manager.close();
        factory.close();
    }
}

SpringDataJPA入门学习总结笔记_第4张图片


在数据库中查询结果
SpringDataJPA入门学习总结笔记_第5张图片


主键的生成策略

自增 要求底层数据库支持自增 mysql

	@GeneratedValue(strategy = GenerationType.IDENTITY) 

序列 要求底层数据库支持序列 oracle

	@GeneratedValue(strategy = GenerationType.SEQUENCE) 

TABLE JPA提供的一种机制,通过一张数据库表完成自增

	@GeneratedValue(strategy = GenerationType.TABLE) 

由程序自动帮我们完成主键自增

	@GeneratedValue(strategy = GenerationType.AUTO) 

JPA操作步骤

  • 1.加载配置文件 创建工厂对象
    静态方法 根据持久化单元名称创建实体管理器工厂
    (创建工厂比较耗时,可以使用静态代码块创建一个公共的工厂)
    Persistence:

  • 2.通过工厂获取实体管理器EntityManager对象
    是一个线程安全的对象,内部维护了数据库信息、缓存信息、所有实体管理器对象
    在这里插入图片描述
    EntityManager对象方法:
    getTransaction 获取事务对象
    persist 保存
    merge 更新
    remove 删除
    find/getReference 根据id查询

  • 3.获取事务对象,开启事务
    在这里插入图片描述
    EntityTransaction对象方法:
    begin 开启事务
    rollback 回滚事务
    commit 提交事务

  • 4.完成操作

  • 5.提交(回滚)事务

  • 6.释放资源


抽取JPA工具类

解决实体管理器工厂浪费资源和耗时问题,通过静态代码块的形式,当程序第一次访问工具类时,创建一个实体管理器工厂对象

public class JpaUtils {
    private static EntityManagerFactory myJPAFactory;

    static {
        myJPAFactory = Persistence.createEntityManagerFactory("myJPA");
    }

    //获取实体管理器
    public static EntityManager getEntityManager(){
        return myJPAFactory.createEntityManager();
    }
}

测试类修改为

//测试jpa的保存
    @Test
    public void save(){
        //获取实体管理器
        EntityManager manager = JpaUtils.getEntityManager();
        //获取事务对象,开启事务
        EntityTransaction transaction = manager.getTransaction();
        transaction.begin();
        //保存操作实现
        Customer customer=new Customer();
        customer.setName("kobe");
        customer.setIndustry("nba");
        manager.persist(customer);
        //提交事务
        transaction.commit();
        //释放资源
        manager.close();
    }

查询客户

//测试jpa的查询
    @Test
    public void findById(){
        //获取实体管理器
        EntityManager manager = JpaUtils.getEntityManager();
        //获取事务对象,开启事务
        EntityTransaction transaction = manager.getTransaction();
        transaction.begin();
        //查询操作实现(将配置中的create改为update)
        Customer customer = manager.find(Customer.class, 1L);
        System.out.println(customer);
        //提交事务
        transaction.commit();
        //释放资源
        manager.close();
    }

SpringDataJPA入门学习总结笔记_第6张图片


延迟加载与立即加载

使用getReference方法

//测试jpa的查询2
    @Test
    public void findById2(){
        //获取实体管理器
        EntityManager manager = JpaUtils.getEntityManager();
        //获取事务对象,开启事务
        EntityTransaction transaction = manager.getTransaction();
        transaction.begin();
        //查询操作实现(将配置中的create改为update)
        Customer customer = manager.getReference(Customer.class, 1L);
        System.out.println(customer);
        //提交事务
        transaction.commit();
        //释放资源
        manager.close();
    }

结果和之前一模一样
SpringDataJPA入门学习总结笔记_第7张图片
区别:

  • 使用find方法查询,查询获取的对象就是当前客户对象本身,调用find方法时就会发送sql语句查询数据库
  • 使用getReference方法查询,查询获取的对象是动态代理对象,调用方法时不会立即发送sql语句查询数据库,当调用结果对象时(本例中为输出对象)才会发送sql语句查询数据库
  • 一般使用延迟加载,节省资源

删除客户

//测试jpa的删除
    @Test
    public void remove(){
        //获取实体管理器
        EntityManager manager = JpaUtils.getEntityManager();
        //获取事务对象,开启事务
        EntityTransaction transaction = manager.getTransaction();
        transaction.begin();
        //删除操作实现(将配置中的create改为update)
        Customer customer = manager.getReference(Customer.class, 1L);
        manager.remove(customer);
        //提交事务
        transaction.commit();
        //释放资源
        manager.close();
    }

SpringDataJPA入门学习总结笔记_第8张图片
运行后查询数据库
在这里插入图片描述


更新客户

数据库初始记录
在这里插入图片描述
更新代码

//测试jpa的更新
    @Test
    public void update(){
        //获取实体管理器
        EntityManager manager = JpaUtils.getEntityManager();
        //获取事务对象,开启事务
        EntityTransaction transaction = manager.getTransaction();
        transaction.begin();
        //删除操作实现(将配置中的create改为update)
        Customer customer = manager.getReference(Customer.class, 1L);
        customer.setAddress("LOS ANGELES");
        customer.setName("KOBE BRYANT");
        manager.merge(customer);
        //提交事务
        transaction.commit();
        //释放资源
        manager.close();
    }

运行,查询结果
SpringDataJPA入门学习总结笔记_第9张图片
在这里插入图片描述


使用JPQL查询

JPQL全称Java persistence query language,Java持久化查询语言,是面向对象的查询语言,查询的是实体类和类中的属性,语法与SQL类似。

查询全部

//测试jpql查询
    @Test
    public void findAll(){
        //获取实体管理器
        EntityManager entityManager = JpaUtils.getEntityManager();
        //获取事务对象,开启事务
        EntityTransaction transaction = entityManager.getTransaction();
        transaction.begin();
        //查询全部
        String jpql="from com.pojo.Customer";
        Query query = entityManager.createQuery(jpql);
        List resultList = query.getResultList();
        System.out.println(resultList);
        //提交事务
        transaction.commit();
        //释放资源
        entityManager.close();
    }

SpringDataJPA入门学习总结笔记_第10张图片


排序查询

//测试jpql排序查询
    @Test
    public void findOrderById(){
        //获取实体管理器
        EntityManager entityManager = JpaUtils.getEntityManager();
        //获取事务对象,开启事务
        EntityTransaction transaction = entityManager.getTransaction();
        transaction.begin();
        //根据id倒序查询全部
        String jpql="from Customer order by id desc";
        Query query = entityManager.createQuery(jpql);
        List<Customer> resultList = query.getResultList();
        for(Customer customer:resultList){
            System.out.println(customer);
        }
        //提交事务
        transaction.commit();
        //释放资源
        entityManager.close();
    }

SpringDataJPA入门学习总结笔记_第11张图片


统计查询

//测试jpql统计查询
    @Test
    public void findCount(){
        //获取实体管理器
        EntityManager entityManager = JpaUtils.getEntityManager();
        //获取事务对象,开启事务
        EntityTransaction transaction = entityManager.getTransaction();
        transaction.begin();
        //统计查询
        String jpql="select count(id) from Customer";
        Query query = entityManager.createQuery(jpql);
        Long count = (Long) query.getSingleResult();
        System.out.println("记录数: "+count);
        //提交事务
        transaction.commit();
        //释放资源
        entityManager.close();
    }

SpringDataJPA入门学习总结笔记_第12张图片


分页查询

//测试jpql分页查询
    @Test
    public void findPage(){
        //获取实体管理器
        EntityManager entityManager = JpaUtils.getEntityManager();
        //获取事务对象,开启事务
        EntityTransaction transaction = entityManager.getTransaction();
        transaction.begin();
        //分页查询
        String jpql="from Customer";
        Query query = entityManager.createQuery(jpql);
        //对分页参数赋值 从1开始,查询1条
        query.setFirstResult(1);
        query.setMaxResults(1);
        List<Customer> resultList = query.getResultList();
        for(Customer customer:resultList){
            System.out.println(customer);
        }
        //提交事务
        transaction.commit();
        //释放资源
        entityManager.close();
    }

SpringDataJPA入门学习总结笔记_第13张图片


条件查询

//测试jpql条件查询
    @Test
    public void findCondition(){
        //获取实体管理器
        EntityManager entityManager = JpaUtils.getEntityManager();
        //获取事务对象,开启事务
        EntityTransaction transaction = entityManager.getTransaction();
        transaction.begin();
        //条件查询 姓名以KO开头的记录
        String jpql="from Customer where name like ?";
        Query query = entityManager.createQuery(jpql);
        query.setParameter(1,"KO%");
        List<Customer> resultList = query.getResultList();
        for(Customer customer:resultList){
            System.out.println(customer);
        }
        //提交事务
        transaction.commit();
        //释放资源
        entityManager.close();
    }

SpringDataJPA入门学习总结笔记_第14张图片


Spring Data JPA相关的基础概念

Spring Data JPA概述

  • Spring Data JPA 是 Spring 基于 ORM 框架、JPA 规范的基础上封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据库的访问和操作。
  • 它提供了包括增删改查等在内的常用功能,且易于扩展,可以极大提高开发效率。
  • Spring Data JPA 让我们解脱了DAO层的操作,基本上所有CRUD都可以依赖于它来实现,在实际的工作工程中,推荐使用Spring Data JPA + ORM(如:hibernate)完成操作,这样在切换不同的ORM框架时提供了极大的方便,同时也使数据库层操作更加简单,方便解耦

Spring Data JPA的特性

  • SpringData Jpa 极大简化了数据库访问层代码。
  • 使用了SpringDataJpa,我们的dao层中只需要写接口,就自动具有了增删改查、分页查询等方法。

Spring Data JPA 与 JPA和hibernate之间的关系

  • JPA是一套规范,内部是由有接口和抽象类组成的。hibernate是一套成熟的ORM框架,而且Hibernate实现了JPA规范,所以也可以称hibernate为JPA的一种实现方式,我们使用JPA的API编程,意味着站在更高的角度上看待问题(面向接口编程)
  • Spring Data JPA是Spring提供的一套对JPA操作更加高级的封装,是在JPA规范下的专门用来进行数据持久化的解决方案。

SpringDataJPA入门案例

搭建环境

创建工程导入坐标

 <properties>
        <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
        <spring.version>5.2.1.RELEASEspring.version>
        <hibernate.version>5.0.12.Finalhibernate.version>
    properties>

    <dependencies>
        
        <dependency>
            <groupId>org.aspectjgroupId>
            <artifactId>aspectjweaverartifactId>
            <version>1.9.4version>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-aopartifactId>
            <version>${spring.version}version>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-contextartifactId>
            <version>${spring.version}version>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-ormartifactId>
            <version>${spring.version}version>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-beansartifactId>
            <version>${spring.version}version>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-coreartifactId>
            <version>${spring.version}version>
        dependency>
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-testartifactId>
            <version>${spring.version}version>
        dependency>
        <dependency>
            <groupId>org.springframework.datagroupId>
            <artifactId>spring-data-jpaartifactId>
            <version>2.2.1.RELEASEversion>
        dependency>


        
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.12version>
            <scope>testscope>
        dependency>

        
        <dependency>
            <groupId>org.hibernategroupId>
            <artifactId>hibernate-coreartifactId>
            <version>${hibernate.version}version>
        dependency>
        <dependency>
            <groupId>org.hibernategroupId>
            <artifactId>hibernate-entitymanagerartifactId>
            <version>${hibernate.version}version>
        dependency>
        <dependency>
            <groupId>org.hibernategroupId>
            <artifactId>hibernate-validatorartifactId>
            <version>5.3.5.Finalversion>
        dependency>

        
        <dependency>
            <groupId>org.hibernategroupId>
            <artifactId>hibernate-c3p0artifactId>
            <version>${hibernate.version}version>
        dependency>

        
        <dependency>
            <groupId>log4jgroupId>
            <artifactId>log4jartifactId>
            <version>1.2.17version>
        dependency>
        
        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>5.1.44version>
        dependency>

        
        <dependency>
            <groupId>javax.elgroupId>
            <artifactId>javax.el-apiartifactId>
            <version>2.2.4version>
        dependency>

        <dependency>
            <groupId>org.glassfish.webgroupId>
            <artifactId>javax.elartifactId>
            <version>2.2.4version>
        dependency>
        
    dependencies>

配置spring文件
在resources目录下创建一个spring-data-jpa.xml的springConfig配置文件


<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">

    
    
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        
        <property name="packagesToScan" value="com.pojo"/>
        
        <property name="persistenceProvider">
            <bean class="org.hibernate.jpa.HibernatePersistenceProvider"/>
        property>
        
        <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"/>
                <property name="showSql" value="true"/>
            bean>
        property>
        
        <property name="jpaDialect">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
        property>
    bean>

    
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql:///test"/>
        <property name="user" value="root"/>
        <property name="password" value=""/>
    bean>

    
    <jpa:repositories base-package="com.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"/>
beans>

编写实体类,用jpa注解配置映射关系

跟之前的Customer类一样

@Entity//声明此类是一个实体类
@Table(name = "customer")//配置实体类和表的映射关系 name属性配置数据库表名
public class Customer {
    @Id//声明主键
    @GeneratedValue(strategy = GenerationType.IDENTITY)//配置主键生产策略
    @Column(name = "cust_id")//配置属性和字段的映射关系 name配置数据库字段名
    private Long id;//主键

    @Column(name = "cust_name")
    private String name;//名称

    @Column(name = "cust_source")
    private String source;//来源

    @Column(name = "cust_industry")
    private String industry;//行业

    @Column(name = "cust_level")
    private String level;//级别

    @Column(name = "cust_address")
    private String address;//地址

    @Column(name = "cust_phone")
    private String phone;//联系方式

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSource() {
        return source;
    }

    public void setSource(String source) {
        this.source = source;
    }

    public String getIndustry() {
        return industry;
    }

    public void setIndustry(String industry) {
        this.industry = industry;
    }

    public String getLevel() {
        return level;
    }

    public void setLevel(String level) {
        this.level = level;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    @Override
    public String toString() {
        return "Customer{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", source='" + source + '\'' +
                ", industry='" + industry + '\'' +
                ", level='" + level + '\'' +
                ", address='" + address + '\'' +
                ", phone='" + phone + '\'' +
                '}';
    }
}

编写符合SpringDataJpa的dao层接口

dao层规范:

  • 继承接口JpaRepository
  • 提供相应的泛型,T是实体类类型,ID是主键类型

接口代码

public interface CustomerDao extends JpaRepository<Customer,Long> {
//不需要其他代码 
//JpaRepository封装了基本CRUD操作
}


基本CRUD操作

查询操作

直接调用findById方法根据Id查询

@RunWith(SpringJUnit4ClassRunner.class)//声明spring提供的单元测试环境
@ContextConfiguration(locations = "classpath:spring-data-jpa-config.xml")//指定spring容器的配置信息
public class SpringDataJpaTest {

    @Autowired
    private CustomerDao customerDao;

    @Test
    public void findById(){
        Optional<Customer> customer = customerDao.findById(2L);
        System.out.println(customer);
    }
}

运行结果:
SpringDataJPA入门学习总结笔记_第15张图片


保存和更新操作

@Test
    public void save(){
        //如果存在的对象id主键不存在,代表保存,存在代表更新
        Customer customer=new Customer();
        customer.setName("AAA");
        customer.setIndustry("FootBall");
        customerDao.save(customer);//保存
        customer.setId(4L);
        customer.setName("BBB");
        customerDao.save(customer);//更新
    }

查询数据库
SpringDataJPA入门学习总结笔记_第16张图片


删除操作

@Test
    public void delete(){
        customerDao.deleteById(4L);
    }

再次查询数据库
在这里插入图片描述


查询所有操作

@Test
    public void findAll(){
        List<Customer> customers = customerDao.findAll();
        for(Customer customer:customers){
            System.out.println(customer);
        }
    }

结果
SpringDataJPA入门学习总结笔记_第17张图片


执行过程分析

在自定义的CustomerDao中,并没有提供任何方法就可以使用其中的很多方法。
由于继承了JpaRepository所以我们可以使用这两个接口的所有方法。
但是这些方法都只是一些声明,没有具体的实现方式,那么在 Spring Data JPA中它又是怎么实现的呢?
以debug断点调试的方式,分析Spring Data JPA的的执行过程,以findById方法为例进行分析。
SpringDataJPA入门学习总结笔记_第18张图片
可以发现注入的customerDao对象,本质上是通过JdkDynamicAopProxy生成的一个代理对象:
在这里插入图片描述
当程序执行的时候,会通过JdkDynamicAopProxyinvoke方法,对customerDao对象生成动态代理对象,这个动态代理对象就是SimpleJpaRepository
调用自定义类的findById方法实际就是调用SimpleJpaRepositoryfindById方法
SpringDataJPA入门学习总结笔记_第19张图片
Spring Data JPA对JPA操作进行了进一步封装,简化了Dao层代码的开发。


执行过程和原理总结:

  • 通过JdkDynamicAopProxyinvoke方法创建了一个动态代理对象SimpleJpaRepository
  • SimpleJpaRepository中封装了JPA的操作
  • 通过hibernate(封装了JDBC)完成数据库操作

复杂查询

统计总数

 	@Test
    public void count(){
        long count = customerDao.count();
        System.out.println(count);
    }

SpringDataJPA入门学习总结笔记_第20张图片


判断存在

	@Test
    public void exists(){
        boolean b = customerDao.existsById(3L);
        System.out.println(b);
    }

SpringDataJPA入门学习总结笔记_第21张图片


getOne() 查询一个

	@Test@Transactional//保证正常运行
    public void getOne(){
        Customer customer = customerDao.getOne(1L);
        System.out.println(customer);
    }

SpringDataJPA入门学习总结笔记_第22张图片

通过源码getReference方法可以看出getOnefindById的区别是使用了延迟加载
SpringDataJPA入门学习总结笔记_第23张图片


使用JPQL查询

需要将JPQL通过注解配置到接口方法上

根据名称查询

接口中增加方法

public interface CustomerDao extends JpaRepository<Customer,Long> {

    //根据客户名称查询
    @Query(value = "from Customer where name = ?1")
    Customer findByName(String name);
}

测试类中增加方法

@Test
    public void findByName(){
        Customer customer = customerDao.findByName("JAMES");
        System.out.println(customer);
    }

结果
SpringDataJPA入门学习总结笔记_第24张图片


根据id和名称查询

接口中增加方法 占位符需要和方法参数的顺序一致, ?后的数字是参数的索引,从1开始

	//根据客户id和名称查询
    @Query(value = "from Customer where id=?1 and name = ?2")
    //等价于@Query(value = "from Customer where name=?2 and id = ?1")
    Customer findByIdAndName(Long id,String name);

测试类中增加方法

	 @Test
    public void findByIdAndName(){
        Customer customer = customerDao.findByIdAndName(2L,"JAMES");
        System.out.println(customer);
    }

结果
SpringDataJPA入门学习总结笔记_第25张图片


更新操作
springdatajpa的更新/删除操作需要事务支持(添加注解),默认执行结束后回滚,需要添加注解取消回滚

接口方法

//根据id更新名称
    @Query(value = "update Customer set name=?1 where id=?2")
    @Modifying//表示是更新操作
    void updateNameById(String name,Long id);

测试方法

	@Test
	@Transactional//添加事务支持
	@Rollback(false)//取消回滚
    public void updateNameById(){
        customerDao.updateNameById("JAMES23",2L);
    }

运行后查询数据库
在这里插入图片描述


使用SQL查询

需要将SQL通过注解配置到接口方法上
使用@Query中的nativeQuery属性进行标识(true表示MySQL)


查询全部

//查询全部
    @Query(value = "select * from customer",nativeQuery = true)
    List<Object[]> findAllBySql();

测试方法

 @Test
    public void findAllBySql(){
        List<Object[]> lists = customerDao.findAllBySql();
        for(Object[] obj:lists){
            System.out.println(Arrays.toString(obj));
        }
    }

结果:
SpringDataJPA入门学习总结笔记_第26张图片


模糊查询

接口中添加方法

 //模糊查询
    @Query(value = "select * from customer where cust_name like ?",nativeQuery = true)
    List<Object[]> findByNameWithSql(String name);

测试方法

@Test
public void findByNameWithSql(){
    List<Object[]> lists = customerDao.findByNameWithSql("K%");
    for(Object[] obj:lists){
        System.out.println(Arrays.toString(obj));
    }
}

结果
SpringDataJPA入门学习总结笔记_第27张图片


方法名规则查询

是对JPQL更深层的封装,只需要按照springdataJPA提供的方法名规则定义方法,不需要配置JPQL语句
方法名的规则:

具体查询
findBy+对象中的属性名称
SpringDataJPA入门学习总结笔记_第28张图片
例如根据名称查询
在这里插入图片描述
测试方法
SpringDataJPA入门学习总结笔记_第29张图片
结果
SpringDataJPA入门学习总结笔记_第30张图片


条件查询
findBy+对象中的属性名称+查询方式
例:模糊查询

接口方法
在这里插入图片描述
测试方法
SpringDataJPA入门学习总结笔记_第31张图片
结果
SpringDataJPA入门学习总结笔记_第32张图片


多条件查询
findBy+对象中的属性名称+查询方式+多条件连接符(and|or)
例:根据名称模糊匹配和所属行业精准匹配
接口方法:

Customer findByNameLikeAndIndustry(String name,String industry);

测试方法

@Test
    public void findByNameLikeAndIndustry(){
        Customer customer = customerDao.findByNameLikeAndIndustry("JA%","nba");
        System.out.println(customer);
    }

结果
SpringDataJPA入门学习总结笔记_第33张图片


Specifications动态查询

方法列表
T findOne(Specification spec) 查询单个对象

List findAll(Specification spec) 查询列表

Page findAll(Specification spec,Pageable pageable) 分页查询全部

List findAll(Specification spec,Sort sort) 排序查询全部

long count(Specification spec) 统计查询

Specification代表查询条件


查询单个

dao接口需要继承JpaSpecificationExecutor
在这里插入图片描述
测试方法

//根据客户名称查询
    @Test
    public void findOne(){
        //自定义查询条件 实现Specification接口 实现toPredicate方法 从root获取对象属性 CriteriaBuilder构造查询条件
        Specification<Customer> specification= (Specification<Customer>) (root, criteriaQuery, criteriaBuilder) -> {
            //获取比较的属性
            Path<Object> name = root.get("name");
            //构造查询
            Predicate res = criteriaBuilder.equal(name, "JAMES23");//精确匹配,相当于查询name为JAMES23的记录
            return res;
        };
        Optional<Customer> customer = customerDao.findOne(specification);
        System.out.println(customer);
    }

结果
SpringDataJPA入门学习总结笔记_第34张图片


多条件查询

//根据客户名称和行业查询
    @Test
    public void findOne2(){
        Specification<Customer> specification= (Specification<Customer>) (root, criteriaQuery, criteriaBuilder) -> {
            //获取比较的属性
            Path<Object> name = root.get("name");
            Path<Object> industry = root.get("industry");
            //构造查询
            Predicate res1 = criteriaBuilder.equal(name, "JAMES23");
            Predicate res2 = criteriaBuilder.equal(industry, "nba");
            Predicate res = criteriaBuilder.and(res1, res2);
            return res;
        };
        Optional<Customer> customer = customerDao.findOne(specification);
        System.out.println(customer);
    }

结果
SpringDataJPA入门学习总结笔记_第35张图片


模糊查询

//根据客户名称模糊查询
    @Test
    public void findOne3(){
        Specification<Customer> specification= (Specification<Customer>) (root, criteriaQuery, criteriaBuilder) -> {
            //获取比较的属性
            Path<Object> name = root.get("name");
            //构造查询 使用path对象的as方法指定类型
            Predicate res = criteriaBuilder.like(name.as(String.class),"JA%");
            return res;
        };
        Optional<Customer> customer = customerDao.findOne(specification);
        System.out.println(customer);
    }

结果
SpringDataJPA入门学习总结笔记_第36张图片


排序查询
使用Sort.by()方法进行排序,将返回值作为查询的参数

@Test
    public void findOne3(){
        Specification<Customer> specification= (Specification<Customer>) (root, criteriaQuery, criteriaBuilder) -> {
            //获取比较的属性
            Path<Object> name = root.get("name");
            //构造查询 使用path对象的as方法指定类型
            Predicate res = criteriaBuilder.like(name.as(String.class),"JA%");
            return res;
        };
        //第一个参数排序的顺序 第二个参数排序的属性名
        Sort sort=Sort.by(Sort.Direction.ASC,"id");
        List<Customer> customer = customerDao.findAll(specification,sort);
        System.out.println(customer);
    }

结果
SpringDataJPA入门学习总结笔记_第37张图片


分页查询

@Test
    public void findOne4(){
        //第一个参数查询的页数 第二个参数显示的个数
        Specification<Customer> specification=null;
        Pageable pageable=PageRequest.of(1,1);
        Page<Customer> page = customerDao.findAll(specification, pageable);
        System.out.println("数据"+page.getContent());
        System.out.println("page"+page.getTotalPages());//总页数
        System.out.println("count"+page.getTotalElements());//总条数
    }

结果
SpringDataJPA入门学习总结笔记_第38张图片


多表之间的关系和操作多表的步骤

表关系

  • 一对一
  • 一对多
    一的一方为主表,多的一方为从表,需要在从表新建一列作为外键,取值来源于主表的主键
  • 多对多
    需要一张中间表,最少需要两个字段作为外键指向两张表的主键,组成了联合主键

实体类关系

  • 包含 通过实体类的包含关系描述表关系
  • 继承

步骤

  • 明确表关系
  • 确定表关系(描述 通过外键|中间表)
  • 编写实体类,在实体类中描述表关系(包含关系)
  • 配置映射关系

一对多操作

案例:客户(一)和联系人(多)
1 明确表关系:一对多
2 确定表关系
主表:客户 使用之前的客户表
从表:联系人 在从表添加外键

/*创建联系人表*/
CREATE TABLE linkman (
  lkm_id BIGINT(32) PRIMARY KEY AUTO_INCREMENT COMMENT '联系人编号(主键)',
  lkm_name VARCHAR(16)  COMMENT '联系人姓名',
  lkm_gender CHAR(1)  COMMENT '联系人性别',
  lkm_phone VARCHAR(16)  COMMENT '联系人办公电话',
  lkm_mobile VARCHAR(16)  COMMENT '联系人手机',
  lkm_email VARCHAR(64)  COMMENT '联系人邮箱',
  lkm_position VARCHAR(16)  COMMENT '联系人职位',
  lkm_memo VARCHAR(512)  COMMENT '联系人备注',
  lkm_cust_id BIGINT(32) NOT NULL COMMENT '客户id(外键)',
  CONSTRAINT `FK_cst_linkman_lkm_cust_id` FOREIGN KEY (`lkm_cust_id`) REFERENCES `customer` (`cust_id`)
);

3 编写实体类
客户:在客户实体类中包含一个联系人集合

@Entity//声明此类是一个实体类
@Table(name = "customer")//配置实体类和表的映射关系 name属性配置数据库表名
public class Customer {
    @Id//声明主键
    @GeneratedValue(strategy = GenerationType.IDENTITY)//配置主键生产策略
    @Column(name = "cust_id")//配置属性和字段的映射关系 name配置数据库字段名
    private Long id;//主键

    @Column(name = "cust_name")
    private String name;//名称

    @Column(name = "cust_source")
    private String source;//来源

    @Column(name = "cust_industry")
    private String industry;//行业

    @Column(name = "cust_level")
    private String level;//级别

    @Column(name = "cust_address")
    private String address;//地址

    @Column(name = "cust_phone")
    private String phone;//联系方式
    
    //配置一对多关系 targetEntity 多实体类的字节码
    @OneToMany(targetEntity = Linkman.class)
    //name 从表外键 referencedColumnName 主表主键 
    @JoinColumn(name ="lkm_cust_id" ,referencedColumnName = "cust_id")
    private Set<Linkman> linkmen=new HashSet<>();

    public Set<Linkman> getLinkmen() {
        return linkmen;
    }

    public void setLinkmen(Set<Linkman> linkmen) {
        this.linkmen = linkmen;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSource() {
        return source;
    }

    public void setSource(String source) {
        this.source = source;
    }

    public String getIndustry() {
        return industry;
    }

    public void setIndustry(String industry) {
        this.industry = industry;
    }

    public String getLevel() {
        return level;
    }

    public void setLevel(String level) {
        this.level = level;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    @Override
    public String toString() {
        return "Customer{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", source='" + source + '\'' +
                ", industry='" + industry + '\'' +
                ", level='" + level + '\'' +
                ", address='" + address + '\'' +
                ", phone='" + phone + '\'' +
                '}';
    }
}

联系人:在联系人实体类包含一个客户对象

@Entity
@Table(name="linkman")
public class Linkman {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "lkm_id")
    private Long id;

    @Column(name ="lkm_name" )
    private String name;

    @Column(name = "lkm_gender")
    private String gender;

    @Column(name = "lkm_phone")
    private String phone;

    @Column(name = "lkm_mobile")
    private String mobile;

    @Column(name = "lkm_email")
    private String email;

    @Column(name = "km_position")
    private String position;

    @Column(name = "km_memo")
    private String memo;

    //配置表关系
    @ManyToOne(targetEntity = Customer.class)
    //配置外键
    @JoinColumn(name ="lkm_cust_id" ,referencedColumnName = "cust_id")
    private Customer customer;

    public Customer getCustomer() {
        return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getMobile() {
        return mobile;
    }

    public void setMobile(String mobile) {
        this.mobile = mobile;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPosition() {
        return position;
    }

    public void setPosition(String position) {
        this.position = position;
    }

    public String getMemo() {
        return memo;
    }

    public void setMemo(String memo) {
        this.memo = memo;
    }

    @Override
    public String toString() {
        return "Linkman{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", phone='" + phone + '\'' +
                ", mobile='" + mobile + '\'' +
                ", email='" + email + '\'' +
                ", position='" + position + '\'' +
                ", memo='" + memo + '\'' +
                '}';
    }
}

4 配置映射关系
使用JPA注解配置一对多关系

编写联系人的dao接口

public interface LinkmanDao extends JpaRepository<Linkman,Long>, JpaSpecificationExecutor<Linkman> {
}

在配置文件加入以下配置

	
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.hbm2ddl.auto">createprop>
            props>
        property>

编写测试类测试

@RunWith(SpringJUnit4ClassRunner.class)//声明spring提供的单元测试环境
@ContextConfiguration(locations = "classpath:spring-data-jpa-config.xml")
public class OneToManyTest {
    @Autowired
    private CustomerDao customerDao;

    @Autowired
    private LinkmanDao linkmanDao;

    @Test
    @Transactional
    @Rollback(false)//不自动回滚
    public void save(){
        Customer customer=new Customer();
        customer.setName("kobe");

        Linkman linkman=new Linkman();
        linkman.setName("james");

		customer.getLinkmen().add(linkman);
		
        customerDao.save(customer);
        linkmanDao.save(linkman);
    }
}

运行结果
SpringDataJPA入门学习总结笔记_第39张图片

查询数据库
客户表
在这里插入图片描述
联系人表
在这里插入图片描述


也可通过联系人维护外键关系

@Test
    @Transactional
    @Rollback(false)//不自动回滚
    public void save(){
        Customer customer=new Customer();
        customer.setName("kobe");

        Linkman linkman=new Linkman();
        linkman.setName("james");

        linkman.setCustomer(customer);

        customerDao.save(customer);
        linkmanDao.save(linkman);
    }

从显示的sql语句中看到少了一条update语句,数据库结果是一样的
SpringDataJPA入门学习总结笔记_第40张图片


可以在主表一方放弃外键维护提高效率
将注解修改为
在这里插入图片描述


删除从表数据:可以任意删除。
删除主表数据:

  • 有从表数据
    1、在默认情况下,它会把外键字段置为null,然后删除主表数据。如果在数据库的表 结构上,外键字段有非空约束,默认情况就会报错了。
    2、如果配置了放弃维护关联关系的权利,则不能删除(与外键字段是否允许为null, 没有关系)因为在删除时,它根本不会去更新从表的外键字段了。
    3、如果还想删除,使用级联删除引用

  • 没有从表数据引用:随便删


级联操作:指操作一个对象同时操作它的关联对象
使用方法:只需要在操作主体的注解上配置cascade

级联添加
在Customer类的联系人集合属性上的一对多注解配置cascade属性
在这里插入图片描述
测试类

	@Test
    @Transactional
    @Rollback(false)//不自动回滚
    public void add(){
        Customer customer=new Customer();
        customer.setName("kobe");

        Linkman linkman=new Linkman();
        linkman.setName("james");
        Linkman linkman2=new Linkman();
        linkman2.setName("gigi");


        customer.getLinkmen().add(linkman);
        customer.getLinkmen().add(linkman2);
        linkman.setCustomer(customer);
        linkman2.setCustomer(customer);

        //只需要保存客户,即可保存联系人
        customerDao.save(customer);
    }

SpringDataJPA入门学习总结笔记_第41张图片
查询数据库的联系人表
在这里插入图片描述
级联删除
先修改配置文件自动创建表为update,这样不会在运行时重新创建表清空数据
SpringDataJPA入门学习总结笔记_第42张图片
测试方法

@Test
    @Transactional
    @Rollback(false)//不自动回滚
    public void delete(){
        customerDao.deleteById(1L);
    }

可以看到先删除了从表
SpringDataJPA入门学习总结笔记_第43张图片
数据库中记录被删除
在这里插入图片描述


cascade属性
CascadeType.MERGE 级联更新
CascadeType.PERSIST 级联保存:
CascadeType.REFRESH 级联刷新:
CascadeType.REMOVE 级联删除:
CascadeType.ALL 包含所有


多对多操作

案例:用户和角色
用户类

@Entity
@Table(name = "user")
public class User implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "user_id")
    private Long id;

    @Column(name = "user_name")
    private String name;

    @ManyToMany(targetEntity = Role.class)
    @JoinTable(name = "user_role",//中间表名称
    joinColumns = {@JoinColumn(name = "user_key",referencedColumnName = "user_id")},//当前对象在中间表的外键
    inverseJoinColumns = {@JoinColumn(name ="role_key" ,referencedColumnName ="role_id" )})//对方对象在中间表的外键
    private Set<Role> roles=new HashSet<>();

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Set<Role> getRoles() {
        return roles;
    }

    public void setRoles(Set<Role> roles) {
        this.roles = roles;
    }
}

角色类

@Entity
@Table(name = "role")
public class Role implements Serializable {

    @Id@GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "role_id")
    private Long id;

    @Column(name = "role_name")
    private String name;

    @ManyToMany(targetEntity = User.class)
    @JoinTable(name = "user_role",//中间表名称
            joinColumns = {@JoinColumn(name = "role_key",referencedColumnName = "role_id")},//当前对象在中间表的外键
            inverseJoinColumns = {@JoinColumn(name ="user_key" ,referencedColumnName ="user_id" )})//对方对象在中间表的外键
    private Set<User> users=new HashSet<>();

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Set<User> getUsers() {
        return users;
    }

    public void setUsers(Set<User> users) {
        this.users = users;
    }
}


测试类

@RunWith(SpringJUnit4ClassRunner.class)//声明spring提供的单元测试环境
@ContextConfiguration(locations = "classpath:spring-data-jpa-config.xml")
public class ManyToMany {

    @Autowired
    private UserDao userDao;
    @Autowired
    private RoleDao roleDao;

    @Test@Transactional@Rollback(false)
    public void add(){
        User user=new User();
        user.setName("kobe");

        Role role=new Role();
        role.setName("basketball-player");

        user.getRoles().add(role);

        userDao.save(user);
        roleDao.save(role);
    }
}

查询结果
SpringDataJPA入门学习总结笔记_第44张图片
SpringDataJPA入门学习总结笔记_第45张图片
SpringDataJPA入门学习总结笔记_第46张图片
SpringDataJPA入门学习总结笔记_第47张图片


在多对多(保存)中,如果双向都设置关系,意味着双方都维护中间表,都会往中间表插入数据,中间表的2个字段又作为联合主键,所以报错,主键重复,解决保存失败的问题:只需要在任意一方放弃对中间表的维护权即可,推荐在被动的一方放弃,配置如下:
修改Role类中的属性

	@ManyToMany(mappedBy = "roles")
    private Set<User> users=new HashSet<>();

级联操作
在User类的多读多注解添加cascade属性
SpringDataJPA入门学习总结笔记_第48张图片
测试方法

@Test@Transactional@Rollback(false)
    public void addCascade(){
        User user=new User();
        user.setName("kobe");

        Role role=new Role();
        role.setName("basketball-player");

        user.getRoles().add(role);

        userDao.save(user);//只需要保存用户

    }

运行,查看数据库,role表插入记录
SpringDataJPA入门学习总结笔记_第49张图片
删除记录,先将配置文件中创建数据库方式设置为update

@Test@Transactional@Rollback(false)
    public void delete(){
        userDao.deleteById(1L);
    }

成功删除3个表中数据
SpringDataJPA入门学习总结笔记_第50张图片


对象导航查询

含义:查询一个对象(get方法查询)的同时,通过此对象可以查询它的关联对象
案例:客户和联系人(一对多)

从客户查询联系人

@RunWith(SpringJUnit4ClassRunner.class)//声明spring提供的单元测试环境
@ContextConfiguration(locations = "classpath:spring-data-jpa-config.xml")
public class QueryTest {
    @Autowired
    private CustomerDao customerDao;
    
	@Autowired
    private LinkmanDao linkmanDao;
    
    @Test@Transactional
    public void test(){
        Customer customer = customerDao.getOne(1L);
        Set<Linkman> linkmen = customer.getLinkmen();
        for (Linkman linkman : linkmen) {
            System.out.println(linkman);
        }
    }
}

通过客户对象可直接查询联系人
SpringDataJPA入门学习总结笔记_第51张图片
对象导航查询一到多默认使用延迟加载的形式查询,如果要使用立即加载,在实体类注解配置加上fetch属性。
在这里插入图片描述


从联系人查询客户

@Test@Transactional
    public void test2(){
        Linkman linkman = linkmanDao.getOne(1L);
        Customer customer = linkman.getCustomer();
        System.out.println(customer);
    }

SpringDataJPA入门学习总结笔记_第52张图片
对象导航查询多到一默认使用立即加载的形式查询。


总结
从一查多 默认使用延迟加载 关联对象是集合 使用立即加载可能浪费资源
从多查一 默认使用立即加载 关联对象是一个对象 所以使用立即加载

你可能感兴趣的:(SSM,JAVA)