黑马程序员spring data jpa 2019年第一版本

第一步首先创建一个maven工程,导入对于的pom依赖

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.cib.com</groupId>
  <artifactId>heimaspringdatajpa</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
  <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.6</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>

        <!-- spring对orm框架的支持包-->
        <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-c3p0</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 -->

     
     

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

        <!-- spring data jpa 的坐标-->
        <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 -->
    </dependencies>
</project>

1、接下来创建jpa的核心配置文件

jpa的核心配置文件必须放在类路径的meta-info文件夹下面,命名也必须满足对于的规则

PA规范要求在类路径的META-INF目录下放置persistence.xml, 文件的名称是固定的,配置模板如下:

<!--必须要有name属性,不能为空 -->
<persistence-unit name="myJap" transaction-type="RESOURCE_LOCAL">

这里

 如果是分布式事务管理,这里就要配置为JTA,这里只操作一个数据库,这里不存在分布式事务,这里设置为RESOURCE_LOCAl

 

 

 persistence.xml的内容如下所示

<?xml version="1.0" encoding="UTF-8"?>
 <persistence version="2.0" 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">
    
    <!--必须要有name属性,不能为空 -->
     <persistence-unit name="myJap" transaction-type="RESOURCE_LOCAL">
          <!--可选 -->
          <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
          
          <!--厂商的特定属性 -->
        
          
          <properties>
          <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/jpa?useUnicode=true&amp;characterEncoding=UTF-8" />
            <property name="javax.persistence.jdbc.user" value="root" />
            <property name="javax.persistence.jdbc.password" value="123456" />
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.hbm2ddl.auto" value="update" />
        </properties>
     </persistence-unit>
             
 </persistence>

接下来,我们要编写实体类,创建对于的数据库表

创建客户的数据库表

drop table if exists cst_customer;
/*创建客户表*/
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=UTF8MB4;

————————————————
版权声明:本文为CSDN博主「底层_码农」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_40794973/article/details/98895832

注:表可以不用创建

3)创建、编写实体类和数据库表的映射配置[重点]

注解描述

@Entity:声明实体类】
@Table : 配置实体类和表的映射关系 , name : 配置数据库表的名称
/**
     * @Id:声明主键的配置
     * @GeneratedValue:配置主键的生成策略
     *      strategy
     *          GenerationType.IDENTITY :自增,mysql
     *                 * 底层数据库必须支持自动增长(底层数据库支持的自动增长方式,对id自增)
     *          GenerationType.SEQUENCE : 序列,oracle
     *                  * 底层数据库必须支持序列
     *          GenerationType.TABLE : jpa提供的一种机制,通过一张数据库表的形式帮助我们完成主键自增
     *          GenerationType.AUTO : 由程序自动的帮助我们选择主键生成策略
     * @Column:配置属性和字段的映射关系
     *      name:数据库表中字段的名称
     */
    /**
     * 客户编号(主键)
     */

GenerationType.IDENTITY :自增,mysql
* * 底层数据库必须支持自动增长(底层数据库支持的自动增长方式,对id自增) 必须和mysql中的  AUTO_INCREMENT一一对象,cust_id bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)',

@Column:配置属性和字段的映射关系
* name:数据库表中字段的名称

package com.itcast.domain;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * 客户的实体类
 *      配置映射关系
 *
 *   1.实体类和表的映射关系
 *      @Entity:声明实体类
 *      @Table : 配置实体类和表的映射关系
 *          name : 配置数据库表的名称
 *   2.实体类中属性和表中字段的映射关系
 */
@Entity
@Table(name = "cst_customer")
public class Customer implements Serializable {
 
    /**
     * @Id:声明主键的配置
     * @GeneratedValue:配置主键的生成策略
     *      strategy
     *          GenerationType.IDENTITY :自增,mysql
     *                 * 底层数据库必须支持自动增长(底层数据库支持的自动增长方式,对id自增)
     *          GenerationType.SEQUENCE : 序列,oracle
     *                  * 底层数据库必须支持序列
     *          GenerationType.TABLE : jpa提供的一种机制,通过一张数据库表的形式帮助我们完成主键自增
     *          GenerationType.AUTO : 由程序自动的帮助我们选择主键生成策略
     * @Column:配置属性和字段的映射关系
     *      name:数据库表中字段的名称
     */
    /**
     * 客户编号(主键)
     */
    @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;
    public Long getCustId() {
        return custId;
    }
    public void setCustId(Long custId) {
        this.custId = custId;
    }
    public String getCustName() {
        return custName;
    }
    public void setCustName(String custName) {
        this.custName = custName;
    }
    public String getCustSource() {
        return custSource;
    }
    public void setCustSource(String custSource) {
        this.custSource = custSource;
    }
    public String getCustIndustry() {
        return custIndustry;
    }
    public void setCustIndustry(String custIndustry) {
        this.custIndustry = custIndustry;
    }
    public String getCustLevel() {
        return custLevel;
    }
    public void setCustLevel(String custLevel) {
        this.custLevel = custLevel;
    }
    public String getCustAddress() {
        return custAddress;
    }
    public void setCustAddress(String custAddress) {
        this.custAddress = custAddress;
    }
    public String getCustPhone() {
        return custPhone;
    }
    public void setCustPhone(String custPhone) {
        this.custPhone = custPhone;
    }
    
    
}

接下来我们就可以编写一个测试类,测试对于的jpa的操作


/**
* 测试jpa的保存
* 案例:保存一个客户到数据库中
* Jpa的操作步骤
* 1.加载配置文件创建工厂(实体管理器工厂)对象
* 2.通过实体管理器工厂获取实体管理器
* 3.获取事务对象,开启事务
* 4.完成增删改查操作
* 5.提交事务(回滚事务)
* 6.释放资源
*/

package com.itcast.cn;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

import org.junit.Test;

import com.itcast.domain.Customer;

public class TestJpa {

    
    /**
     * 测试jpa的保存
     *      案例:保存一个客户到数据库中
     *  Jpa的操作步骤
     *     1.加载配置文件创建工厂(实体管理器工厂)对象
     *     2.通过实体管理器工厂获取实体管理器
     *     3.获取事务对象,开启事务
     *     4.完成增删改查操作
     *     5.提交事务(回滚事务)
     *     6.释放资源
     */
    @Test
    public void testSave() {
        //1.加载配置文件创建工厂(实体管理器工厂)对象
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJap");
        //2.通过实体管理器工厂获取实体管理器
        EntityManager em = factory.createEntityManager();
     
        //3.获取事务对象,开启事务
        EntityTransaction tx = em.getTransaction(); //获取事务对象
        tx.begin();//开启事务
        try{
            //4.完成增删改查操作:保存一个客户到数据库中
            Customer customer = new Customer();
            customer.setCustName("蔡徐坤");
            customer.setCustIndustry("明星");
            customer.setCustSource("bibi");
            //保存
            em.persist(customer); //保存操作
            //5.提交事务
            tx.commit();
        }catch (Exception e){
            tx.rollback();//回滚事务
            e.printStackTrace();
        }finally {
            //6.释放资源
            em.close();
            //关闭工厂
            factory.close();
        }
     
    }
}

