JPA入门总结

1.Hibernate的概述

Hibernate是一个开放源代码对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的JavaEE架构中取代CMP,完成数据持久化的重任。

JPA入门总结

1.JAP入门

1.开发准备

	/*创建客户表*/
    CREATE TABLE cst_customer (
      cust_id BIGINT(32) NOT NULL 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 '客户联系电话',
      PRIMARY KEY (`cust_id`)
    ) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

2.添加依赖

 <!--添加依赖-->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.hibernate.version>5.0.7.Final</project.hibernate.version>
    </properties>

    <dependencies>
        <!-- junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <!-- hibernate对jpa的支持包 -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>${project.hibernate.version}</version>
        </dependency>

        <!-- c3p0 -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-c3p0</artifactId>
            <version>${project.hibernate.version}</version>
        </dependency>

        <!-- log日志 -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

        <!-- Mysql and MariaDB -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
         <!--添加lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.16</version>
        </dependency>

    </dependencies>

3.编写pojo

//标志实体类
@Entity
//映射表
@Table(name = "cst_customer")
//添加get()set方法
@Data
public class Customer implements Serializable {
     @Id  //把一个属性标记成主键
     @GeneratedValue(strategy = GenerationType.IDENTITY) //主键生成侧列
     @Column(name = "cust_id")  //属性名和表字段进行映射
    private Long    custId;
    @Column(name = "cust_name")
    private String  custName;
    @Column(name = "cust_source")
    private String  custSource;
    @Column(name = "cust_Industry")
    private String  custIndustry;
    @Column(name = "cust_level")
    private String  custIevel;
    @Column(name = "cust_address")
    private String  custAddress;
    @Column(name = "cust_phone")
    private String  custPhone;
}

4.编写配置文件

JPA入门总结

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
    http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
             version="2.0">

    <!-- 持久化单元
    name: 持久化单元名称
    transaction-type: 事务类型
            RESOURCE_LOCAL: 本地事务
            JTA: Java Transaction API : 跨数据库的事务
    -->
    <persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL">
        <!-- 指定提供商 -->
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <!-- 配置属性:链接数据库的四要素,可选的配置,例如显示sql语句 -->
        <properties>
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://192.168.93.222:3306/day19?useUnicode=true&amp;characterEncoding=UTF-8"/>
            <property name="javax.persistence.jdbc.user" value="root"/>
            <property name="javax.persistence.jdbc.password" value="root"/>

            <!-- 显示sql语句 -->
            <property name="hibernate.show_sql" value="true"/>
        </properties>
    </persistence-unit>

</persistence>

5测试

核心步骤

	 * 步骤:
	 * 	1、加载配置文件创建实体类管理器工厂
	 * 	2、通过工厂 创建实体类管理器
	 * 	3、获取事务对象
	 * 	4、开启事务
	 * 	5、CRUD:保存客户实体
	 * 	6、提交事务
	 * 	7、释放资源

测试代码

 @Test
    public void show(){

        Customer customer = new Customer();
        customer.setCustName("行健乖乖把");
        customer.setCustIevel("永恒砖石");
        //步骤:
	 //1、加载配置文件创建实体类管理器工厂
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa");

        //2、通过工厂 创建实体类管理器
        EntityManager entityManager = factory.createEntityManager();
        //3、获取事务对象
        EntityTransaction tx = entityManager.getTransaction();
        //4、开启事务
        tx.begin();
     //5、CRUD:保存客户实体
        entityManager.persist(customer);
    //6、提交事务
        tx.commit();
    //7、释放资源
        entityManager.close();
        factory.close();
    }

6.JPA总结

  1. 创建工程,添加依赖

  2. 创建实体类和创建数据库

  3. 进行JPA的映射

    • @Entity 实体类映射
    • @Table(name = “cst_customer”) 表的映射 参数name表示表名
    • @Id //把一个属性标记成主键
    • @GeneratedValue(strategy = GenerationType.IDENTITY) //主键生成侧列
    • @Column(name = “cust_id”) //属性名和表字段进行映射 参数name 表示数据库字段
  4. 配置JPA的核心文件

    • 文件名: persistence.xml
    • 目录:META-INF
  5. 测试保存一个用户

    • 加载配置文件创建实体类管理共仓
    • 通过工厂 创建实体类管理器
    • 获取事务对象
    • 开启事务对象
    • 开始事务
    • CRUD:保存用户
    • 提交事务
    • 释放资源

3.JPA的核心API的介绍

1、Persistence 重要程度:一般

作用:用于加载配置文件创建实体类管理器工厂
主要方法:
	createEntityManagerFactory("持久化单元名称")

2、EntityManagerFactory 重要程度:比较重要

作用:用于创建实体类管理器
常用方法:
	createEntityManager()
	close()
细节:
	1、这个类是个重量级的类:维护了全字段的CRUD的sql语句,二级缓存
	2、这个类是线程安全的类,多线程环境下不会出现线程安全并发问题
使用:
	一个web项目应该只有一个这个对象

3、EntityManager 重要程度:非常重要

作用:与数据库的交互都是他完成,事务对象也是他获取的
常用的方法:
	getTransaction()
	persist()
	close
	find
	getReference
	....
细节:
	1、由于工厂已经维护了较多的信息,所以这个类维护的信息就少了,所以他是一个轻量级对象
	2、他是线程不安全的
使用:
	一个线程只有一个这个对象,一次请求

4、EntityTransaction 重要程度:会用就行

作用:控制事务
常用方法:
	begin
	commit
	rollback

4.抽取JPA的工具类:JpaUtil

public class JpaUtil {

    private static EntityManagerFactory myJpa;

    /*
    * 静态的加载
    * */
    static {
        myJpa = Persistence.createEntityManagerFactory("myJpa");
    }

    /*
    * 实体类管理器
    * */
    public static EntityManager getEntityManager(){
     return myJpa.createEntityManager();
    }

    /*
    * 关闭资源
    * */

    public static void close(EntityManager entityManager){
        if (entityManager!=null){
            entityManager.close();
        }
    }
}


5.JPA的CRUD

1.添加数据

    /*
    * 添加数据包
    * */

    @Test
    public void show(){

        Customer customer = new Customer();
        customer.setCustName("行健乖乖把");
        customer.setCustIevel("VIP");
        EntityManager entityManager = JpaUtil.getEntityManager();
//        //3、获取事务对象
        EntityTransaction tx = entityManager.getTransaction();
        //4、开启事务
        tx.begin();
     //5、CRUD:保存客户实体
        entityManager.persist(customer);
    //6、提交事务
        tx.commit();
    //7、释放资源
        JpaUtil.close(entityManager);


    }


2.删除数据

    /*
    * 删除数据
    * */
@Test
    public void delete(){
//获取实体类管理器
        EntityManager entityManager = JpaUtil.getEntityManager();
//        获取事务对象
        EntityTransaction tx = entityManager.getTransaction();
//开启事务
        tx.begin();

    Customer customer1 = entityManager.find(Customer.class, 1L);

    entityManager.remove(customer1);
//        提交事务
    tx.commit();
//
    JpaUtil.close(entityManager);


    }

