springdata学习记录


springdata简介

是Spring 的一个子项目。用于简化数据库访问,支持NoSQL 和 关系数据存储。其主要目标是使数据库的访问变得方便快捷。

相关概述

ORM概述

ORM(Object-Relational Mapping) 表示对象关系映射。在面向对象的软件开发中,通过ORM,就可以把对象映射到关系型数据库中。只要有一套程序能够做到建立对象与数据库的关联,操作对象就可以直接操作数据库数据,就可以说这套程序实现了ORM对象关系映射
简单的说:实现一个应用程序时(不使用O/R Mapping),可能会写特别多数据访问层的代码,从数据库保存数据、修改数据、删除数据,而这些代码都是重复的。而使用ORM则会大大减少重复性代码。ORM就是建立实体类和数据库表之间的关系,从而达到操作实体类就相当于操作数据库表的目的。

hibernate概述

Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。

JPA概述

JPA的全称是Java Persistence API, 即Java 持久化API,是SUN公司推出的一套基于ORM的规范,内部是由一系列的接口和抽象类构成。
JPA通过JDK 5.0注解描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。
JPA和Hibernate的关系就像JDBC和JDBC驱动的关系,JPA是规范,Hibernate除了作为ORM框架之外,它也是一种JPA实现。JPA怎么取代Hibernate呢?JDBC规范可以驱动底层数据库吗?答案是否定的,也就是说,如果使用JPA规范进行数据库操作,底层需要hibernate作为其实现类完成数据持久化工作。

JPA案例

1、Maven工程pom.xml中导入坐标

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

        <!-- jdbc驱动jar包 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
    </dependencies>

2、配置JPA的核心配置文件
** 在java工程的src路径下创建一个名为META-INF的文件夹,在此文件夹下创建一个名为persistence.xml的配置文件 **

<?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:分布式事务管理 -->
    <persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL">
        <!--配置JPA规范的服务提供商 -->
        <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" />
            <!-- 数据库用户名 -->
            <property name="javax.persistence.jdbc.user" value="root" />
            <!-- 数据库密码 -->
            <property name="javax.persistence.jdbc.password" value="rootroot" />

            <!--jpa提供者的可选配置:我们的JPA规范的提供者为hibernate,所以jpa的核心配置中兼容hibernate的配 -->
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.format_sql" value="true" />
            <property name="hibernate.hbm2ddl.auto" value="create" />
        </properties>
    </persistence-unit>
</persistence>

3、创建数据库表