运行的sql语句如下所示

log4j:WARN No appenders could be found for logger (org.jboss.logging).
log4j:WARN Please initialize the log4j system properly.
Hibernate: insert into cst_customer (cust_address, cust_industry, cust_level, cust_name, cust_phone, cust_source) values (?, ?, ?, ?, ?, ?)

GenerationType.TABLE : jpa提供的一种机制,通过一张数据库表的形式帮助我们完成主键自增,jpa会另外生成一张表帮助我们进行主键的管理

 GenerationType.AUTO : 由程序自动的帮助我们选择主键生成策略

 

 多个线程在内存中共享一份Factory对象,减少Factory对象创建消耗资源

 采用静态代码块的方法,减少Factory资源创建消耗性能的问题

1. 抽取JPAUtil工具类

package com.itcast.utils;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

/**
 * 解决实体管理器工厂的浪费资源和耗时问题
 * 通过静态代码块的形式,当程序第一次访问此工具类时,创建一个公共的实体管理器工厂对象
 *
 * 第一次访问getEntityManager方法:经过静态代码块创建一个factory对象,再调用方法创建一个EntityManager对象
 * 第二次方法getEntityManager方法:直接通过一个已经创建好的factory对象,创建EntityManager对象
 */
public class JpaUtils {
    private static EntityManagerFactory factory;
 
    static {
        //1.加载配置文件,创建entityManagerFactory
        factory = Persistence.createEntityManagerFactory("myJpa");
    }
    /**
     * 获取EntityManager对象
     */
    public static EntityManager getEntityManager() {
        return factory.createEntityManager();
    }
}

我们在编写一个测试类进行测试

解决创建 EntityManagerFactory  浪费资源问题 

3. 测试查询
查询有两个方法,注意区别

package com.itcast.cn;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

import org.junit.Test;

import com.itcast.domain.Customer;
import com.itcast.utils.JpaUtils;

public class TestJpa {

    
    /**
     * 测试jpa的保存
     *      案例:保存一个客户到数据库中
     *  Jpa的操作步骤
     *     1.加载配置文件创建工厂(实体管理器工厂)对象
     *     2.通过实体管理器工厂获取实体管理器
     *     3.获取事务对象,开启事务
     *     4.完成增删改查操作
     *     5.提交事务(回滚事务)
     *     6.释放资源
     */
    @Test
    public void testSave() {
        //1.加载配置文件创建工厂(实体管理器工厂)对象
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJap");
        //2.通过实体管理器工厂获取实体管理器
        EntityManager em = factory.createEntityManager();
     
        //3.获取事务对象,开启事务
        EntityTransaction tx = em.getTransaction(); //获取事务对象
        tx.begin();//开启事务
        try{
            //4.完成增删改查操作:保存一个客户到数据库中
            Customer customer = new Customer();
            customer.setCustName("蔡徐坤");
            customer.setCustIndustry("明星");
            customer.setCustSource("bibi");
            //保存
            em.persist(customer); //保存操作
            //5.提交事务
            tx.commit();
        }catch (Exception e){
            tx.rollback();//回滚事务
            e.printStackTrace();
        }finally {
            //6.释放资源
            em.close();
            //关闭工厂
            factory.close();
        }
     
    }
    
    @Test
    public void testtestSave02(){
        //1.获取工厂(实体管理器工厂)对象
        EntityManager em = JpaUtils.getEntityManager();
        //3.获取事务对象,开启事务
        EntityTransaction tx = em.getTransaction(); //获取事务对象
        tx.begin();//开启事务
        //4.完成增删改查操作:保存一个客户到数据库中
        Customer customer = new Customer();
        customer.setCustName("蔡徐坤");
        customer.setCustIndustry("明星");
        customer.setCustSource("bibi");
        //保存
        em.persist(customer); //保存操作
        //5.提交事务
        tx.commit();
        //6.释放资源
        em.close();
    }
    
    /**
     * 根据id查询客户
     *  使用find方法查询:
     *      1.查询的对象就是当前客户对象本身
     *      2.在调用find方法的时候,就会发送sql语句查询数据库
     *
     *  立即加载
     */
    @Test
    public  void testFind() {
        //1.通过工具类获取entityManager
        EntityManager entityManager = JpaUtils.getEntityManager();
        //3.增删改查 -- 根据id查询客户
        /**
         * find : 根据id查询数据
         *      class:查询数据的结果需要包装的实体类类型的字节码
         *      id:查询的主键的取值
         * 没有返回 null
         */
        Customer customer = entityManager.find(Customer.class, 1L);//打断点
        //不管打不打印(使用),执行到上一条语句时,都会发送SQL语句
        //System.out.print(customer);
        //class com.bug.domain.Customer
        System.out.println(customer.toString());
        //5.释放资源
        entityManager.close();

    }
    
    /**
     * 根据id查询客户
     *      getReference方法
     *          1.获取的对象是一个动态代理对象
     *          2.调用getReference方法不会立即发送sql语句查询数据库
     *              * 当调用查询结果对象的时候,才会发送查询的sql语句:什么时候用,什么时候发送sql语句查询数据库
     *
     * 延迟加载(懒加载)
     *      * 得到的是一个动态代理对象
     *      * 什么时候用,什么使用才会查询
     */
    @Test
    public  void testReference() {
        //1.通过工具类获取entityManager
        EntityManager entityManager = JpaUtils.getEntityManager();
        //3.增删改查 -- 根据id查询客户
        /**
         * getReference : 根据id查询数据
         *      class:查询数据的结果需要包装的实体类类型的字节码
         *      id:查询的主键的取值
         */
        Customer customer = entityManager.getReference(Customer.class, 1L);//打断点
        //这里不打印(不使用)就不会发送SQL语句
        //System.out.print(customer);
        //class com.bug.domain.Customer_$$_jvst88e_0 代理对象
        System.out.println("

");
        System.out.println(customer.toString());
        //5.释放资源
        entityManager.close();
    }


}

//3.增删改查 -- 根据id查询客户
/**
* getReference : 根据id查询数据
* class:查询数据的结果需要包装的实体类类型的字节码
* id:查询的主键的取值
*/

getReference 是懒加载,在find查询语句的时候不会发起sql语句查询,在实际使用使用System.out.print(customer)的时候才发起sql语句进行查询,返回的查询结果是一个代理对象

4. 测试删除

@Test
    public  void testRemove() {
        //1.通过工具类获取entityManager
        EntityManager entityManager = JpaUtils.getEntityManager();
        //3.增删改查 -- 删除客户
        //3.获取事务对象,开启事务
        EntityTransaction tx = entityManager.getTransaction(); //获取事务对象
        tx.begin();//开启事务
        //i 根据id查询客户
        Customer customer = entityManager.find(Customer.class, 1L);
        System.out.println(customer);
        if(customer != null){
            //ii 调用remove方法完成删除操作
            entityManager.remove(customer);
        }
        //5.提交事务
        tx.commit();
        //5.释放资源
        entityManager.close();
    }

7.JPA中的复杂查询
JPQL全称Java Persistence Query Language,Java持久化查询语言(JPQL),它是一种可移植的查询语言,旨在以面向对象表达式语言的表达式,将SQL语法和简单查询语义绑定在一起·使用这种语言编写的查询是可移植的,可以被编译成所有主流数据库服务器上的SQL。

其特征与原生SQL语句类似,并且完全面向对象,通过类名和属性访问,而不是表名和表的属性。