3.更新数据

    /*
    * 更新数据
    * */

    @Test
    public void update(){
//        获取实体类的管理器
        EntityManager entityManager = JpaUtil.getEntityManager();

//        获取事务对象
        EntityTransaction tx= entityManager.getTransaction();
//        开启事务
        tx.begin();
//先查询在更新
        Customer customer = entityManager.find(Customer.class, 2L);
        customer.setCustName("来了老弟");

        entityManager.persist(customer);

//        提交事务
        tx.commit();
       JpaUtil.close(entityManager);

    }


4.查询数据

     /*
     * 查询全部数据
     * */
    @Test
    public void findList(){
        EntityManager entityManager = JpaUtil.getEntityManager();
        Query query = entityManager.createQuery("from Customer");
        List<Customer> resultList = query.getResultList();
        resultList.forEach(o-> System.out.println("o = " + o));

    }


    /*
    * 根据id查询数据
    * */
    @Test
    public void findById(){

//        获取实体类的管理器
        EntityManager entityManager = JpaUtil.getEntityManager();
//根据id查询信息
        Customer customer = entityManager.find(Customer.class, 2L);
        System.out.println("customer = " + customer);


    }


6.JPQL查询

1.JPQL查询全部数据

    @Test
    public void show(){

        EntityManager entityManager = JpaUtil.getEntityManager();

        String  sql="from Customer";
        Query query = entityManager.createQuery(sql);

        List resultList = query.getResultList();

        resultList.forEach(o -> System.out.println("o = " + o));

    }

2.JPQL分页查询

JPA分页分析:

mysql: limit ? 查询前面n条

​ limit ? ,?

​ 第一个参数:开始索引=(当前页-1)* 页大小

​ 第二个参数:页大小

    /*
    * 分页
    * */
    @Test
    public void show1(){

        EntityManager entityManager = JpaUtil.getEntityManager();
        Query query = entityManager.createQuery("from Customer ");
//        设置分页条件  :页大小
        query.setFirstResult(1);  //(2-1)*2
        query.setMaxResults(2);

        List resultList = query.getResultList();
        resultList.forEach(p-> System.out.println("p = " + p));


    }

3.JPQL条件查询

    /*
    * 多条件查询
    * */
    @Test
    public void show5(){
        EntityManager entityManager = JpaUtil.getEntityManager();
//创建查询条件
        Query query = entityManager.createQuery("from Customer where custName like ? and custIevel= ? ");

        query.setParameter(1,"行健%");
        query.setParameter(2,"VIP");

        List resultList = query.getResultList();
        resultList.forEach(o-> System.out.println("o = " + o));

    }


/*
* 模糊查询
* */
@Test
    public void show4(){
        EntityManager entityManager = JpaUtil.getEntityManager();
//创建查询条件
        Query query = entityManager.createQuery("from Customer where custName like ?");
//        对占位符赋值
    query.setParameter(1,"行健%");

    List resultList = query.getResultList();

    resultList.forEach(p-> System.out.println("p = " + p));

}


    /*
    * 精确查询
    * */
    @Test
    public void show3(){
        EntityManager entityManager = JpaUtil.getEntityManager();
//创建查询条件
        Query query = entityManager.createQuery("from Customer where custName= ?");

        query.setParameter(1,"来了老弟");

        List resultList = query.getResultList();
        resultList.forEach(p-> System.out.println("p = " + p));


    }

4.JPQL查询:排序,统计查询

    /*
    * 排序
    * */
    @Test
    public void show6(){
        EntityManager entityManager = JpaUtil.getEntityManager();
        Query query = entityManager.createQuery("from Customer where custName like ? order by custId desc");

        query.setParameter(1,"行健%");

        List resultList = query.getResultList();
        resultList.forEach(o-> System.out.println("o = " + o));
    }

    /**
     * 统计查询: 一行一列: 一个数字
     */
    @Test
    public void test5() {
        EntityManager em = JpaUtil.getEntityManager();
        EntityTransaction tx = em.getTransaction();
        tx.begin();
        //统计
        /**
         * select count(*) 约等于 count(1)  mysql5.7之后
         * select count(id)
         * select count(1)
         */
        Query query = em.createQuery("select avg(custId) from Customer where custName like ?");
        //对占位符赋值
        query.setParameter(1, "行健%");

        //获取结果集
        List<Double> list = query.getResultList();
        //迭代
        for (Double l : list) {
            System.out.println("============================="+l);
        }
    }



2.SpringDateJpa入门

1.JPA入门

1.导入依赖

    <properties>
        <spring.version>5.0.2.RELEASE</spring.version>
        <hibernate.version>5.0.7.Final</hibernate.version>
        <slf4j.version>1.6.6</slf4j.version>
        <log4j.version>1.2.12</log4j.version>
        <c3p0.version>0.9.1.2</c3p0.version>
        <mysql.version>5.1.18</mysql.version>
    </properties>

    <dependencies>
        <!-- junit单元测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <!-- spring beg -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.6.8</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- spring end -->

        <!-- hibernate beg -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.2.1.Final</version>
        </dependency>
        <!-- hibernate end -->

        <!-- c3p0 beg -->
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>${c3p0.version}</version>
        </dependency>
        <!-- c3p0 end -->

        <!-- log end -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j.version}</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <!-- log end -->


        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>

        <!-- SpringDataJpa核心包 -->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
            <version>1.9.0.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- el beg 使用spring data jpa 必须引入 -->
        <dependency>
            <groupId>javax.el</groupId>
            <artifactId>javax.el-api</artifactId>
            <version>2.2.4</version>
        </dependency>

        <dependency>
            <groupId>org.glassfish.web</groupId>
            <artifactId>javax.el</artifactId>
            <version>2.2.4</version>
        </dependency>
        <!-- el end -->

<!--添加lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
        </dependency>

    </dependencies>

2.编写编写文件

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


    <!-- SpringDataJpa配置 -->
    <!-- 1、EntityManagerFactory 交给spring管理-->
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <!-- 1、扫描实体类的包 -->
        <property name="packagesToScan" value="com.xjggb.pojo"></property>
        <!-- 2、引用数据源 -->
        <property name="dataSource" ref="dataSource"></property>
        <!-- 3、配置jpa的提供商 -->
        <property name="persistenceProvider">
            <bean class="org.hibernate.jpa.HibernatePersistenceProvider"></bean>
        </property>
        <!-- 4、jpa提供商的适配器-->
        <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>
        <!-- 5、JPA方言:可以使用jpa的高级特性 -->
        <property name="jpaDialect">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"></bean>
        </property>
        <!-- 6、让hibenrate维护表结构 -->
        <property name="jpaProperties">
            <props>
                <!--
                create: 每次都先删除表,再创建表
                update: 如果有变,而且属性和字段不一致,更新表;如果没有表,会创建表
                none: 跟没配置是一样的,什么也不干
                 -->
                <prop key="hibernate.hbm2ddl.auto">create</prop>
            </props>
        </property>
    </bean>
    <!-- 2、配置数据源 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://192.168.93.222:3306/day19"></property>
        <property name="user" value="root"></property>
        <property name="password" value="root"></property>
    </bean>
    <!-- 3、平台事务管理器 -->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"></property>
    </bean>


    <!-- 4、SpringDataJpa的配置
    base-package: 基础包,基包:dao接口所在的包
    entity-manager-factory-ref: 引用实体类管理器工厂
    transaction-manager-ref: 平台事务管理器
    -->
    <jpa:repositories base-package="com.xjggb.mapper" entity-manager-factory-ref="entityManagerFactory" transaction-manager-ref="transactionManager"></jpa:repositories>
    <!-- 5、开启组件的扫描-->
    <context:component-scan base-package="com.xjggb"></context:component-scan>