CREATE TABLE per_student (
      per_id bigint(32) NOT NULL AUTO_INCREMENT COMMENT '学生编号(主键)',
      per_name varchar(32) NOT NULL COMMENT '学生姓名',
      per_age int DEFAULT NULL COMMENT '学生年龄',
      per_sex varchar(2) DEFAULT NULL COMMENT '学生性别',
      per_major varchar(32) DEFAULT NULL COMMENT '学生专业',
      per_phone varchar(64) DEFAULT NULL COMMENT '学生联系电话',
      PRIMARY KEY (`per_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

4、创建实体类

import java.io.Serializable;
import javax.persistence.*
/**
*        * 所有的注解都是使用JPA的规范提供的注解,
 *        * 所以在导入注解包的时候,一定要导入javax.persistence下的
 */
@Entity //声明实体类
@Table(name="per_student") //建立实体类和表的映射关系
public class Student implements Serializable{

    @Id//声明当前私有属性为主键
    @GeneratedValue(strategy=GenerationType.IDENTITY) //配置主键的生成策略
    @Column(name="per_id") //指定和表中per_id字段的映射关系
    private Long perId;

    @Column(name="per_name") //指定和表中per_name字段的映射关系
    private String perName;

    @Column(name="per_age")//指定和表中per_age字段的映射关系
    private String perAge;

    @Column(name="per_sex")//指定和表中per_sex字段的映射关系
    private String perSex;

    @Column(name="per_major")//指定和表中per_major字段的映射关系
    private String perMajor;

    @Column(name="per_phone")//指定和表中per_phone字段的映射关系
    private String perPhone;

    public Long getPerId() {
        return perId;
    }

    public void setPerId(Long perId) {
        this.perId = perId;
    }

    public String getPerName() {
        return perName;
    }

    public void setPerName(String perName) {
        this.perName = perName;
    }

    public int getPerAge() {
        return perAge;
    }

    public void setPerAge(int perAge) {
        this.perAge = perAge;
    }

    public String getPerSex() {
        return perSex;
    }

    public void setPerSex(String perSex) {
        this.perSex = perSex;
    }

    public String getPerMajor() {
        return perMajor;
    }

    public void setPerMajor(String perMajor) {
        this.perMajor = perMajor;
    }

    public String getPerPhone() {
        return perPhone;
    }

    public void setPerPhone(String perPhone) {
        this.perPhone = perPhone;
    }
}

补充

@Entity
作用:指定当前类是实体类。
@Table
作用:指定实体类和表之间的对应关系。
属性:
name:指定数据库表的名称
@Id
作用:指定当前字段是主键。
@GeneratedValue
作用:指定主键的生成方式。。
属性:
strategy :指定主键生成策略。
@Column
作用:指定实体类属性和数据库表之间的对应关系
属性:
name:指定数据库表的列名称。
unique:是否唯一
nullable:是否可以为空
inserttable:是否可以插入
updateable:是否可以更新
columnDefinition: 定义建表时创建此列的DDL
secondaryTable: 从表名。如果此列不建在主表上(默认建在主表),该属性定义该列所在从表的名字搭建开发环境

5、测试-添加数据

@Test
    public void test() {
        /**
         * 创建实体管理类工厂,借助Persistence的静态方法获取
         *         其中传递的参数为持久化单元名称,需要jpa配置文件中指定
         */
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa");
        //创建实体管理类
        EntityManager em = factory.createEntityManager();
        //获取事务对象
        EntityTransaction tx = em.getTransaction();
        //开启事务
        tx.begin();
        Student c = new Student();
            c.setPerName("张三");
            c.setPerAge(18);
            c.setPerSex("男");
            c.setPerMajor("java开发攻城狮");
            c.setPerPhone("17856520896");
        //保存操作
        em.persist(c);
        //提交事务
        tx.commit();
        //释放资源
        em.close();
        factory.close();
    }

JPA的API介绍

Persistence对象
Persistence对象主要作用是用于获取EntityManagerFactory对象的 。通过调用该类的createEntityManagerFactory静态方法,根据配置文件中持久化单元名称创建EntityManagerFactory。

@Test
String unitName = "myJpa";
EntityManagerFactory factory= Persistence.createEntityManagerFactory(unitName);

EntityManagerFactory
EntityManagerFactory 接口主要用来创建 EntityManager 实例
//创建实体管理类
EntityManager em = factory.createEntityManager();
由于EntityManagerFactory 是一个线程安全的对象(即多个线程访问同一个EntityManagerFactory 对象不会有线程安全问题),并且EntityManagerFactory 的创建极其浪费资源,所以在使用JPA编程时,我们可以对EntityManagerFactory 的创建进行优化,只需要做到一个工程只存在一个EntityManagerFactory 即可

EntityManager
在 JPA 规范中, EntityManager是完成持久化操作的核心对象。实体类作为普通 java对象,只有在调用 EntityManager将其持久化后才会变成持久化对象。EntityManager对象在一组实体类与底层数据源之间进行 O/R 映射的管理。它可以用来管理和更新 Entity Bean, 根椐主键查找 Entity Bean, 还可以通过JPQL语句查询实体。
我们可以通过调用EntityManager的方法完成获取事务,以及持久化数据库的操作
方法说明:

getTransaction : 获取事务对象
persist : 保存操作
merge : 更新操作
remove : 删除操作
find/getReference : 根据id查询

EntityTransaction
在 JPA 规范中, EntityTransaction是完成事务操作的核心对象,对于EntityTransaction在我们的java代码中承接的功能比较简单

begin:开启事务
commit:提交事务
rollback:回滚事务

JPAUtil工具类

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

public final class JPAUtil {
    // JPA的实体管理器工厂:相当于Hibernate的SessionFactory
    private static EntityManagerFactory em;
    // 使用静态代码块赋值
    static {
        // 注意:该方法参数必须和persistence.xml中persistence-unit标签name属性取值一致
        em = Persistence.createEntityManagerFactory("myPersistUnit");
    }
    /**
     * 使用管理器工厂生产一个管理器对象
     * 
     * @return
     */
    public static EntityManager getEntityManager() {
        return em.createEntityManager();
    }
}

JPA增删改查

添加

@Test
public void Add() {
    // 定义对象
    Student c = new Student();
    c.setPerName("张三");
    c.setPerAge(18);
    c.setPerSex("男");
    c.setPerMajor("java开发攻城狮");
    c.setPerPhone("17856520896");
    EntityManager em = null;
    EntityTransaction tx = null;
    try {
        // 获取实体管理对象
        em = JPAUtil.getEntityManager();
        // 获取事务对象
        tx = em.getTransaction();
        // 开启事务
        tx.begin();
        // 执行操作
        em.persist(c);
        // 提交事务
        tx.commit();
    } catch (Exception e) {
        // 回滚事务
        tx.rollback();
        e.printStackTrace();
    } finally {
        // 释放资源
        em.close();
    }
}

修改

@Test
public void Merge(){  
    //定义对象
    EntityManager em=null;  
    EntityTransaction tx=null;  
    try{  
        //获取实体管理对象
        em=JPAUtil.getEntityManager();
        //获取事务对象
        tx=em.getTransaction();
        //开启事务
        tx.begin();
        //执行操作
        Student c1 = em.find(Student.class, 1L);
        c1.setPerName("李四");
        em.clear();//把c1对象从缓存中清除出去
        em.merge(c1);
        //提交事务
        tx.commit(); 
    }catch(Exception e){
        //回滚事务
        tx.rollback();
        e.printStackTrace();  
    }finally{  
        //释放资源
        em.close();  
    }    
}

删除

@Test
public void testRemove() {
    // 定义对象
    EntityManager em = null;
    EntityTransaction tx = null;
    try {
        // 获取实体管理对象
        em = JPAUtil.getEntityManager();
        // 获取事务对象
        tx = em.getTransaction();
        // 开启事务
        tx.begin();
        // 执行操作
        Student c1 = em.find(Student.class,1L);
        em.remove(c1);
        // 提交事务
        tx.commit();
    } catch (Exception e) {
        // 回滚事务
        tx.rollback();
        e.printStackTrace();
    } finally {
        // 释放资源
        em.close();
    }
}

查询

根据id查询

立即加载的策略方法

@Test
public void testGetOne() {
    // 定义对象
    EntityManager em = null;
    EntityTransaction tx = null;
    try {
        // 获取实体管理对象
        em = JPAUtil.getEntityManager();
        // 获取事务对象
        tx = em.getTransaction();
        // 开启事务
        tx.begin();
        // 执行操作
        Customer c1 = em.find(Customer.class, 1L);
        // 提交事务
        tx.commit();
        System.out.println(c1); // 输出查询对象
    } catch (Exception e) {
        // 回滚事务
        tx.rollback();
        e.printStackTrace();
    } finally {
        // 释放资源
        em.close();
    }
}

延迟加载的策略方法:

/**
 * 查询一个: 使用延迟加载策略
 */
@Test
public void testLoadOne() {
    // 定义对象
    EntityManager em = null;
    EntityTransaction tx = null;
    try {
        // 获取实体管理对象
        em = JPAUtil.getEntityManager();
        // 获取事务对象
        tx = em.getTransaction();
        // 开启事务
        tx.begin();
        // 执行操作
        Customer c1 = em.getReference(Customer.class, 1L);
        // 提交事务
        tx.commit();
        System.out.println(c1);
    } catch (Exception e) {
        // 回滚事务
        tx.rollback();
        e.printStackTrace();
    } finally {
        // 释放资源
        em.close();
    }
}

查询全部

//查询所有
@Test
    public void findAll() {
        EntityManager em = null;
        EntityTransaction tx = null;
        try {
            //获取实体管理对象
            em = JPAUtil.getEntityManager();
            //获取事务对象
            tx = em.getTransaction();
            tx.begin();
            // 创建query对象
            String jpql = "from Student";
            Query query = em.createQuery(jpql);
            // 查询并得到返回结果
            List list = query.getResultList(); // 得到集合返回类型
            for (Object object : list) { //遍历结果集
                System.out.println(object);
            }
            tx.commit();
        } catch (Exception e) {
            // 回滚事务
            tx.rollback();
            e.printStackTrace();
        } finally {
            // 释放资源
            em.close();
        }
    }

分页查询

//分页查询
@Test
public void findPaged () {
    EntityManager em = null;
    EntityTransaction tx = null;
    try {
        //获取实体管理对象
        em = JPAUtil.getEntityManager();
        //获取事务对象
        tx = em.getTransaction();
        tx.begin();
        //创建query对象
        String jpql = "from Student";
        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();
    }
}

条件查询

//条件查询
@Test
public void findCondition () {
    EntityManager em = null;
    EntityTransaction tx = null;
    try {
        //获取实体管理对象
        em = JPAUtil.getEntityManager();
        //获取事务对象
        tx = em.getTransaction();
        tx.begin();
        //创建query对象
        String jpql = "from Student where perName 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();
    }
}

排序查询

//根据学生id倒序查询所有
@Test
public void testOrder() {
    EntityManager em = null;
    EntityTransaction tx = null;
    try {
        //获取实体管理对象
        em = JPAUtil.getEntityManager();
        //获取事务对象
        tx = em.getTransaction();
        tx.begin();
        // 创建query对象
        String jpql = "from Student order by perId desc";
        Query query = em.createQuery(jpql);
        // 查询并得到返回结果
        List list = query.getResultList(); // 得到集合返回类型
        for (Object object : list) {
            System.out.println(object);
        }
        tx.commit();
    } catch (Exception e) {
        // 回滚事务
        tx.rollback();
        e.printStackTrace();
    } finally {
        // 释放资源
        em.close();
    }
}

统计查询

//统计查询
@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(perId) from Student";
        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();
    }
}

Spring Data JPA

概述

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

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

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

Spring Data JPA案例

引入Spring Data JPA的坐标

    <!-- 公共版本号 -->
    <properties>
        <spring.version>4.2.4.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.9</version>
            <scope>test</scope>
        </dependency>

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

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

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

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

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

        <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>4.2.4.RELEASE</version>
        </dependency>

        <!-- 使用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> 
    </dependencies>

Spring整合Spring Data JPA

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:task="http://www.springframework.org/schema/task"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/data/jpa 
        http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

    <!-- 1.dataSource 配置数据库连接池-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver" />
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/jpa" />
        <property name="user" value="root" />
        <property name="password" value="rootroot" />
    </bean>

    <!-- 2.配置entityManagerFactory -->
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!-- 配置扫描实体类所在的包 -->
        <property name="packagesToScan" value="com.dzkj.domain" />
        <!--  jpa实现厂家 -->
        <property name="persistenceProvider">
            <bean class="org.hibernate.jpa.HibernatePersistenceProvider" />
        </property>
        <!--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>
        <property name="jpaDialect">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
        </property>
         <!--注入jpa的配置信息
            加载jpa的基本配置信息和jpa实现方式(hibernate)的配置信息
            hibernate.hbm2ddl.auto : 自动创建数据库表
                create : 每次都会重新创建数据库表
                update:有表不会重新创建,没有表会重新创建表
        -->
        <property name="jpaProperties" >
            <props>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
            </props>
        </property>
    </bean>

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

    <!-- 整合spring data jpa-->
    <jpa:repositories base-package="com.dzkj.dao"
        transaction-manager-ref="transactionManager"
        entity-manager-factory-ref="entityManagerFactory"></jpa:repositories>

    <!-- 4.声明式事务-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="save*" propagation="REQUIRED"/>
            <tx:method name="insert*" propagation="REQUIRED"/>
            <tx:method name="update*" propagation="REQUIRED"/>
            <tx:method name="delete*" propagation="REQUIRED"/>
            <tx:method name="get*" read-only="true"/>
            <tx:method name="find*" read-only="true"/>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

    <!-- 5.aop-->
    <aop:config>
        <aop:pointcut id="mypoint" expression="execution(* com.dzkj.service.*.*(..))" />
        <aop:advisor advice-ref="txAdvice" pointcut-ref="mypoint" />
    </aop:config>

    <context:component-scan base-package="com.dzkj"></context:component-scan>

</beans>

JPA注解配置实体类映射关系

import javax.persistence.*;
/**
*        * 所有的注解都是使用JPA的规范提供的注解,
 *        * 所以在导入注解包的时候,一定要导入javax.persistence下的
 */
@Entity
@Table(name="per_student") //建立实体类和表的映射关系
public class Student implements Serializable{

    @Id//声明当前私有属性为主键
    @GeneratedValue(strategy=GenerationType.IDENTITY) //配置主键的生成策略
    @Column(name="per_id") //指定和表中per_id字段的映射关系
    private Long perId;

    @Column(name="per_name") //指定和表中per_name字段的映射关系
    private String perName;

    @Column(name="per_age")//指定和表中per_age字段的映射关系
    private int perAge;

    @Column(name="per_sex")//指定和表中per_sex字段的映射关系
    private String perSex;

    @Column(name="per_major")//指定和表中per_major字段的映射关系
    private String perMajor;

    @Column(name="per_phone")//指定和表中per_phone字段的映射关系
    private String perPhone;

    public Long getPerId() {
        return perId;
    }

    public void setPerId(Long perId) {
        this.perId = perId;
    }

    public String getPerName() {
        return perName;
    }

    public void setPerName(String perName) {
        this.perName = perName;
    }

    public int getPerAge() {
        return perAge;
    }

    public void setPerAge(int perAge) {
        this.perAge = perAge;
    }

    public String getPerSex() {
        return perSex;
    }

    public void setPerSex(String perSex) {
        this.perSex = perSex;
    }

    public String getPerMajor() {
        return perMajor;
    }

    public void setPerMajor(String perMajor) {
        this.perMajor = perMajor;
    }

    public String getPerPhone() {
        return perPhone;
    }

    public void setPerPhone(String perPhone) {
        this.perPhone = perPhone;
    }
}

编写Spring Data JPA规范的Dao层接口

1.创建一个Dao层接口,并实现JpaRepository和JpaSpecificationExecutor
2.提供相应的泛型

import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import com.dzkj.Student;
/**
 * JpaRepository<实体类类型,主键类型>:用来完成基本CRUD操作
 * JpaSpecificationExecutor<实体类类型>:用于复杂查询(分页等查询操作)
 */
public interface StudentDao extends JpaRepository<Student, Long>, JpaSpecificationExecutor<Student> {
}

CRUD操作

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

    @Autowired
    private StudentDao studentDao;

    /**
     * 添加学生:调用save(obj)方法
     */
    @Test
    public void testSave() {
        Student c = new Student();
        c.setperName("李四");
        studentDao.save(c);
    }

    /**
     * 修改学生:调用save(obj)方法
     * 对于save方法的解释:如果执行此方法是对象中存在id属性,即为更新操作会先根据id查询,再更新    
     *                    如果执行此方法中对象中不存在id属性,即为保存操作  
     */
    @Test
    public void testUpdate() {
        //根据id查询id为1的学生
        Student student = studentDao.findOne(1l);
        //修改学生名称
        student.setCustName("张三");
        //更新
        studentDao.save(student);
    }

    /**
     * 根据id删除:调用delete(id)方法
     */
    @Test
    public void testDelete() {
        studentDao.delete(1l);
    }

    /**
     * 根据id查询:调用findOne(id)方法
     */
    @Test
    public void testFindById() {
        Student student = studentDao.findOne(2l);
        System.out.println(student);
    }
}

spring内部原理

Spring Data JPA 工作原理 : 自定义JpaRespository接口却不用提供实现

JPQL的方式查询

使用Spring Data JPA提供的查询方法已经可以解决大部分的应用场景,对于某些业务来说,还需要灵活的构造查询条件,这时就可以使用@Query注解,结合JPQL的语句方式完成查询,@Query 只需在方法上面标注该注解,同时提供一个JPQL查询语句,使用时调用该方法就可以了

public interface CustomerDao extends JpaRepository<Customer, Long>,JpaSpecificationExecutor<Customer> {    
    //@Query 使用jpql的方式查询所有。
    @Query(value="from Student")
    public List<Student> findAllStudent();

    //@Query 使用jpql的方式查询。?1代表参数的占位符,其中1对应方法中的参数索引
    @Query(value="from Student where perName = ?1")
    public Student findStudent(String perName);

    //在使用 @Query 的同时,用 @Modifying 来将该操作标识为修改查询,框架最终会生成一个更新的操作,而非查询
    @Query(value="update Student set perName = ?1 where perId = ?2")
    @Modifying
    public void updateStudent(String perName,Long perId);
}

SQL语句查询

    /**
     * nativeQuery :false(使用jpql查询) | true(使用本地查询:sql查询)
     * 默认jpql查询
     */
    @Query(value="select * from per_student",nativeQuery=true)
    public void findSql();

方法命名规则查询

需要按照Spring Data JPA提供的方法命名规则定义方法的名称,Spring Data JPA在程序执行的时候会根据方法名称进行解析,并自动生成查询语句进行查询

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

具体的关键字,使用方法和生产成SQL如下表所示

: Keyword : : Sample : : 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):

Specifications动态查询

当查询某个实体的时候,给定的条件是不固定的,就需要动态构建相应的查询语句,在Spring Data JPA中可以通过JpaSpecificationExecutor接口查询。相比JPQL,其优势是类型安全,更加的面向对象。

Specifications 条件查询

//依赖注入customerDao
    @Autowired
    private StudentDao studentDao;    
    @Test
    public void testSpecifications() {
          //使用匿名内部类的方式,创建一个Specification的实现类,并实现toPredicate方法
        /**
        *    root    :Root接口,代表查询的根对象,可以通过root获取实体中的属性
        *    query    :代表一个顶层查询对象,用来自定义查询
        *    cb        :用来构建查询,此对象里有很多条件方法
        **/
        Specification <Student> spec = new Specification<Student>() {
            public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                //cb:构建查询,添加查询方式   like:模糊匹配
                //root:从实体Customer对象中按照custName属性进行查询
                return cb.like(root.get("perName").as(String.class), "张三");
            }
        };
        Student student = studentDao.findOne(spec);
        System.out.println(student);
    }

Specifications 分页查询

@Test
    public void testPage() {
        //构造查询条件
        Specification<Student> spec = new Specification<Student>() {
            public Predicate toPredicate(Root<Student> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                return cb.like(root.get("perName").as(String.class), "张三%");
            }
        };
        /**
         * 构造分页参数
         *         Pageable : 接口
         *             PageRequest实现了Pageable接口,调用构造方法的形式构造
         *                 第一个参数:页码(从0开始)
         *                 第二个参数:每页查询条数
         */
        Pageable pageable = new PageRequest(0, 5);
        /**
         * 分页查询,封装为Spring Data Jpa 内部的page bean
         *         此重载的findAll方法为分页方法需要两个参数
         *             第一个参数:查询条件Specification
         *             第二个参数:分页参数
         */
        Page<Student> page = studentDao.findAll(spec,pageable);
        /**
        //获取总页数
        page.getTotalPages();
        //获取总记录数    
        page.getTotalElements();
        //获取列表数据
        page.getContent();
        */
    }

映射的注解说明

@OneToMany:
作用:建立一对多的关系映射
属性:
targetEntityClass:指定多的多方的类的字节码
mappedBy:指定从表实体类中引用主表对象的名称。
cascade:指定要使用的级联操作
fetch:指定是否采用延迟加载
orphanRemoval:是否使用孤儿删除

@ManyToOne
作用:建立多对一的关系
属性:
targetEntityClass:指定一的一方实体类字节码
cascade:指定要使用的级联操作
fetch:指定是否采用延迟加载
optional:关联是否可选。如果设置为false,则必须始终存在非空关系。

@JoinColumn
作用:用于定义主键字段和外键字段的对应关系。
属性:
name:指定外键字段的名称
referencedColumnName:指定引用主表的主键字段名称
unique:是否唯一。默认值不唯一
nullable:是否允许为空。默认值允许。
insertable:是否允许插入。默认值允许。
updatable:是否允许更新。默认值允许。
columnDefinition:列的定义信息。

多表设计

一对多

数据库关系的建立

可以不用创建数据库表 借助springdatajpa的机制自动创建表,在配置文件中添加

<property name="jpaProperties" >
    <props>
        <prop key="hibernate.hbm2ddl.auto">update</prop>
    </props>
</property>
CREATE TABLE  per_teacher(
      tea_id bigint(32) NOT NULL AUTO_INCREMENT COMMENT '老师编号(主键)',
      tea_name varchar(32) NOT NULL COMMENT '老师姓名',
      tea_age int DEFAULT NULL COMMENT '老师年龄',
      tea_sex varchar(2) DEFAULT NULL COMMENT '老师性别',
      tea_major varchar(32) DEFAULT NULL COMMENT '授课专业',
      tea_phone varchar(64) DEFAULT NULL COMMENT '老师联系电话',
            PRIMARY KEY (`tea_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

CREATE TABLE per_student (
      per_id bigint(32) NOT NULL AUTO_INCREMENT COMMENT '学生编号(主键)',
      per_name varchar(32) NOT NULL COMMENT '学生姓名',
      per_age int DEFAULT NULL COMMENT '学生年龄',
      per_sex varchar(2) DEFAULT NULL COMMENT '学生性别',
      per_major varchar(32) DEFAULT NULL COMMENT '学生专业',
      per_phone varchar(64) DEFAULT NULL COMMENT '学生联系电话',
            per_tea_id bigint(32) NOT NULL COMMENT '老师编号(外键)',
      PRIMARY KEY (`per_id`),
            foreign key(per_tea_id) references per_Teacher(tea_id)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

实体类关系建立

老师实体类

import java.util.HashSet;
import java.util.Set;

import javax.persistence.*;

@Entity//表示当前类是一个实体类
@Table(name="per_teacher")//建立当前实体类和表之间的对应关系
public class Teacher {
    @Id//表明当前私有属性是主键
    @GeneratedValue(strategy=GenerationType.IDENTITY)//指定主键的生成策略
    @Column(name="tea_id")//指定和数据库表中的cust_id列对应
    private Long teaId;

    @Column(name="tea_name")
    private String teaName;

    @Column(name="tea_age")
    private int teaAge;

    @Column(name="tea_sex")
    private String teaSex;

    @Column(name="tea_major")
    private String teaMajor;

    @Column(name="tea_phone")
    private String teaPhone;

    //设置了双向关系后,会发送两条insert语句,一条多余的update语句,解决思路就是一方放弃维护权
    @OneToMany(mappedBy="teacher",cascade = CascadeType.ALL)
    private Set<Student> students = new HashSet<>();

    public Long getTeaId() {
        return teaId;
    }

    public void setTeaId(Long teaId) {
        this.teaId = teaId;
    }

    public String getTeaName() {
        return teaName;
    }

    public void setTeaName(String teaName) {
        this.teaName = teaName;
    }

    public int getTeaAge() {
        return teaAge;
    }

    public void setTeaAge(int teaAge) {
        this.teaAge = teaAge;
    }

    public String getTeaSex() {
        return teaSex;
    }

    public void setTeaSex(String teaSex) {
        this.teaSex = teaSex;
    }

    public String getTeaMajor() {
        return teaMajor;
    }

    public void setTeaMajor(String teaMajor) {
        this.teaMajor = teaMajor;
    }

    public String getTeaPhone() {
        return teaPhone;
    }

    public void setTeaPhone(String teaPhone) {
        this.teaPhone = teaPhone;
    }

    public Set<Student> getStudents() {
        return students;
    }

    public void setStudents(Set<Student> students) {
        this.students = students;
    }

    @Override
    public String toString() {
        return "Teacher [teaId=" + teaId + ", teaName=" + teaName + ", teaAge=" + teaAge + ", teaSex=" + teaSex
                + ", teaMajor=" + teaMajor + ", teaPhone=" + teaPhone + ", students=" + students + "]";
    }

}

学生实体类

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

@Entity
@Table(name="per_student") //建立实体类和表的映射关系
public class Student implements Serializable{

    @Id//声明当前私有属性为主键
    @GeneratedValue(strategy=GenerationType.IDENTITY) //配置主键的生成策略
    @Column(name="per_id") //指定和表中per_id字段的映射关系
    private Long perId;

    @Column(name="per_name") //指定和表中per_name字段的映射关系
    private String perName;

    @Column(name="per_age")//指定和表中per_age字段的映射关系
    private int perAge;

    @Column(name="per_sex")//指定和表中per_sex字段的映射关系
    private String perSex;

    @Column(name="per_major")//指定和表中per_major字段的映射关系
    private String perMajor;

    @Column(name="per_phone")//指定和表中per_phone字段的映射关系
    private String perPhone;

    //多对一关系映射:多个学生对应老师
    @ManyToOne(targetEntity=Teacher.class)
    @JoinColumn(name="per_tea_id",referencedColumnName="tea_id")
    private Teacher teacher;

    public Long getPerId() {
        return perId;
    }

    public void setPerId(Long perId) {
        this.perId = perId;
    }

    public String getPerName() {
        return perName;
    }

    public void setPerName(String perName) {
        this.perName = perName;
    }

    public int getPerAge() {
        return perAge;
    }

    public void setPerAge(int perAge) {
        this.perAge = perAge;
    }

    public String getPerSex() {
        return perSex;
    }

    public void setPerSex(String perSex) {
        this.perSex = perSex;
    }

    public String getPerMajor() {
        return perMajor;
    }

    public void setPerMajor(String perMajor) {
        this.perMajor = perMajor;
    }

    public String getPerPhone() {
        return perPhone;
    }

    public void setPerPhone(String perPhone) {
        this.perPhone = perPhone;
    }

    public Teacher getTeacher() {
        return teacher;
    }

    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }

    @Override
    public String toString() {
        return "Student [perId=" + perId + ", perName=" + perName + ", perAge=" + perAge + ", perSex=" + perSex
                + ", perMajor=" + perMajor + ", perPhone=" + perPhone + ", teacher=" + teacher + "]";
    }

}

添加

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;

import com.dzkj.dao.StudentDao;
import com.dzkj.dao.TeacherDao;
import com.dzkj.domain.Student;
import com.dzkj.domain.Teacher;

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

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class OneToManyTest {
    @Autowired
    private TeacherDao teacherDao;

    @Autowired
    private StudentDao studentDao;

    @Test
    @Transactional  //开启事务
    @Rollback(false)//设置为不回滚
    public void testAdd() {
        Teacher t = new Teacher();
        t.setTeaName("王老师");
        t.setTeaAge(23);
        t.setTeaSex("男");
        t.setTeaMajor("java开发");
        t.setTeaPhone("17856520899");

        Student s = new Student();
        s.setPerName("张三");
        s.setPerAge(18);
        s.setPerSex("男");
        s.setPerMajor("java开发攻城狮");
        s.setPerPhone("17856520896");

        t.getStudents().add(s);
        s.setTeacher(t);
        teacherDao.save(t);
        studentDao.save(s);

    }

删除

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

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

@Autowired
private CustomerDao customerDao;

@Test
@Transactional
@Rollback(false)//设置为不回滚
public void testDelete() {
    customerDao.delete(1l);
}

级联操作

    /**
     * cascade:配置级联操作
     *         CascadeType.MERGE    级联更新
     *         CascadeType.PERSIST    级联保存:
     *         CascadeType.REFRESH 级联刷新:
     *         CascadeType.REMOVE    级联删除:
     *         CascadeType.ALL        包含所有
     */
    @OneToMany(mappedBy="Teacher",cascade=CascadeType.ALL)

多对多

实体类关系配置

用户实体类

/**
 * 用户的数据模型
 */
@Entity
@Table(name="sys_user")
public class SysUser implements Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="user_id")
    private Long userId;
    @Column(name="user_code")
    private String userCode;
    @Column(name="user_name")
    private String userName;
    @Column(name="user_password")
    private String userPassword;
    @Column(name="user_state")
    private String userState;

    //多对多关系映射
    @ManyToMany(mappedBy="users")
    private Set<SysRole> roles = new HashSet<SysRole>(0);

    public Long getUserId() {
        return userId;
    }
    public void setUserId(Long userId) {
        this.userId = userId;
    }
    public String getUserCode() {
        return userCode;
    }
    public void setUserCode(String userCode) {
        this.userCode = userCode;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public String getUserPassword() {
        return userPassword;
    }
    public void setUserPassword(String userPassword) {
        this.userPassword = userPassword;
    }
    public String getUserState() {
        return userState;
    }
    public void setUserState(String userState) {
        this.userState = userState;
    }
    public Set<SysRole> getRoles() {
        return roles;
    }
    public void setRoles(Set<SysRole> roles) {
        this.roles = roles;
    }
    @Override
    public String toString() {
        return "SysUser [userId=" + userId + ", userCode=" + userCode + ", userName=" + userName + ", userPassword="
                + userPassword + ", userState=" + userState + "]";
    }
}

角色实体类

/**
 * 角色的数据模型
 */
@Entity
@Table(name="sys_role")
public class SysRole implements Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="role_id")
    private Long roleId;
    @Column(name="role_name")
    private String roleName;
    @Column(name="role_memo")
    private String roleMemo;

    //多对多关系映射
    @ManyToMany
    @JoinTable(name="user_role_rel",//中间表的名称
              //中间表user_role_rel字段关联sys_role表的主键字段role_id
              joinColumns={@JoinColumn(name="role_id",referencedColumnName="role_id")},
              //中间表user_role_rel的字段关联sys_user表的主键user_id
              inverseJoinColumns={@JoinColumn(name="user_id",referencedColumnName="user_id")}
    )
    private Set<SysUser> users = new HashSet<SysUser>(0);


    public Long getRoleId() {
        return roleId;
    }
    public void setRoleId(Long roleId) {
        this.roleId = roleId;
    }
    public String getRoleName() {
        return roleName;
    }
    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }
    public String getRoleMemo() {
        return roleMemo;
    }
    public void setRoleMemo(String roleMemo) {
        this.roleMemo = roleMemo;
    }
    public Set<SysUser> getUsers() {
        return users;
    }
    public void setUsers(Set<SysUser> users) {
        this.users = users;
    }
    @Override
    public String toString() {
        return "SysRole [roleId=" + roleId + ", roleName=" + roleName + ", roleMemo=" + roleMemo + "]";
    }
}