 jpql语句不能写select *,但是能够写select 加上对象的属性值

查询数据库 表中存在多少条记录

//统计查询
    @Test
    public void findCount() {
        EntityManager em = null;
        EntityTransaction tx = null;
        try {
            //获取实体管理对象
            em = JPAUtil.getEntityManager();
            //获取事务对象
            tx = em.getTransaction();
            tx.begin();
            // 查询全部客户
            // 1.创建query对象
            String jpql = "select count(custId) from Customer";
            Query query = em.createQuery(jpql);
            // 2.查询并得到返回结果
            Object count = query.getSingleResult(); // 得到集合返回类型
            System.out.println(count);
            tx.commit();
        } catch (Exception e) {
            // 回滚事务
            tx.rollback();
            e.printStackTrace();
        } finally {
            // 释放资源
            em.close();
        }
    }
 
————————————————
版权声明:本文为CSDN博主「I Java」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zlx_508/article/details/97005499

记录总数只有一条记录,使用getSingleResult,返回一条记录

分页查询

 0表示查询第一页,2表示第一页显示2条记录

//分页查询客户
    @Test
    public void findPaged () {
        EntityManager em = null;
        EntityTransaction tx = null;
        try {
            //获取实体管理对象
            em = JPAUtil.getEntityManager();
            //获取事务对象
            tx = em.getTransaction();
            tx.begin();
 
            //创建query对象
            String jpql = "from Customer";
            Query query = em.createQuery(jpql);
            //起始索引
            query.setFirstResult(0);
            //每页显示条数
            query.setMaxResults(2);
            //查询并得到返回结果
            List list = query.getResultList(); //得到集合返回类型
            for (Object object : list) {
                System.out.println(object);
            }
            tx.commit();
        } catch (Exception e) {
            // 回滚事务
            tx.rollback();
            e.printStackTrace();
        } finally {
            // 释放资源
            em.close();
        }
    }
————————————————
版权声明:本文为CSDN博主「I Java」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zlx_508/article/details/97005499

接下来我们讲解条件查询

//条件查询
    @Test
    public void findCondition () {
        EntityManager em = null;
        EntityTransaction tx = null;
        try {
            //获取实体管理对象
            em = JPAUtil.getEntityManager();
            //获取事务对象
            tx = em.getTransaction();
            tx.begin();
            //创建query对象
            String jpql = "from Customer where custName like ? ";
            Query query = em.createQuery(jpql);
            //对占位符赋值,从1开始
            query.setParameter(1, "传智播客%");
            //查询并得到返回结果
            Object object = query.getSingleResult(); //得到唯一的结果集对象
            System.out.println(object);
            tx.commit();
        } catch (Exception e) {
            // 回滚事务
            tx.rollback();
            e.printStackTrace();
        } finally {
            // 释放资源
            em.close();
        }
    }
————————————————
版权声明:本文为CSDN博主「I Java」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zlx_508/article/details/97005499

 接下来重点讲解spring -data-jpa

这里配置文件有点问题,不清楚的看佟刚spring data的视频教程

 

 pom.xml的依赖如下

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.cib.com</groupId>
  <artifactId>heimaspringdatajpa</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
  <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.6</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>

        <!-- spring对orm框架的支持包-->
        <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-c3p0</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 -->

     
     

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

        <!-- spring data jpa 的坐标-->
        <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 -->
    </dependencies>
</project>

db.properties的配置如下

jdbc.user=root
jdbc.password=123456
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.jdbcUrl=jdbc:mysql:///jpa
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:jpa="http://www.springframework.org/schema/data/jpa"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <!-- 配置自动扫描的包 -->
    <context:component-scan base-package="com.atguigu.springdata"></context:component-scan>

    <!-- 1. 配置数据源 -->
    <context:property-placeholder location="classpath:db.properties"/>

    <bean id="dataSource"
        class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="${jdbc.user}"></property>
        <property name="password" value="${jdbc.password}"></property>    
        <property name="driverClass" value="${jdbc.driverClass}"></property>
        <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
        
        <!-- 配置其他属性 -->
    </bean>

    <!-- 2. 配置 JPA 的 EntityManagerFactory -->
    <bean id="entityManagerFactory" 
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"></bean>
        </property>
        <property name="packagesToScan" value="com.atguigu.springdata"></property>
        <property name="jpaProperties">
            <props>
                <!-- 二级缓存相关 -->
                <!--  
                <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
                <prop key="net.sf.ehcache.configurationResourceName">ehcache-hibernate.xml</prop>
                -->
                <!-- 生成的数据表的列的映射策略 -->
                <prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
                <!-- hibernate 基本属性 -->
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.format_sql">true</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
            </props>
        </property>
    </bean>

    <!-- 3. 配置事务管理器 -->
    <bean id="transactionManager"
        class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"></property>    
    </bean>

    <!-- 4. 配置支持注解的事务 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>