</beans>

注意

 <!-- 6、让hibenrate维护表结构 -->
        <property name="jpaProperties">
            <props>
                <!--
                create: 每次都先删除表,再创建表
                update: 如果有变,而且属性和字段不一致,更新表;如果没有表,会创建表
                none: 跟没配置是一样的,什么也不干
                 -->
                <prop key="hibernate.hbm2ddl.auto">create</prop>
            </props>
        </property>

3.编写实体类

package com.xjggb.pojo;

import lombok.Data;

import javax.persistence.*;
import java.io.Serializable;

@Entity
@Table(name="cst_customer")
@Data
public class Customer implements Serializable {

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

    @Column(name="cust_name")
    private String custName;

    @Column(name="cust_source")
    private String custSource;

    @Column(name="cust_industry")
    private String custIndustry;

    @Column(name="cust_level")
    private String custLevel;

    @Column(name="cust_address")
    private String custAddress;

    @Column(name="cust_phone")
    private String custPhone;

}


4.编写Mapper接口

public interface CustomerMapper extends JpaRepository<Customer,Long>, JpaSpecificationExecutor<Customer> {
}

5.测试

//指定运行期
@RunWith(SpringJUnit4ClassRunner.class)
//加载配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class JpaTest {

    @Autowired
    private CustomerMapper customerMapper;

    /*
    * 查询一个对象
    * */
    @Test
    public void show(){

        Customer one = customerMapper.findOne(2L);

        System.out.println("one = " + one);
    }
    
}

2.JPA -CRUD

//指定运行期
@RunWith(SpringJUnit4ClassRunner.class)
//加载配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class JpaTest2 {

    @Autowired
    private CustomerMapper customerMapper;





    /*
    * 添加对象
    * */
    @Test
    public void show(){
        Customer customer = new Customer();
        customer.setCustName("冰糖雪梨");
        customer.setCustLevel("嘴强王者");
        customerMapper.save(customer);

    }

    /*
    * 删除数据
    * */
    @Test
    public void show1(){
   customerMapper.delete(4L);
    }


    /*
    * 更新数据
    * */
@Test
    public void show3(){
     //先查询在更新
        Customer one = customerMapper.findOne(2L);
        one.setCustName("我叫行健乖乖霸");
        System.out.println("one = " + one);
        customerMapper.save(one);


    }

    /*
    * 查询全部数据
    * */

    @Test
    public void show4(){
     //查询全部数据
        List<Customer> all = customerMapper.findAll();
        all.forEach(p-> System.out.println("p = " + p));

    }
}


小结
  1. 创建maven工程
  2. 编写spring的配置文件applicationContext.xml文件
  3. 编写配置类 jpa的注解
  4. 编写mapper接口 继承两个接口 1.JpaRepository<实体类,主键类型> 2.JpaSpecificationExecutor<实体类>
  5. 测试CRUD

3.接口方法定义查询

1.查询一个的两种方式

    /*
    * 查询一个的两种方式
    * */

    @Test
    @Transactional
    public void show(){

//        Customer one = customerMapper.findOne(3L);//立即加载
        Customer one = customerMapper.getOne(3L);
        System.out.println("one = " + one);  //
    }


2.分页查询+排序查询

   /*
    * 分页查询
    * */
    @Test
    public void show2(){
        /*
        * 分页查询
        * 参数一 当前页 
        * 参数二 页大小
        * 参数三 排序对象   【可选】
        * */
        PageRequest pageRequest = new PageRequest(2,2);

//执行分页查询
        Page<Customer> all = customerMapper.findAll(pageRequest);
        System.out.println("获取总记录数 " + all.getTotalElements());
        System.out.println("总页数" + all.getTotalPages());

        List<Customer> content = all.getContent();
        for (Customer customer : content) {
            System.out.println("customer = " + customer);
        }


    }



    /*
    * 分页查询+排序查询
    * */
    @Test
    public void show2(){

//        排序规则 倒叙
        Sort orders = new Sort(Sort.Direction.DESC,"custId");

        /*
        * 分页查询
        * 参数一 当前页
        * 参数二 页大小
        * 参数三 排序对象
        * */
        PageRequest pageRequest = new PageRequest(2,2,orders);

//执行分页查询
        Page<Customer> all = customerMapper.findAll(pageRequest);
        System.out.println("获取总记录数 " + all.getTotalElements());
        System.out.println("总页数" + all.getTotalPages());

        List<Customer> content = all.getContent();
        for (Customer customer : content) {
            System.out.println("customer = " + customer);
        }


    }



3.查询统计和判断对象是否存在

    /*
    * 统计所有\
    * 相当于  select count(*) from  表
    * */

    @Test
    public void show4(){

        long count = customerMapper.count();
        System.out.println("count = " + count);
    }



    /*
    * 判断一个对象是否存在
    * 存在为 true 不存在为 false
    * 相当于 select * from 表 where id=?
    * */
    @Test
    public void show3(){
        boolean exists = customerMapper.exists(4L);
        System.out.println("equals = " + exists);
    }


4.JPQL查询操作

1.方式一 查询操作

掌握@Query注解

JPQL查询规则:

	1)在dao接口中编写方法
	2)在方法上使用@Query(value="JPQL语句")
	3)返回值,自己定,如果是单个对象,你就写单个对象,如果多个,就用List

mapper代码

  /*
    * 精确查询
    * */
    @Query(value="from Customer  where  custName= ?")
    Customer findJPQL1(String l);

    /*
    *模糊查询
    * */
    @Query(value="from Customer where custName like ?")
    List<Customer> findListJPQL(String s);

    /*
    * 多条件查询
     * 默认情况下:方法参数的所有与 占位符的索引一致,如果数据类型不一致,会报错
     * 我们可以手动改变索引:只需要在占位符后面加上方法参数的索引即可
    * */
    @Query(value="from Customer where custId =?2 or custName like ?1")
    List<Customer> findJPQL3(String o ,Long id);




测试

package com.xjggb.test;

import com.xjggb.mapper.CustomerMapper;
import com.xjggb.pojo.Customer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.List;