添加

@Autowired
    private UserDao userDao;

    @Autowired
    private RoleDao roleDao;
    /**
     * 需求:
     *     保存用户和角色
     * 要求:
     *     创建2个用户和3个角色
     *     让1号用户具有1号和2号角色(双向的)
     *     让2号用户具有2号和3号角色(双向的)
     *  保存用户和角色
     * 问题:
     *  在保存时,会出现主键重复的错误,因为都是要往中间表中保存数据造成的。
     * 解决办法:
     *     让任意一方放弃维护关联关系的权利
     */
    @Test
    @Transactional  //开启事务
    @Rollback(false)//设置为不回滚
    public void test1(){
        //创建对象
        SysUser u1 = new SysUser();
        u1.setUserName("用户1");
        SysRole r1 = new SysRole();
        r1.setRoleName("角色1");
        //建立关联关系
        u1.getRoles().add(r1);
        r1.getUsers().add(u1);
        //保存
        roleDao.save(r1);
        userDao.save(u1);
    }

删除

@Autowired
    private UserDao userDao;
    /**
     * 删除操作
     *     在多对多的删除时,双向级联删除根本不能配置
     * 禁用
     *    如果配了的话,如果数据之间有相互引用关系,可能会清空所有数据
     */
    @Test
    @Transactional
    @Rollback(false)//设置为不回滚
    public void testDelete() {
        userDao.delete(1l);
    }