    <!-- 5. 配置 SpringData -->
    <!-- 加入  jpa 的命名空间 -->
    <!-- base-package: 扫描 Repository Bean 所在的 package -->
    <jpa:repositories base-package="com.atguigu.springdata"
        entity-manager-factory-ref="entityManagerFactory"></jpa:repositories>

</beans>

这里有几个配置很关键

<jpa:repositories base-package="com.atguigu.springdata" 指定扫描@Reporisty注解的包

<property name="packagesToScan" value="com.atguigu.springdata"></property>指定@Entiry注解的包

<context:component-scan base-package="com.atguigu.springdata"></context:component-scan>指定spring @service @compent所在的包路径

接下来我们创建包com.atguigu.springdata,所有在的操作都在这个包下面

接下来我们创建实体类

package com.atguigu.springdata;
import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.GenerationType;

import javax.persistence.Id;

import javax.persistence.Table;

@Entity // 声明此类是个实体类 需要导入javax.persistence.Entity;

@Table(name = "cst_customer") //需要将该类对应到数据库中的哪一个表中,name中填表的名称

public class Customer {



@Id //声明主键 

@GeneratedValue(strategy = GenerationType.IDENTITY) //声明主键的生成策略为自动递增

//mysql使用自增模式,orcle 使用序列模式

@Column(name = "cust_id") //设置该属性和数据库中的哪一个字段对应

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 cusIndustry;

 

@Column(name = "cust_phone")

private String custPhone;

 

@Column(name = "cust_address")

private String custAddress;



public Long getCustId() {

return custId;

}



public void setCustId(Long custId) {

this.custId = custId;

}



public String getCustName() {

return custName;

}



public void setCustName(String custName) {

this.custName = custName;

}



public String getCustSource() {

return custSource;

}



public void setCustSource(String custSource) {

this.custSource = custSource;

}



public String getCustLevel() {

return custLevel;

}



public void setCustLevel(String custLevel) {

this.custLevel = custLevel;

}



public String getCusIndustry() {

return cusIndustry;

}



public void setCusIndustry(String cusIndustry) {

this.cusIndustry = cusIndustry;

}



public String getCustPhone() {

return custPhone;

}



public void setCustPhone(String custPhone) {

this.custPhone = custPhone;

}



public String getCustAddress() {

return custAddress;

}



public void setCustAddress(String custAddress) {

this.custAddress = custAddress;

}



@Override

public String toString() {

return "Customer [custId=" + custId + ", custName=" + custName + ", custSource=" + custSource

+ ", custLevel=" + custLevel + ", cusIndustry=" + cusIndustry + ", custPhone=" + custPhone

+ ", custAddress=" + custAddress + "]";

}

 

}

实体类创建成功之后,接下来我们就可以编写jpa的接口进行增删改查的操作了,只需要编写jpa接口,不需要编写jpa的实现类

关键点:

1.编写dao层的接口就可以了,不需要dao接口的实现类

2、编写的dao接口的规范如下

 SpringDataJPA通过实现接口(代理的形式)进行简单的CRUD

https://blog.csdn.net/qq_42041712/article/details/94451572

JpaRepository<Customer,Long> 第一个参数是我们要操作的实体类类型,第二个参数是实体类的主键

JpaSpecificationExecutor<Customer> 参数是我们要操作的实体类的类型

package com.atguigu.springdata;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

/*
* 符合SpringDatajpa的dao层接口规范
*JpaRepository<操作的实体类类型,实体类中主键属性的类型>
    *封装了基本的CRUD操作
 JpaSpecificationExecutor<操作的实体类类型>
    *封装了复杂查询操作(分页)
* */
 
public interface CustomerDao  extends JpaRepository<Customer,Long>, JpaSpecificationExecutor<Customer> 
{
 
}

接下来编写好接口之后,就可以进行增加删除操作数据库了,注意CustomerDao没有使用注解,只要放在<jpa:repositories base-package="com.atguigu.springdata"对于的包下面就可以了

 我们可以编写一个测试类进行操作,首先保证数据库中存在数据

import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collector;
import java.util.stream.Collectors;

import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.sql.DataSource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.atguigu.springdata.CustomerDao;
import com.itcast.domain.Customer;
import com.itcast.utils.JpaUtils;



@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class SpringDataTest {

    @Autowired
    private CustomerDao dao;
    
    @Test
    public  void testFind() {
        
      com.atguigu.springdata.Customer customer = dao.findOne((long) 2);
      System.out.println(customer.toString());
    }
    
}

测试的结果如下

在eclipse中查看一个类及其父类中的所有方法和属性
只需要连续按两次Ctrl+O

JpaRepository默认实现了下面的方法

在eclipse中查看一个类的集成关系
只需要连续按两次Ctrl+T

 JpaRepository继承自PagingAndSortingRepository,PagingAndSortingRepository继承自CrudRepository,CrudRepository集成自Repository

import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collector;
import java.util.stream.Collectors;

import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.sql.DataSource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.atguigu.springdata.Customer;
import com.atguigu.springdata.CustomerDao;
import com.itcast.utils.JpaUtils;



@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class SpringDataTest {

    @Autowired
    private CustomerDao customerDao;
    
    @Test
    public  void testFind() {
        
      com.atguigu.springdata.Customer customer = customerDao.findOne((long) 2);
      System.out.println(customer.toString());
    }
    
    /**

     * 保存客户:调用save(obj)方法

     */

    @Test

    public void testSave() {

        Customer c = new Customer();

        c.setCustName("传智播客");

        customerDao.save(c);

    }

   

    /**

     * 修改客户:调用save(obj)方法

     *      对于save方法的解释:如果执行此方法是对象中存在id属性,即为更新操作会先根据id查询,再更新   

     *                      如果执行此方法中对象中不存在id属性,即为保存操作

     *         

     */

    @Test

    public void testUpdate() {

        //根据id查询id为1的客户

        Customer customer = customerDao.findOne(1l);

        //修改客户名称

        customer.setCustName("传智播客顺义校区");

        //更新

        customerDao.save(customer);

    }
    
}

/**

* 根据id删除:调用delete(id)方法

*/

@Test

public void testDelete() {

customerDao.delete(1l);

}

 

 

 

import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collector;
import java.util.stream.Collectors;

import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.sql.DataSource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.atguigu.springdata.Customer;
import com.atguigu.springdata.CustomerDao;
import com.itcast.utils.JpaUtils;



@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class SpringDataTest {

    @Autowired
    private CustomerDao customerDao;
    
    @Test
    public  void testFind() {
        
      com.atguigu.springdata.Customer customer = customerDao.findOne((long) 2);
      System.out.println(customer.toString());
    }
    
    /**

     * 保存客户:调用save(obj)方法

     */

    @Test

    public void testSave() {

        Customer c = new Customer();

        c.setCustName("传智播客");

        customerDao.save(c);

    }

   

    /**

     * 修改客户:调用save(obj)方法

     *      对于save方法的解释:如果执行此方法是对象中存在id属性,即为更新操作会先根据id查询,再更新   

     *                      如果执行此方法中对象中不存在id属性,即为保存操作

     *         

     */

    @Test

    public void testUpdate() {

        //根据id查询id为1的客户

        Customer customer = customerDao.findOne(1l);

        //修改客户名称

        customer.setCustName("传智播客顺义校区");

        //更新

        customerDao.save(customer);

    }
    
    @Test

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

    public void testExits() {
          boolean exists = customerDao.exists((long) 2);
          
          System.out.println(exists);
    }
    
    
    
}

 
    @Test