//指定运行期
@RunWith(SpringJUnit4ClassRunner.class)
//加载配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class JpaTest4 {

    @Autowired
    private CustomerMapper customerMapper;


    /*
     * 精确查询
     * */
    @Test
    public void show2(){
        Customer customer = customerMapper.findJPQL1("冰糖雪梨");
        System.out.println("customer = " + customer);
    }


    /*
     * 模糊查询
     * */
    @Test
    public void show(){
        List<Customer> listJPQL = customerMapper.findListJPQL("行健%");
        listJPQL.forEach(u-> System.out.println("u = " + u));

        System.out.println();
    }


    /*
     *多条件查询
     * */
    @Test
    public void show3(){
        List<Customer> jpql3 = customerMapper.findJPQL3("行健%", 3L);
        jpql3.forEach(o-> System.out.println("o = " + o));
        System.out.println();
    }

}



2.方式二查询更新操作

目标:掌握如何使用JPQL实现更新对象的操作

dao接口的要求:

1) 在Query的value属性中编写的update的jpql语句

2)dao接口的方法上还需要加入一个注解:@Modifying

测试的要求:

1)需要事务

2)在测试阶段,如果用的是spring的测试,执行成功之后就自动回滚了,看到效果,需要加注解:@Rollback(false)

mapper代码

    /*
    * 更新操作
    * */
    @Modifying //标记为更新操作
    @Query(value="update Customer set custName=?2 where custId=?1")
    void updateJPQL(Long id ,String nmae);

测试代码

    /*
    * 更新操作
    * */

    @Test
    //由于我们现在用的Spring的测试,所以在测试成功之后,spring就给我们回滚了
    //在测试阶段,如果想看到结果,需要加入另外一个注解,注意这个注解在非测试代码不用加
    //TransactionRequiredException: Executing an update/delete query  事务异常

    @Transactional
    @Rollback(false)
    public void show4(){
    customerMapper.updateJPQL(2L,"隔壁老王");

    }


3.方式三sql查询

sql查询规则

	1)在dao接口中编写方法
	2)在方法上使用@Query(value="SQL语句",nativeQuery=true)nativeQuery=true 开启sql语句查询
	3)返回值,自己定,如果是单个对象,你就写单个对象,如果多个,就用List

mapper代码

    /**
     * sql查询
     * nativeQuery=true  开启sql查询
     */
    @Query(value="select * from cst_customer where cust_name like ?2 or cust_id = ?1",nativeQuery=true)
    public List<Customer> findSQL(Long id, String name);


测试代码

    /*
    * sql查询
    * */
    @Test
    public void show5(){
        List<Customer> sql = customerMapper.findSQL(3L, "行健%");
        sql.forEach(o-> System.out.println("o = " + o));
    }


4.方式四根据方法名规则查询

Dao接口的方法名规则:

	1)以findBy开头
	2)后面跟的是查询的属性条件: 属性名首字母大写
	3)属性名后面跟的是查询规则: 模糊【Like】、精确 【不加规则代表精确查询】
	4)多个条件以  And 、 Or 拼接
	5)重复上面的步骤,从2开始

mapper接口

//    精确查询
    Customer findByCustName(String name);

//    模糊查询
    List<Customer> findByCustNameLike(String name);

//    多条件查询
    List<Customer> findByCustNameOrCustId(String name , Long id);

测试

    /*
    * 多条件查询
    * */
    @Test
    public void show8(){

        List<Customer> p = customerMapper.findByCustNameOrCustId("冰糖雪梨", 8L);
        p.forEach(o-> System.out.println("o = " + o));
    }



    /*
    * 精确查询
    * */
    @Test
    public void show7(){
        Customer o = customerMapper.findByCustName("冰糖雪梨");
        System.out.println("o = " + o);
    }

    /*
    * 模糊查询
    * */
    @Test
    public void show6(){

        List<Customer> byCustNameLike = customerMapper.findByCustNameLike("行健%");
        byCustNameLike.forEach(o->System.out.println("byCustNameLike = " + o));
    }


规则的关键字:

Keyword 方法名举例 JPQL
And findByLastnameAndFirstname … where x.lastname = ?1 and x.firstname = ?2
Or findByLastnameOrFirstname … where x.lastname = ?1 or x.firstname = ?2
Is,Equals findByFirstnameIs, findByFirstnameEquals … where x.firstname = ?1
Between findByStartDateBetween … where x.startDate between ?1 and ?2
LessThan findByAgeLessThan … where x.age < ?1
LessThanEqual findByAgeLessThanEqual … where x.age ⇐ ?1
GreaterThan findByAgeGreaterThan … where x.age > ?1
GreaterThanEqual findByAgeGreaterThanEqual … where x.age >= ?1
After findByStartDateAfter … where x.startDate > ?1
Before findByStartDateBefore … where x.startDate < ?1
IsNull findByAgeIsNull … where x.age is null
IsNotNull,NotNull findByAge(Is)NotNull … where x.age not null
Like findByFirstnameLike … where x.firstname like ?1
NotLike findByFirstnameNotLike … where x.firstname not like ?1
StartingWith findByFirstnameStartingWith … where x.firstname like ?1 (parameter bound with appended %)
EndingWith findByFirstnameEndingWith … where x.firstname like ?1 (parameter bound with prepended %)
Containing findByFirstnameContaining … where x.firstname like ?1 (parameter bound wrapped in %)
OrderBy findByAgeOrderByLastnameDesc … where x.age = ?1 order by x.lastname desc
Not findByLastnameNot … where x.lastname <> ?1
In findByAgeIn(Collection ages) … where x.age in ?1
NotIn findByAgeNotIn(Collection age) … where x.age not in ?1
TRUE findByActiveTrue() … where x.active = true
FALSE findByActiveFalse() … where x.active = false
IgnoreCase findByFirstnameIgnoreCase … where UPPER(x.firstame) = UPPER(?1)

3.Specification动态查询介绍

JpaSpecificationExecutor 接口 介绍:完成复杂查询和动态查询

JpaSpecificationExecutor<T> {
	T findOne(Specification<T> spec);
	List<T> findAll(Specification<T> spec);
	Page<T> findAll(Specification<T> spec, Pageable pageable);
	List<T> findAll(Specification<T> spec, Sort sort);
	long count(Specification<T> spec);
}

Specification:它是一个接口,所有的动态拼接的条件都在这个接口的方法里完成

public interface Specification<T> {
	Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);
}

它只有一个方法:toPredicate,此方法有三个参数

第一个:Root :获取对象的属性的

第二个:CriteriaQuery :查询的顶层接口,他可以完成自定义查询,一般不用

第三个:CriteriaBuilder :动态构建查询条件,都用它

1.Specification查询:精确、模糊、多条件查询