对象导航查询

对象图导航检索方式是根据已经加载的对象,导航到他的关联对象。它利用类与类之间的关系来检索对象。例如:我们通过ID查询方式查出一个老师,可以调用Teacher类中的getLinkMans()方法来获取该客户的所有联系人。对象导航查询的使用要求是:两个对象之间必须存在关联关系。

查询一个老师,获取该老师的所有学生

@Autowired
    private CustomerDao customerDao;

    @Test
    //由于是在java代码中测试,为了解决no session问题,将操作配置到同一个事务中
    @Transactional 
    public void testFind() {
        Teacher teacher = teacherDao.findOne(5l);
        Set<Student> Students = teacher.getStudents();//对象导航查询
        for(Student student : Students) {
              System.out.println(student);
        }
    }

查询一个学生,获取该学生的所有老师

@Autowired
    private StudentDao studentDao;


    @Test
    public void testFind() {
        Student Student = studentDao.findOne(4l);
        Teacher teacher = Student.getTeacher(); //对象导航查询
        System.out.println(teacher);
    }

查询学生时,肯定会看看该学生的专业老师。如果我们不查的话,在用的时候还要自己写代码,调用方法去查询。如果我们查出来的话,一个对象不会消耗太多的内存。而且多数情况下我们都是要使用的
** 解决: 采用立即加载的思想。通过配置的方式来设定,只要查询从表实体,就把主表实体对象同时查出来 **

/**
     * 在联系人对象的@ManyToOne注解中添加fetch属性
     *         FetchType.EAGER    :立即加载
     *         FetchType.LAZY    :延迟加载
     */
    @ManyToOne(targetEntity=Teacher.class,fetch=FetchType.EAGER)
    @JoinColumn(name="per_tea_id",referencedColumnName="tea_id")
    private Teacher teacher;

文章作者: Hanair
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Hanair !
 上一篇
mysql启动失败 mysql启动失败
mysql启动失败:mysql服务无法启动 mysql5.7安装 mysql发生系统错误2 解决方法:切换到bin目录后,首先删除前面安装的MySQL服务,然后在重新安装MySQL服务,然后启动。 document.que
2020-04-08 Hanair
下一篇 
redis学习记录 redis学习记录
redis简介Redis:开源、免费、高性能、K-V数据库、内存数据库、非关系型数据库,支持持久化、集群和事务 Centos7 安装redis Redis 连接时报错:Could not connect to Redis at 127.0
2020-03-21 Hanair
  目录