    @Transactional
    public void testGetOne() {
          Customer one = customerDao.getOne((long) 2);
          
          System.out.println(one);
    }
    

getOne是懒加载,findOne是直接加载,懒加载的实现需要依赖事务,所有使用getOne方法的时候,一定要引入事务管理的依赖,这里使用 @Transactiona,否则代码会报错

3.2 使用JPQL的方式查询
使用Spring Data JPA提供的查询方法已经可以解决大部分的应用场景,但是对于某些业务来说,我们还需要灵活的构造查询条件,这时就可以使用@Query注解,结合JPQL的语句方式完成查询

package com.atguigu.springdata;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

import antlr.collections.List;

/*
* 符合SpringDatajpa的dao层接口规范
*JpaRepository<操作的实体类类型,实体类中主键属性的类型>
    *封装了基本的CRUD操作
 JpaSpecificationExecutor<操作的实体类类型>
    *封装了复杂查询操作(分页)
* */
 

public interface CustomerDao  extends JpaRepository<Customer,Long>, JpaSpecificationExecutor<Customer> 
{
    


   

    //@Query 使用jpql的方式查询。?1代表参数的占位符,其中1对应方法中的参数索引

    @Query(value="from Customer where custName = ?1")

    public Customer findCustomer(String custName);
 
}

   //@Query 使用jpql的方式查询。?1代表参数的占位符,其中1对应方法中的参数索引

 2表示的是输入参数为name,1表示输入的参数是id

 

 此外,也可以通过使用 @Query 来执行一个更新操作,为此,我们需要在使用 @Query 的同时,用 @Modifying 来将该操作标识为修改查询,这样框架最终会生成一个更新的操作,而非查询

package com.atguigu.springdata;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

import antlr.collections.List;

/*
* 符合SpringDatajpa的dao层接口规范
*JpaRepository<操作的实体类类型,实体类中主键属性的类型>
    *封装了基本的CRUD操作
 JpaSpecificationExecutor<操作的实体类类型>
    *封装了复杂查询操作(分页)
* */
 

public interface CustomerDao  extends JpaRepository<Customer,Long>, JpaSpecificationExecutor<Customer> 
{
    


   

    //@Query 使用jpql的方式查询。?1代表参数的占位符,其中1对应方法中的参数索引

    @Query(value="from Customer where custName = ?1")

    public Customer findCustomer(String custName);
    
    
    @Query(value="update Customer set custName = ?1 where custId = ?2")

    @Modifying

    public void updateCustomer(String custName,Long custId);
 
}

执行更新或者删除操作,必须需要添加 @Modifying,此外必须要具有事务操作

@Test
    @Transactional
    @Rollback(value=false)
    public void testupdateCustomer() {
        customerDao.updateCustomer("我是可不2222", (long) 2);
    }
    

执行更新删除操作需要有事务所有上面有@Transactional,此外jpa执行事务操作完成之后默认会回滚,当数据更新操作成功之后,因为jpa默认要回滚,会把更新的数据还原回去,我们要在数据库中看到更新的

数据,我们要禁止jpa的回滚@Rollback(value=false)

3.3 使用SQL语句查询
Spring Data JPA同样也支持sql语句的查询,如下:

 

package com.atguigu.springdata;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

/*
* 符合SpringDatajpa的dao层接口规范
*JpaRepository<操作的实体类类型,实体类中主键属性的类型>
    *封装了基本的CRUD操作
 JpaSpecificationExecutor<操作的实体类类型>
    *封装了复杂查询操作(分页)
* */
 

public interface CustomerDao  extends JpaRepository<Customer,Long>, JpaSpecificationExecutor<Customer> 
{
    


   

    //@Query 使用jpql的方式查询。?1代表参数的占位符,其中1对应方法中的参数索引

    @Query(value="from Customer where custName = ?1")

    public Customer findCustomer(String custName);
    
    
    @Query(value="update Customer set custName = ?1 where custId = ?2")
    @Modifying
    public void updateCustomer(String custName,Long custId);
 
    
    /**

     * nativeQuery : 使用本地sql的方式查询

     */

    @Query(value="select * from cst_customer",nativeQuery=true)

    public List<Object[]> findSql();
    
}

这里千万要注意返回的是一个List<Object[]>,每一个元素是一个Object类型的数组,不能写成List<Customer[]>

@Test
    public void testfindSql() {
          List<Object[]> datas = customerDao.findSql();
          
          for(Object[] data:datas){
              
              System.out.println(Arrays.toString(data));
          }
          
    }
package com.atguigu.springdata;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

/*
* 符合SpringDatajpa的dao层接口规范
*JpaRepository<操作的实体类类型,实体类中主键属性的类型>
    *封装了基本的CRUD操作
 JpaSpecificationExecutor<操作的实体类类型>
    *封装了复杂查询操作(分页)
* */
 

public interface CustomerDao  extends JpaRepository<Customer,Long>, JpaSpecificationExecutor<Customer> 
{
    


   

    //@Query 使用jpql的方式查询。?1代表参数的占位符,其中1对应方法中的参数索引

    @Query(value="from Customer where custName = ?1")

    public Customer findCustomer(String custName);
    
    
    @Query(value="update Customer set custName = ?1 where custId = ?2")
    @Modifying
    public void updateCustomer(String custName,Long custId);
 
    
    /**

     * nativeQuery : 使用本地sql的方式查询

     */

    @Query(value="select * from cst_customer",nativeQuery=true)