//指定运行期
@RunWith(SpringJUnit4ClassRunner.class)
//加载配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class JpaTest5 {

    @Autowired
    private CustomerMapper customerMapper;
    /*
    * 多条件查询
    * */

    @Test
    public void show(){
        Specification<Customer> spec = new Specification<Customer>() {
            @Override
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cd) {

//                获取对比属性
                Path<String> custName = root.get("custName");
                Path<Object> custLevel = root.get("custLevel");

//                构建查询条件
                Predicate like = cd.like(custName, "行健%");
                Predicate equal = cd.equal(custLevel, "VIP");

//                合并查询条件
                Predicate or = cd.or(like, equal);
                return or;
            }
        };


        List<Customer> all = customerMapper.findAll(spec);
        all.forEach(o-> System.out.println("o = " + o));
    }
}


2.Specification查询:分页与排序查询

    /*
    * 分页排序
    * */

    @Test
    public void show2(){
//        相当于where
        Specification<Customer> spec =null;


//        排序
        Sort orders = new Sort(Sort.Direction.DESC,"custId");

//        分页
        PageRequest pageRequest = new PageRequest(0, 2, orders);


        Page<Customer> all = customerMapper.findAll(spec, pageRequest);

        System.out.println("获取总记录数 " + all.getTotalElements());
        System.out.println("获取页数" + all.getTotalPages());
        all.getContent().forEach(o-> System.out.println("o = " + o));


    }

4.一对多映射

1.一对多单向保存

1.第一步

使用带入法 一对多

客户表   :  一方  一个客户可一有多个联系人
联系人表 :  多方 一个联系只能属于一家公司

2.第二步

找主外键

多方【从表】:外键在多方中

一方【主表】:外键的值来源于一方的主键

JPA入门总结

3.第三步:

在实体类中描述他们的关系

类类与类的关系 :继承和包含

我们才用包含

客户包含多个联系人 :List / Set

联系人包含一个联系人 Customer

客户实体类代码

package com.xjggb.pojo;

import lombok.Data;

import javax.persistence.*;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

@Entity
@Table(name="cst_customer")
@Data
public class Customer implements Serializable {

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

    @Column(name="cust_name")
    private String custName;

    @Column(name="cust_source")
    private String custSource;

    @Column(name="cust_industry")
    private String custIndustry;

    @Column(name="cust_level")
    private String custLevel;

    @Column(name="cust_address")
    private String custAddress;

    @Column(name="cust_phone")
    private String custPhone;

    //当前是一方
    /**
     * new :
     * 		1、如果new出当前方法,集合也会实例化
     * 		2、我们为了解决有可能出现的空指针异常,new,我们可以在new的时候指定开辟的大小
     *
     * 不new:
     * 		容器用来装联系人实体
     * 		customer.getLinkman().add(new Linkman())
     * 		有可能出现空指针异常
     *
     */

//  配置一对多关系注解
    //配置一对多
     @OneToMany(targetEntity = Linkman.class)
//     配置外键注解

     @JoinColumn(
//             外键名称
             name = "lkm_cust_id",
//             外键值的来源:来源于主表的主键
             referencedColumnName = "cust_id"
     )
    private Set<Linkman> linkmen=new HashSet<>(0);


}


Linkman联系人实体类

package com.xjggb.pojo;

import lombok.Data;

import javax.persistence.*;
import java.io.Serializable;

@Entity
@Table(name = "cst_linkman")
@Data
public class Linkman implements Serializable {

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

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

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

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

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

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

    @Column(name="lkm_position")
    private String lkmPosition;

    @Column(name="lkm_memo")
    private String lkmMemo;




    //当前是多方
//    关系注解 多对一
    @ManyToOne(targetEntity = Customer.class)
//    外键注解
    @JoinColumn(
//             外键名称
            name = "lkm_cust_id",
//             外键值的来源:来源于主表的主键
            referencedColumnName = "cust_id"
    )

    private Customer customer;

}


4.第四步

package com.xjggb.test;

import com.xjggb.mapper.CustomerMapper;
import com.xjggb.mapper.LinkmanMapper;
import com.xjggb.pojo.Customer;
import com.xjggb.pojo.Linkman;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;

//指定运行期
@RunWith(SpringJUnit4ClassRunner.class)
//加载配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class JpaTest6 {

    @Autowired
    private CustomerMapper customerMapper;

    @Autowired
    private LinkmanMapper linkmanMapper;

	/**
	 * 单向保存:
	 * 		一对多的保存原则: 先保存主表的数据,再保存从表的数据
	 */
    @Test
    @Transactional
@Rollback(false)
    public void show(){

        Customer customer = new Customer();
        customer.setCustName("行健乖乖把");

        Linkman linkman = new Linkman();
        linkman.setLkmName("吾乃行健乖乖把");
        linkman.setLkmPosition("CEO");
//要想外键有值,必须配置关系:
        //1、让客户来维护关系: 客户通过update的语句来维护外键
       // customer.getLinkmen().add(linkman);

        //2、让联系人维护外键: 联系人通过insert语句就可以维护外键【让联系人维护外键的效率高,少了update的语句】
       linkman.setCustomer(customer);

        //保存:先保存主表的数据,再保存从表的数据

//        保存主表的数据,在保存从表的数
        customerMapper.save(customer);

       linkmanMapper.save(linkman);


    }


}


2.一对所双向bao存

分析

如果是双向保存,会有两条insert 和 一条update

原因:多出的这一条update语句,是由于客户维护外键导致的

解决:
	不想看到多出的这一条update的语句
	让客户不维护外键就可以
	删除@JoinColumn注解

1.客户实体类

package com.xjggb.pojo;

import lombok.Data;

import javax.persistence.*;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;



/**
 * 实体类
 * @author Johnny.Chen
 *
 */

@Entity
@Table(name="cst_customer")
public class Customer implements Serializable{

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

    @Column(name="cust_name")
    private String custName;

    @Column(name="cust_source")
    private String custSource;

    @Column(name="cust_level")
    private String custLevel;

    @Column(name="cust_industry")
    private String custIndustry;

    @Column(name="cust_phone")
    private String custPhone;

    @Column(name="cust_address")
    private String custAddress;


    //当前是一方
    /**
     * new :
     * 		1、如果new出当前方法,集合也会实例化
     * 		2、我们为了解决有可能出现的空指针异常,new,我们可以在new的时候指定开辟的大小
     *
     * 不new:
     * 		容器用来装联系人实体
     * 		customer.getLinkman().add(new Linkman())
     * 		有可能出现空指针异常
     *
     */
    //配置一对多的关系注解
    //客户维护外键
	/*//1、关系注解:一对多
	@OneToMany(targetEntity=Linkman.class)
	//2、外键注解
	@JoinColumn(
			//外键名称
			name="lkm_cust_id",
			//外键值的来源: 来源于主表的主键
			referencedColumnName="cust_id"
	)*/

    //客户不维护外键
    @OneToMany(mappedBy="customer")//mappedBy: 配置的对方有@JoinColumn注解的属性的名称
    private Set<Linkman> linkmans = new HashSet<>(0);

    /**
     * 获取
     * @return custId
     */
    public Long getCustId() {
        return custId;
    }

    /**
     * 设置
     * @param custId
     */
    public void setCustId(Long custId) {
        this.custId = custId;
    }

    /**
     * 获取
     * @return custName
     */
    public String getCustName() {
        return custName;
    }

    /**
     * 设置
     * @param custName
     */
    public void setCustName(String custName) {
        this.custName = custName;
    }

    /**
     * 获取
     * @return custSource
     */
    public String getCustSource() {
        return custSource;
    }

    /**
     * 设置
     * @param custSource
     */
    public void setCustSource(String custSource) {
        this.custSource = custSource;
    }

    /**
     * 获取
     * @return custLevel
     */
    public String getCustLevel() {
        return custLevel;
    }

    /**
     * 设置
     * @param custLevel
     */
    public void setCustLevel(String custLevel) {
        this.custLevel = custLevel;
    }

    /**
     * 获取
     * @return custIndustry
     */
    public String getCustIndustry() {
        return custIndustry;
    }

    /**
     * 设置
     * @param custIndustry
     */
    public void setCustIndustry(String custIndustry) {
        this.custIndustry = custIndustry;
    }

    /**
     * 获取
     * @return custPhone
     */
    public String getCustPhone() {
        return custPhone;
    }

    /**
     * 设置
     * @param custPhone
     */
    public void setCustPhone(String custPhone) {
        this.custPhone = custPhone;
    }

    /**
     * 获取
     * @return custAddress
     */
    public String getCustAddress() {
        return custAddress;
    }

    /**
     * 设置
     * @param custAddress
     */
    public void setCustAddress(String custAddress) {
        this.custAddress = custAddress;
    }

    /**
     * 获取
     * @return linkmans
     */
    public Set<Linkman> getLinkmans() {
        return linkmans;
    }

    /**
     * 设置
     * @param linkmans
     */
    public void setLinkmans(Set<Linkman> linkmans) {
        this.linkmans = linkmans;
    }

}


2.联系人实体类

package com.xjggb.pojo;

import lombok.Data;

import javax.persistence.*;
import java.io.Serializable;


/**
 * 联系人
 * @author Johnny.Chen
 *
 */

@Entity
@Table(name="cst_linkman")
public class Linkman implements Serializable{

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

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

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

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

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

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

    @Column(name="lkm_position")
    private String lkmPosition;

    @Column(name="lkm_memo")
    private String lkmMemo;


    //当前是多方
    //1、关系注解:多对一
    @ManyToOne(targetEntity=Customer.class)
    //2、外键注解
    @JoinColumn(
            //外键名称
            name="lkm_cust_id",
            //外键值的来源: 来源于主表的主键
            referencedColumnName="cust_id"
    )
    private Customer customer;

    /**
     * 获取
     * @return lkmId
     */
    public Long getLkmId() {
        return lkmId;
    }

    /**
     * 设置
     * @param lkmId
     */
    public void setLkmId(Long lkmId) {
        this.lkmId = lkmId;
    }

    /**
     * 获取
     * @return lkmName
     */
    public String getLkmName() {
        return lkmName;
    }

    /**
     * 设置
     * @param lkmName
     */
    public void setLkmName(String lkmName) {
        this.lkmName = lkmName;
    }

    /**
     * 获取
     * @return lkmGender
     */
    public String getLkmGender() {
        return lkmGender;
    }

    /**
     * 设置
     * @param lkmGender
     */
    public void setLkmGender(String lkmGender) {
        this.lkmGender = lkmGender;
    }

    /**
     * 获取
     * @return lkmPhone
     */
    public String getLkmPhone() {
        return lkmPhone;
    }

    /**
     * 设置
     * @param lkmPhone
     */
    public void setLkmPhone(String lkmPhone) {
        this.lkmPhone = lkmPhone;
    }

    /**
     * 获取
     * @return lkmMobile
     */
    public String getLkmMobile() {
        return lkmMobile;
    }

    /**
     * 设置
     * @param lkmMobile
     */
    public void setLkmMobile(String lkmMobile) {
        this.lkmMobile = lkmMobile;
    }

    /**
     * 获取
     * @return lkmEmail
     */
    public String getLkmEmail() {
        return lkmEmail;
    }

    /**
     * 设置
     * @param lkmEmail
     */
    public void setLkmEmail(String lkmEmail) {
        this.lkmEmail = lkmEmail;
    }

    /**
     * 获取
     * @return lkmPosition
     */
    public String getLkmPosition() {
        return lkmPosition;
    }

    /**
     * 设置
     * @param lkmPosition
     */
    public void setLkmPosition(String lkmPosition) {
        this.lkmPosition = lkmPosition;
    }

    /**
     * 获取
     * @return lkmMemo
     */
    public String getLkmMemo() {
        return lkmMemo;
    }

    /**
     * 设置
     * @param lkmMemo
     */
    public void setLkmMemo(String lkmMemo) {
        this.lkmMemo = lkmMemo;
    }

    /**
     * 获取
     * @return customer
     */
    public Customer getCustomer() {
        return customer;
    }

    /**
     * 设置
     * @param customer
     */
    public void setCustomer(Customer customer) {
        this.customer = customer;
    }

}


3.测试

package com.xjggb.test;

import com.xjggb.mapper.CustomerMapper;
import com.xjggb.mapper.LinkmanMapper;
import com.xjggb.pojo.Customer;
import com.xjggb.pojo.Linkman;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;

//指定运行期
@RunWith(SpringJUnit4ClassRunner.class)
//加载配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class JpaTest6 {

    @Autowired
    private CustomerMapper customerMapper;

    @Autowired
    private LinkmanMapper linkmanMapper;


    /*
    * 双向绑定
    * */


    /**
     * 双向保存:
     * 		一对多的保存原则: 先保存主表的数据,再保存从表的数据
     *
     * 你知道我,我也知道你
     */
    @Test
    //为了解决异常:先加入事务
    @Transactional
    //由于在测试阶段,spring会回滚
    @Rollback(false)
    public void test() {
        Customer c = new Customer();
        c.setCustName("赤木钢化玻璃公司");

        Linkman l = new Linkman();
        l.setLkmName("晴子");
        l.setLkmPosition("CEO");

        //要想外键有值,必须配置关系:双向
     c.getLinkmans().add(l);
        l.setCustomer(c);

        //保存:先保存主表的数据,再保存从表的数据
        customerMapper.save(c);
        linkmanMapper.save(l);
    }


}


3.一对多删除

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

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

  • 操作谁就在谁哪里配置【我们现在删除的是客户,所以在客户这边配置,在关系注解中配置级联】
  • 级联慎用

1.实体类配置

package com.xjggb.pojo;

import lombok.Data;

import javax.persistence.*;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;



/**
 * 实体类
 * @author Johnny.Chen
 *
 */

@Entity
@Table(name="cst_customer")
public class Customer implements Serializable{

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

    @Column(name="cust_name")
    private String custName;

    @Column(name="cust_source")
    private String custSource;

    @Column(name="cust_level")
    private String custLevel;

    @Column(name="cust_industry")
    private String custIndustry;