    public List<Object[]> findSql();
    
    
    @Query(value = "select *    from  cst_customer where cust_name like ?1",nativeQuery = true)
    public List<Object []> findSql2(String name);
    
}

测试代码

import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collector;
import java.util.stream.Collectors;

import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.sql.DataSource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.Query;
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;

import com.atguigu.springdata.Customer;
import com.atguigu.springdata.CustomerDao;
import com.itcast.utils.JpaUtils;



@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class SpringDataTest {

    @Autowired
    private CustomerDao customerDao;
    
    @Test
    public  void testFind() {
        
      com.atguigu.springdata.Customer customer = customerDao.findOne((long) 2);
      System.out.println(customer.toString());
    }
    
    /**

     * 保存客户:调用save(obj)方法

     */

    @Test

    public void testSave() {

        Customer c = new Customer();

        c.setCustName("传智播客");

        customerDao.save(c);

    }

   

    /**

     * 修改客户:调用save(obj)方法

     *      对于save方法的解释:如果执行此方法是对象中存在id属性,即为更新操作会先根据id查询,再更新   

     *                      如果执行此方法中对象中不存在id属性,即为保存操作

     *         

     */

    @Test

    public void testUpdate() {

        //根据id查询id为1的客户

        Customer customer = customerDao.findOne(1l);

        //修改客户名称

        customer.setCustName("传智播客顺义校区");

        //更新

        customerDao.save(customer);

    }
    
    @Test

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

    public void testExits() {
          boolean exists = customerDao.exists((long) 2);
          
          System.out.println(exists);
    }
    
    
    @Test

    @Transactional
    public void testGetOne() {
          Customer one = customerDao.getOne((long) 2);
          
          System.out.println(one);
    }
    
    @Test
    @Transactional
    @Rollback(value=false)
    public void testupdateCustomer() {
        customerDao.updateCustomer("我是可不2222", (long) 2);
    }
    
    @Test
    public void testfindSql() {
          List<Object[]> datas = customerDao.findSql();
          
          for(Object[] data:datas){
              
              System.out.println(Arrays.toString(data));
          }
          
    }
    
  //测试sql查询
    @Test
    public void testFindSql()
    {

        List<Object[]> list = customerDao.findSql2("迅腾软件%");//模糊查询
        for(Object[] obj: list){

            System.out.println(Arrays.toString(obj));
        }
    }

    
}

3.4   方法命名规则查询

顾名思义,方法命名规则查询就是根据方法的名字,就能创建查询。只需要按照Spring Data JPA提供的方法命名规则定义方法的名称,就可以完成查询工作。Spring Data JPA在程序执行的时候会根据方法名称进行解析,并自动生成查询语句进行查询

按照Spring Data JPA 定义的规则,查询方法以findBy开头,涉及条件查询时,条件的属性用条件关键字连接,要注意的是:条件属性首字母需大写。框架在进行方法名解析时,会先把方法名多余的前缀截取掉,然后对剩下部分进行解析。

package com.atguigu.springdata;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

/*
* 符合SpringDatajpa的dao层接口规范
*JpaRepository<操作的实体类类型,实体类中主键属性的类型>
    *封装了基本的CRUD操作
 JpaSpecificationExecutor<操作的实体类类型>
    *封装了复杂查询操作(分页)
* */
 

public interface CustomerDao  extends JpaRepository<Customer,Long>, JpaSpecificationExecutor<Customer> 
{
    


   

    //@Query 使用jpql的方式查询。?1代表参数的占位符,其中1对应方法中的参数索引

    @Query(value="from Customer where custName = ?1")

    public Customer findCustomer(String custName);
    
    
    @Query(value="update Customer set custName = ?1 where custId = ?2")
    @Modifying
    public void updateCustomer(String custName,Long custId);
 
    
    /**

     * nativeQuery : 使用本地sql的方式查询

     */

    @Query(value="select * from cst_customer",nativeQuery=true)

    public List<Object[]> findSql();
    
    
    @Query(value = "select *    from  cst_customer where cust_name like ?1",nativeQuery = true)
    public List<Object []> findSql2(String name);
    
    
    //方法命名方式查询(根据客户名称查询客户)

    public Customer findByCustName(String custName);
    
}

测试代码如下

 @Test
    public void testFindSql22()
    {

       Customer customer = customerDao.findByCustName("3333");
       System.out.println(customer.toString());
    }

 

 

 

 我们使用下Like查看下模糊查询

package com.atguigu.springdata;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

/*
* 符合SpringDatajpa的dao层接口规范
*JpaRepository<操作的实体类类型,实体类中主键属性的类型>
    *封装了基本的CRUD操作
 JpaSpecificationExecutor<操作的实体类类型>
    *封装了复杂查询操作(分页)
* */
 

public interface CustomerDao  extends JpaRepository<Customer,Long>, JpaSpecificationExecutor<Customer> 
{
    


   

    //@Query 使用jpql的方式查询。?1代表参数的占位符,其中1对应方法中的参数索引

    @Query(value="from Customer where custName = ?1")

    public Customer findCustomer(String custName);
    
    
    @Query(value="update Customer set custName = ?1 where custId = ?2")
    @Modifying
    public void updateCustomer(String custName,Long custId);
 
    
    /**

     * nativeQuery : 使用本地sql的方式查询

     */

    @Query(value="select * from cst_customer",nativeQuery=true)

    public List<Object[]> findSql();
    
    
    @Query(value = "select *    from  cst_customer where cust_name like ?1",nativeQuery = true)
    public List<Object []> findSql2(String name);
    
    
    //方法命名方式查询(根据客户名称查询客户)

    public Customer findByCustName(String custName);
    
    public List<Customer> findByCustNameLike(String custName);
    
}

测试代码如下

  
    @Test
    public void testFindSql22()
    {

       List<Customer> customers = customerDao.findByCustNameLike("3333%");
       for(Customer customer:customers){
           System.out.println(customer.toString());
       }
       
    }

 

 这里没有占位符,两个参数顺利不能弄错了

package com.atguigu.springdata;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

/*
* 符合SpringDatajpa的dao层接口规范
*JpaRepository<操作的实体类类型,实体类中主键属性的类型>
    *封装了基本的CRUD操作
 JpaSpecificationExecutor<操作的实体类类型>
    *封装了复杂查询操作(分页)
* */
 

public interface CustomerDao  extends JpaRepository<Customer,Long>, JpaSpecificationExecutor<Customer> 
{
    


   

    //@Query 使用jpql的方式查询。?1代表参数的占位符,其中1对应方法中的参数索引

    @Query(value="from Customer where custName = ?1")

    public Customer findCustomer(String custName);
    
    
    @Query(value="update Customer set custName = ?1 where custId = ?2")
    @Modifying
    public void updateCustomer(String custName,Long custId);
 
    
    /**

     * nativeQuery : 使用本地sql的方式查询

     */

    @Query(value="select * from cst_customer",nativeQuery=true)

    public List<Object[]> findSql();
    
    
    @Query(value = "select *    from  cst_customer where cust_name like ?1",nativeQuery = true)
    public List<Object []> findSql2(String name);
    
    
    //方法命名方式查询(根据客户名称查询客户)

    public Customer findByCustName(String custName);
    
    public List<Customer> findByCustNameLike(String custName);
    
    public List<Customer> findByCustNameLikeAndCusIndustry(String custName,String cusIndustry);
    
}

测试代码如下

 @Test
    public void testFindSql22()
    {

       List<Customer> customers = customerDao.findByCustNameLikeAndCusIndustry("3333%","明星");
       for(Customer customer:customers){
           System.out.println(customer.toString());
       }
       
    }
Hibernate: 
    select
        customer0_.cust_id as cust_id1_0_,
        customer0_.cust_industry as cust_ind2_0_,
        customer0_.cust_address as cust_add3_0_,
        customer0_.cust_level as cust_lev4_0_,
        customer0_.cust_name as cust_nam5_0_,
        customer0_.cust_phone as cust_pho6_0_,
        customer0_.cust_source as cust_sou7_0_ 
    from
        cst_customer customer0_ 
    where
        (
            customer0_.cust_name like ?
        ) 
        and customer0_.cust_industry=?