    @Column(name="cust_phone")
    private String custPhone;

    @Column(name="cust_address")
    private String custAddress;


    //当前是一方
    /**
     * new :
     * 		1、如果new出当前方法,集合也会实例化
     * 		2、我们为了解决有可能出现的空指针异常,new,我们可以在new的时候指定开辟的大小
     *
     * 不new:
     * 		容器用来装联系人实体
     * 		customer.getLinkman().add(new Linkman())
     * 		有可能出现空指针异常
     *
     */
    //配置一对多的关系注解
    //客户维护外键
	/*//1、关系注解:一对多
	@OneToMany(targetEntity=Linkman.class)
	//2、外键注解
	@JoinColumn(
			//外键名称
			name="lkm_cust_id",
			//外键值的来源: 来源于主表的主键
			referencedColumnName="cust_id"
	)*/

    //客户不维护外键
    @OneToMany(
            mappedBy="customer",//mappedBy: 配置的对方有@JoinColumn注解的属性的名称
            cascade = CascadeType.ALL//级联保存更新删除
    )
    private Set<Linkman> linkmans = new HashSet<>(0);

    /**
     * 获取
     * @return custId
     */
    public Long getCustId() {
        return custId;
    }

    /**
     * 设置
     * @param custId
     */
    public void setCustId(Long custId) {
        this.custId = custId;
    }

    /**
     * 获取
     * @return custName
     */
    public String getCustName() {
        return custName;
    }

    /**
     * 设置
     * @param custName
     */
    public void setCustName(String custName) {
        this.custName = custName;
    }

    /**
     * 获取
     * @return custSource
     */
    public String getCustSource() {
        return custSource;
    }

    /**
     * 设置
     * @param custSource
     */
    public void setCustSource(String custSource) {
        this.custSource = custSource;
    }

    /**
     * 获取
     * @return custLevel
     */
    public String getCustLevel() {
        return custLevel;
    }

    /**
     * 设置
     * @param custLevel
     */
    public void setCustLevel(String custLevel) {
        this.custLevel = custLevel;
    }

    /**
     * 获取
     * @return custIndustry
     */
    public String getCustIndustry() {
        return custIndustry;
    }

    /**
     * 设置
     * @param custIndustry
     */
    public void setCustIndustry(String custIndustry) {
        this.custIndustry = custIndustry;
    }

    /**
     * 获取
     * @return custPhone
     */
    public String getCustPhone() {
        return custPhone;
    }

    /**
     * 设置
     * @param custPhone
     */
    public void setCustPhone(String custPhone) {
        this.custPhone = custPhone;
    }

    /**
     * 获取
     * @return custAddress
     */
    public String getCustAddress() {
        return custAddress;
    }

    /**
     * 设置
     * @param custAddress
     */
    public void setCustAddress(String custAddress) {
        this.custAddress = custAddress;
    }

    /**
     * 获取
     * @return linkmans
     */
    public Set<Linkman> getLinkmans() {
        return linkmans;
    }

    /**
     * 设置
     * @param linkmans
     */
    public void setLinkmans(Set<Linkman> linkmans) {
        this.linkmans = linkmans;
    }

    public String toString() {
        return "Customer{custId = " + custId + ", custName = " + custName + ", custSource = " + custSource + ", custLevel = " + custLevel + ", custIndustry = " + custIndustry + ", custPhone = " + custPhone + ", custAddress = " + custAddress + ", linkmans = " + linkmans + "}";
    }
}


2.测试

package com.xjggb.test;

import com.xjggb.mapper.CustomerMapper;
import com.xjggb.pojo.Customer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;

//指定运行期
@RunWith(SpringJUnit4ClassRunner.class)
//加载配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class JpaTest7 {

    @Autowired
    private CustomerMapper customerMapper;


    @Test
    @Transactional
    @Rollback(false)
    public void show(){
//a、在默认情况【双方维护外键】下,它会把外键字段置为null,然后删除主表数据。如果在数据库的表结构上,外键字段有非空约束,默认情况就会报错了。
        //b、如果配置了放弃维护关联关系的权利,则不能删除(与外键字段是否允许为null,没有关系)因为在删除时,它根本不会去更新从表的外键字段了。
        //c、如果还想删除,使用级联删除引用
        /**
         * 级联操作:
         * 		我们操作一个对象的时候,让代码在后台偷偷的去操作关联的另外一个对象
         * 级联删除:
         * 		我们删除客户的时候,让代码先把它关联的联系人属性删除,然后再删除主表数据
         *
         * 配置级联:【慎用】【株连九族】
         * 		1、我们操作谁就在谁哪里配置级联,我们现在删除的是客户,所以在客户哪里配置
         * 		2、在关系注解中配置级联:
         * 			@OneToMany(cascade=CascadeType.ALL)       级联保存更新删除
         * 			@OneToMany(cascade=CascadeType.PERSIST)   级联保存
         * 			@OneToMany(cascade=CascadeType.MERGE)	     级联更新
         * 			@OneToMany(cascade=CascadeType.REMOVE)    级联删除
         *
         */
        customerMapper.delete(1L);


    }

}


小结

1、关系注解:

@OneToMany(mappedBy=“对方有@JoinColumn注解的属性名称”,targeEntity="",cascade="")

@ManyToOne(targeEntity="",cascade="") //不能配置mappedBy,自己不能放弃自己的外键维护

2、维护外键注解:谁有它谁就能维护外键

@JoinColumn(name=“外键名称”,referenceColumnName=“主表的主键名称”)

3、操作:save和delete

关键点找外键

5.多对多映射

1.多对多保存

1.第一步

用户:一个用户可以多个角色

角色:可以拥有多个用户

多对多关系

2.第二步

找出中间表

用户表

角色表

用户角色的中间表,两列,来源用户表的与角色表主键,联合主键

3.第三步

一个用户包含多个角色 :

一个角色包含多个用户:

用户实体类

package com.xjggb.pojo;


import javax.persistence.*;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

/**
 *
 * @author Johnny.Chen
 *
 */
@Entity
//@Table(name="User") //如果表名和类名一样,可以省略
public class User implements Serializable {

    @Id
    //@Column(name="userId") //如果字段名和属性名一样,可以省略
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    private Integer userId;

    private String name;
    private String age;
    private String pwd;

    //一个用户包含多个角色
//    关系注解配置多对多
    @ManyToMany(targetEntity = Role.class)

//    维护中间表注解
    @JoinTable(
            name = "T_user_Role_Ref" , //中间表名称
//            当前中间表的外键
            joinColumns = @JoinColumn(name = "u_id",referencedColumnName = "userId"),
//            对方在中间表的外键
            inverseJoinColumns = @JoinColumn(name = "r_id",referencedColumnName = "roleId")

    )

    private Set<Role> roles = new HashSet<>(0);



    public Set<Role> getRoles() {
        return roles;
    }
    public void setRoles(Set<Role> roles) {
        this.roles = roles;
    }
    public Integer getUserId() {
        return userId;
    }
    public void setUserId(Integer userId) {
        this.userId = userId;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAge() {
        return age;
    }
    public void setAge(String age) {
        this.age = age;
    }
    public String getPwd() {
        return pwd;
    }
    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
    @Override
    public String toString() {
        return "User [userId=" + userId + ", name=" + name + ", age=" + age + ", pwd=" + pwd + "]";
    }

}


角色类

package com.xjggb.pojo;


import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;

@Entity
public class Role {

    @Id
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    private Integer roleId;
    private String roleName;
//
//    //一个角色包含多个用户
//    @ManyToMany(targetEntity =User.class )
    维护中间表注解
//    @JoinTable(
//            name = "T_user_Role_Ref" , //中间表名称
            当前中间表的外键
//            joinColumns = @JoinColumn(name = "r_id",referencedColumnName = "roleId"),
            对方在中间表的外键
//            inverseJoinColumns = @JoinColumn(name = "u_id",referencedColumnName = "userId")



    @ManyToMany(
            mappedBy = "roles",
            cascade = CascadeType.ALL //级联操作

    )
    private Set<User> users = new HashSet<>(0);



    public Set<User> getUsers() {
        return users;
    }
    public void setUsers(Set<User> users) {
        this.users = users;
    }
    public Integer getRoleId() {
        return roleId;
    }
    public void setRoleId(Integer roleId) {
        this.roleId = roleId;
    }
    public String getRoleName() {
        return roleName;
    }
    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }
    @Override
    public String toString() {
        return "Role [roleId=" + roleId + ", roleName=" + roleName + "]";
    }



}



4.第四步

测试

package com.xjggb.test;

import com.xjggb.mapper.CustomerMapper;
import com.xjggb.mapper.RoleMapper;
import com.xjggb.mapper.UserMapper;
import com.xjggb.pojo.Customer;
import com.xjggb.pojo.Role;
import com.xjggb.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;

//指定运行期
@RunWith(SpringJUnit4ClassRunner.class)
//加载配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class JpaTest8 {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RoleMapper roleMapper;



    /*
     *
     * */

    @Test
    @Transactional
    @Rollback(false)
    public void show(){

        User user = new User();
        user.setName("三井寿");


        Role role = new Role();
        role.setRoleName("牙医");

//        谁放弃都可以只能一张表维护中间表  不然会报错 Duplicate entry '1-1' for key 'PRIMARY'
        role.getUsers().add(user);

        user.getRoles().add(role);


        userMapper.save(user);
        roleMapper.save(role);


    }

}


2.多对多的删除

实体类

package com.xjggb.pojo;


import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;

@Entity
public class Role {

    @Id
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    private Integer roleId;
    private String roleName;
//
//    //一个角色包含多个用户
//    @ManyToMany(targetEntity =User.class )
    维护中间表注解
//    @JoinTable(
//            name = "T_user_Role_Ref" , //中间表名称
            当前中间表的外键
//            joinColumns = @JoinColumn(name = "r_id",referencedColumnName = "roleId"),
            对方在中间表的外键
//            inverseJoinColumns = @JoinColumn(name = "u_id",referencedColumnName = "userId")



    @ManyToMany(
            mappedBy = "roles",
            cascade = CascadeType.ALL //级联操作

    )
    private Set<User> users = new HashSet<>(0);



    public Set<User> getUsers() {
        return users;
    }
    public void setUsers(Set<User> users) {
        this.users = users;
    }
    public Integer getRoleId() {
        return roleId;
    }
    public void setRoleId(Integer roleId) {
        this.roleId = roleId;
    }
    public String getRoleName() {
        return roleName;
    }
    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }
    @Override
    public String toString() {
        return "Role [roleId=" + roleId + ", roleName=" + roleName + "]";
    }



}



测试

package com.xjggb.test;

import com.xjggb.mapper.CustomerMapper;
import com.xjggb.mapper.RoleMapper;
import com.xjggb.mapper.UserMapper;
import com.xjggb.pojo.Customer;
import com.xjggb.pojo.Role;
import com.xjggb.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;

//指定运行期
@RunWith(SpringJUnit4ClassRunner.class)
//加载配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class JpaTest8 {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RoleMapper roleMapper;



    /**
     * 删除
     */
    @Test
    //为了解决异常:先加入事务
    @Transactional
    //由于在测试阶段,spring会回滚
    @Rollback(false)
    public void test3() {
        //roleDao.delete(1); //如果已经配置了放弃中间表的维护,删除不了

        /**
         * 级联:
         * 		1)单向级联:
         * 		2)双向级联:两边的关系注解都配置级联【禁用】【寸草不生】
         */
        roleMapper.delete(1); //如果已经配置了放弃中间表的维护,默认删除不了,如果配置了级联可以删除



        //工作中:先删除用户,再删除角色
		/*userDao.delete(1);
		roleDao.delete(1);*/
    }



    /*
     *
     * */

    @Test
    @Transactional
    @Rollback(false)
    public void show(){

        User user = new User();
        user.setName("三井寿");


        Role role = new Role();
        role.setRoleName("牙医");

//        谁放弃都可以只能一张表维护中间表  不然会报错 Duplicate entry '1-1' for key 'PRIMARY'
        role.getUsers().add(user);

        user.getRoles().add(role);


        userMapper.save(user);
        roleMapper.save(role);


    }

}


6.对象导航查询

对象导航查询: 通过对象打点的时候,调用管理属性查询

1)通过客户导航查询联系人:customer.getLinkmen() :

  • 默认是 延迟加载
  • 可以改为立即加载: 在关系注解中配置 fetch属性

2)联系人导航查询客户:linkman.getCustomer()

  • 默认是立即加载
  • 可以改为延迟加载:在关系注解中配置 fetch属性
 //客户不维护外键
    @OneToMany(
            mappedBy="customer",//mappedBy: 配置的对方有@JoinColumn注解的属性的名称
            cascade = CascadeType.ALL//级联保存更新删除
            ,fetch = FetchType.EAGER  //配置立即加载  LAZY 懒加载  EAGER 立即加载
    )

代码如下

    @Test
    //为了解决异常:先加入事务
    @Transactional
    //由于在测试阶段,spring会回滚
    @Rollback(false)
    public void show(){


//通过联系人导航查询客户  默认延迟加载
//通过客户导航查询联系人:懒加载
        Customer one = customerMapper.findOne(1L);//先查客户
        System.out.println("one = " + one);
        Set<Linkman> linkmans = one.getLinkmans();//再查联系人

        //迭代
        for (Linkman linkman : linkmans) {
            System.out.println(linkman);
        }


    }







总结

  1. 对jpa的入门 CRUD

  2. jpa工具的抽取

  3. 接口方法的定义查询

  4. Specification 查询的使用

  5. 一对多查询的映射

  6. 多对多的映射

上一篇:Spring Data JPA使用QueryDsl自定义返回对象(配合小辣椒使用)


下一篇:Java学习路线-这可能是你见过的最全的Java学习路线了