 我们重点来看下JpaSpecificationExecutor方法

 这个接口有上面的几个方法,T findOne(Specification<T> spec);之前的JpaRepository接口也有findOne方法只能依据主键查询,但是没有携带Specification参数,这里携带了Specification参数

我们可以按照主键查询,也可以安装名称查询,我们可以自定义查询条件

 

/**
 * Specification in the sense of Domain Driven Design.
 * 
 * @author Oliver Gierke
 * @author Thomas Darimont
 */
public interface Specification<T> {

    /**
     * Creates a WHERE clause for a query of the referenced entity in form of a {@link Predicate} for the given
     * {@link Root} and {@link CriteriaQuery}.
     * 
     * @param root
     * @param query
     * @return a {@link Predicate}, must not be {@literal null}.
     */
    Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);
}

我们来测试下上面的几个接口

 

 对象CriteriaBuilder有下面这样多的比较的方式

 

 @Test
    public void testFindSql223333()
    {

     Specification<Customer> spec = new Specification<Customer>() {

        public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
            // TODO Auto-generated method stub
            Path<Object> custName = root.get("custName");
            Predicate predicate = cb.equal(custName, "3333");
            return predicate;
        }
    };
       
     Customer customer = customerDao.findOne(spec);
     System.out.println(customer.toString());
    }

多个查询条件的拼接

@Test
    public void testFindSql223333222()
    {

     Specification<Customer> spec = new Specification<Customer>() {

        public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
            // TODO Auto-generated method stub
            Path<Object> custName = root.get("custName");
            Path<Object> cusIndustry = root.get("cusIndustry");
            Predicate predicate1 = cb.equal(custName, "3333");
            Predicate predicate2 = cb.equal(cusIndustry, "2222");
            Predicate predicate3 = cb.and(predicate1,predicate2);
            return predicate3;
        }
    };
       
     Customer customer = customerDao.findOne(spec);
     System.out.println(customer.toString());
    }

@Test
    public void testFindSql223333222wwww()
    {

     Specification<Customer> spec = new Specification<Customer>() {

        public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
            // TODO Auto-generated method stub
            Path<Object> custName = root.get("custName");
            Predicate predicate = cb.like(custName.as(String.class), "33%");
            return predicate;
        }
    };
       
     List<Customer> customer = customerDao.findAll(spec);
     System.out.println(customer.toString());
    }

对于 List<Customer> customer = customerDao.findAll(spec)返回的数据是一个集合,我们可以指定返回的集合中的数据按照某种方式进行排序

 @Test
    public void testFindSql223333222wwwwww()
    {

     Specification<Customer> spec = new Specification<Customer>() {

        public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
            // TODO Auto-generated method stub
            Path<Object> custName = root.get("custName");
            Predicate predicate = cb.like(custName.as(String.class), "33%");
            return predicate;
        }
    };
       
    Sort sort = new Sort(Sort.Direction.ASC,"custId");
     List<Customer> customer = customerDao.findAll(spec,sort);
     System.out.println(customer.toString());
    }

按照"custId"的Sort.Direction.ASC进行排序

 

    /**
     * 目标: 实现带查询条件的分页. id > 5 的条件
     * 
     * 调用 JpaSpecificationExecutor 的 Page<T> findAll(Specification<T> spec, Pageable pageable);
     * Specification: 封装了 JPA Criteria 查询的查询条件
     * Pageable: 封装了请求分页的信息: 例如 pageNo, pageSize, Sort
     */
    @Test
    public void testJpaSpecificationExecutorss(){
        int pageNo = 3 - 1;
        int pageSize = 5;
        Sort sort = new Sort(Sort.Direction.ASC,"custId");
        //封装分页的信息
        PageRequest pageable = new PageRequest(pageNo, pageSize,sort);
        
         Specification<Customer> spec = new Specification<Customer>() {

                public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                    // TODO Auto-generated method stub
                    Path<Object> custName = root.get("custName");
                    Predicate predicate = cb.like(custName.as(String.class), "33%");
                    return predicate;
                }
            };
               
            
        
        Page<Customer> page = customerDao.findAll(spec, pageable);
        
        System.out.println("总记录数: " + page.getTotalElements());
        System.out.println("当前第几页: " + (page.getNumber() + 1));
        System.out.println("总页数: " + page.getTotalPages());
        System.out.println("当前页面的 List: " + page.getContent());
        List<Customer> content = page.getContent();
        System.out.println("当前页面的记录数: " + page.getNumberOfElements());
        /*List<Person> collect = page.getContent().stream().map(stat->(Person)stat).collect(Collectors.toList());
        System.out.println("当前页面的 List1: " + collect);*/
    }

打印结果如下

Hibernate: 
    select
        count(customer0_.cust_id) as col_0_0_ 
    from
        cst_customer customer0_ 
    where
        customer0_.cust_name like ?
总记录数: 1
当前第几页: 3
总页数: 1
当前页面的 List: []
当前页面的记录数: 0

 

 

 

 客户个联系人是一对多的关系

 

 

3.2 实战Hibernate一对多关联映射
3.2.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_phone` varchar(64) DEFAULT NULL COMMENT '固定电话',

  `cust_mobile` varchar(16) DEFAULT NULL COMMENT '移动电话',

  PRIMARY KEY (`cust_id`)

) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

 

联系人表:

CREATE TABLE `cst_linkman` (

  `lkm_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '联系人编号(主键)',

  `lkm_name` varchar(16) DEFAULT NULL COMMENT '联系人姓名',

  `lkm_cust_id` bigint(32) DEFAULT NULL COMMENT '客户id',

  `lkm_gender` char(1) DEFAULT NULL COMMENT '联系人性别',

  `lkm_phone` varchar(16) DEFAULT NULL COMMENT '联系人办公电话',

  `lkm_mobile` varchar(16) DEFAULT NULL COMMENT '联系人手机',

  `lkm_email` varchar(64) DEFAULT NULL COMMENT '联系人邮箱',

  `lkm_qq` varchar(16) DEFAULT NULL COMMENT '联系人qq',

  `lkm_position` varchar(16) DEFAULT NULL COMMENT '联系人职位',

  `lkm_memo` varchar(512) DEFAULT NULL COMMENT '联系人备注',

  PRIMARY KEY (`lkm_id`),

  KEY `FK_cst_linkman_lkm_cust_id` (`lkm_cust_id`),

  CONSTRAINT `FK_cst_linkman_lkm_cust_id` FOREIGN KEY (`lkm_cust_id`) REFERENCES `cst_customer` (`cust_id`) ON DELETE NO ACTION ON UPDATE NO ACTION

) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

接下来我们要新增一个联系人的实体类对象

在customer客户端实体类中,需要配置下面的信息

package com.atguigu.springdata;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.GenerationType;

import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity // 声明此类是个实体类 需要导入javax.persistence.Entity;

@Table(name = "cst_customer") //需要将该类对应到数据库中的哪一个表中,name中填表的名称

public class Customer {



@Id //声明主键 

@GeneratedValue(strategy = GenerationType.IDENTITY) //声明主键的生成策略为自动递增

//mysql使用自增模式,orcle 使用序列模式

@Column(name = "cust_id") //设置该属性和数据库中的哪一个字段对应

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 cusIndustry;

 

@Column(name = "cust_phone")

private String custPhone;

 

@Column(name = "cust_address")

private String custAddress;


@OneToMany(targetEntity=LinkMan.class)
@JoinColumn(name="lkm_cust_id",referencedColumnName="cust_id")
private Set<LinkMan> linkMans = new HashSet<LinkMan>();

public Long getCustId() {

return custId;

}



public void setCustId(Long custId) {

this.custId = custId;

}



public String getCustName() {

return custName;

}



public void setCustName(String custName) {

this.custName = custName;

}



public String getCustSource() {

return custSource;

}



public void setCustSource(String custSource) {

this.custSource = custSource;

}



public String getCustLevel() {

return custLevel;

}



public void setCustLevel(String custLevel) {

this.custLevel = custLevel;

}



public String getCusIndustry() {

return cusIndustry;

}



public void setCusIndustry(String cusIndustry) {

this.cusIndustry = cusIndustry;

}



public String getCustPhone() {

return custPhone;

}



public void setCustPhone(String custPhone) {

this.custPhone = custPhone;

}



public String getCustAddress() {

return custAddress;

}



public void setCustAddress(String custAddress) {

this.custAddress = custAddress;

}



@Override

public String toString() {

return "Customer [custId=" + custId + ", custName=" + custName + ", custSource=" + custSource

+ ", custLevel=" + custLevel + ", cusIndustry=" + cusIndustry + ", custPhone=" + custPhone

+ ", custAddress=" + custAddress + "]";

}



public Set<LinkMan> getLinkMans() {
    return linkMans;
}



public void setLinkMans(Set<LinkMan> linkMans) {
    this.linkMans = linkMans;
}

 

}

在联系人方需要配置如下

package com.atguigu.springdata;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity // 声明此类是个实体类 需要导入javax.persistence.Entity;

@Table(name = "cst_linkman") //需要将该类对应到数据库中的哪一个表中,name中填表的名称
public class LinkMan {

@Id //声明主键
@GeneratedValue(strategy = GenerationType.IDENTITY) //声明主键的生成策略为自动递增
@Column(name = "lkm_id") //设置该属性和数据库中的哪一个字段对应


private Long lkmId; @Column(name = "lkm_gender") //设置该属性和数据库中的哪一个字段对应 private Character lkmGender; @Column(name = "lkm_name") //设置该属性和数据库中的哪一个字段对应 private String lkmName; @Column(name = "lkm_phone") //设置该属性和数据库中的哪一个字段对应 private String lkmPhone; @Column(name = "lkm_email") //设置该属性和数据库中的哪一个字段对应 private String lkmEmail; @Column(name = "lkm_qq") //设置该属性和数据库中的哪一个字段对应 private String lkmQq; @Column(name = "lkm_mobile") //设置该属性和数据库中的哪一个字段对应 private String lkmMobile; @Column(name = "lkm_memo") //设置该属性和数据库中的哪一个字段对应 private String lkmMemo; @Column(name = "lkm_position") //设置该属性和数据库中的哪一个字段对应 private String lkmPosition; @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 getLkmId() { return lkmId; } public void setLkmId(Long lkmId) { this.lkmId = lkmId; } public Character getLkmGender() { return lkmGender; } public void setLkmGender(Character lkmGender) { this.lkmGender = lkmGender; } public String getLkmName() { return lkmName; } public void setLkmName(String lkmName) { this.lkmName = lkmName; } public String getLkmPhone() { return lkmPhone; } public void setLkmPhone(String lkmPhone) { this.lkmPhone = lkmPhone; } public String getLkmEmail() { return lkmEmail; } public void setLkmEmail(String lkmEmail) { this.lkmEmail = lkmEmail; } public String getLkmQq() { return lkmQq; } public void setLkmQq(String lkmQq) { this.lkmQq = lkmQq; } public String getLkmMobile() { return lkmMobile; } public void setLkmMobile(String lkmMobile) { this.lkmMobile = lkmMobile; } public String getLkmMemo() { return lkmMemo; } public void setLkmMemo(String lkmMemo) { this.lkmMemo = lkmMemo; } public String getLkmPosition() { return lkmPosition; } public void setLkmPosition(String lkmPosition) { this.lkmPosition = lkmPosition; } }

  @JoinColumn(name="lkm_cust_id",referencedColumnName="cust_id")中表示的是表联系人中的lkm_cust_id字段的值,来自于表客户的cust_id

接下来,我们要编写一个操作联系人的接口类

package com.atguigu.springdata;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

/*
* 符合SpringDatajpa的dao层接口规范
*JpaRepository<操作的实体类类型,实体类中主键属性的类型>
    *封装了基本的CRUD操作
 JpaSpecificationExecutor<操作的实体类类型>
    *封装了复杂查询操作(分页)
* */
 

public interface LinnkManDao  extends JpaRepository<LinkMan,Long>, JpaSpecificationExecutor<LinkMan> 
{
    


   

}

整个工程的结构如下所示

 接下来我们来就可以进行测试了

 我们来看下程序的代码

import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collector;
import java.util.stream.Collectors;

import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.sql.DataSource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.Query;
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;

import com.atguigu.springdata.Customer;
import com.atguigu.springdata.CustomerDao;
import com.atguigu.springdata.LinkMan;
import com.atguigu.springdata.LinnkManDao;
import com.itcast.utils.JpaUtils;



@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class oneToManyTest {

    @Autowired
    private CustomerDao customerDao;
    
    
    @Autowired
    private LinnkManDao linnkManDao;
    
   
    @Test
    @Transactional
    @Rollback(value=false)
    public void save(){
        
        Customer customer = new Customer();
        customer.setCustName("百度");
        
        LinkMan linkMan = new LinkMan();
        linkMan.setLkmName("小明");
        linkMan.setCustomer(customer);
        
        customerDao.save(customer);
        
        linnkManDao.save(linkMan);
        
    }

}

这里操作了两张表要保证事务的一致性 @Transactional,其次事务操作成功之后要让更新的记录保存到数据库,不进行回滚  @Rollback(value=false)

原文地址:https://www.cnblogs.com/kebibuluan/p/11737015.html