SpringDATAJPA框架与原理-sql、jpql、方法名称规则查询、Specification动态查询、多表查询

在这里插入图片描述
SpringDATAJPA封装JPA操作

依赖

spring-data-jpa
Hibernate相关依赖
c3p0依赖
mysql驱动

<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>
        <!--单元测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.9</version>
        </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-->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>${hibernate.version}</version>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>${hibernate.version}</version>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.2.1.Final</version>
        </dependency>
        <!--hibernate end-->

        <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>
        <!--真正用到SpringDATAJPA的的包-->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
            <version>1.9.0.RELEASE</version>
        </dependency>

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

        <!--el 使用SpringDATAJPA必须引入-->
        <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配置文件

applicationContext.xml
约束头

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:jdbc="http://www.springframework.org/schema/jdbc"
       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/context http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
        http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd"
>
</beans>

spring和SpringDATAJPA的配置

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:jdbc="http://www.springframework.org/schema/jdbc"
       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/context http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
        http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd"
>
    <!--LocalContainerEntityManagerFactoryBean是spring提供的entityManagerFactoty实现类-->
    <bean id="entityManagerFactoty" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <!--连接池-->
        <property name="dataSource" ref="dataSource"/>
        <!--实体类的包 自动去扫描包下所有类-->
        <property name="packagesToScan" value="cn.vivi.domain"/>
        <property name="persistenceProvider" >
            <!--jpa实现的提供-->
            <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"/>
                <!--显示sql-->
                <property name="showSql" value="true"/>
                <!--数据库方言:支持的特有语法-->
                <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"/>
            </bean>
        </property>
        <!--jpa方言:高级特性-->
        <property name="jpaDialect" >
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
        </property>
    </bean>
    <!--数据库连接池-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="root"/>
        <property name="password" value="root"/>
        <property name="jdbcUrl" value="jdbc:mysql:///jpa?characterEncoding=utf8"/>
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
    </bean>

    <!--整合SpringDATAJPA-->
    <jpa:repositories base-package="cn.vivi.dao" transaction-manager-ref="transactionManager" entity-manager-factory-ref="entityManagerFactoty"/>
    <!--事务管理器-->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactoty"/>
    </bean>

    <!--声明式事务-->

    <!--扫描注解-->
    <context:component-scan base-package="cn.vivi"/>

</beans>

编写实体类
在这里插入图片描述
编写dao层几口,不需要编写dao层捷库的实现类。

规范

1.继承两个接口 JpaRepository,JpaSpecificationExecutor.
2 提供相应的泛型
JpaRepository<操作的实体类型,主键属性的类型>
JpaSpecificationExecutor<操作的实体类型>
在这里插入图片描述
此时dao已经封装了基本的crud操作
测试查询:
在这里插入图片描述

基本方法

findOne(),根据主键查询一个
save()保存或更新,根据传递的对象是否有id主键,如果有id代表更新,否则为保存
delete()根据主键删除
findAll()查询全部
查询全部:count();
是否存在:boolean exists(id):


原理分析
dao接口继承JpaRepository,JpaSpecificationExecutor。
动态代理基于接口生成实现类对象。
Spring借助JdkDynamicAopProxy对象创建实体类
在这里插入图片描述
实现InvocationHandler接口的invoke方法,生成SimpleJpaRepository对象,即dao的实现类。

完整逻辑

在这里插入图片描述
1 通过Spring借助JdkDynamicAopProxy对象动态代理创建实体类SimpleJpaRepository对象
2 SimpleJpaRepository实现JpaRepository,JpaSpecificationExecutor接口,实现了调用jpa接口
3 jpa指示hibernate完成增删改查,hibernate底层封装了jdbc。

getOne与findOne区别

findOne():底层调用entityManager.find(); 立即加载
getOne():底层调用entityManager.getReference(Class,id);延迟加载
getOne返回的是一个动态代理对象,使用的时候才加载。


JPQL查询

需要将jpql语句配置到接口方法上
1.特有的查询:需要在dao接口上配置方法
2.在新添加的方法上,使用注解的形式配置jpql查询语句
3.注解:@query
在这里插入图片描述
之后就可以直接调用
多占位符与参数顺序有关,与形参名无关。
在这里插入图片描述
占位符后加数字可以指定形参取的位置。

更新操作需要加入@Modifying注解,query不支持DML操作。且返回值类型void or int/Integer

在这里插入图片描述
调用的时候需要加入事务以及rollback回滚false,默认为true

在这里插入图片描述


SQL查询

注解:@query,属性nativequery默认为false,改为true即为sql语句查询。
在这里插入图片描述
sql查询的返回值为List<Object []> 查询到之后遍历也需要对数组进行Arrays.toString
在这里插入图片描述


方法名称规则查询 类似于通用mapper,区别是需要提前在dao接口声明。

对jpql查询更加深入的封装,
只需要按照SpringDATAJPA提供的方法名称规则定义的方法,不需要再去写jpql;
方法名的约定:
findBy:查询
对象中的属性名,查询的条件。
findByCustName(),根据客户名查询


在这里插入图片描述


Specification动态查询

动态构建相应的查询语句
方法列表:

  • T findOne(Specification spec); //查询单个
  • List findAll(Specification spec); //查询多个结果
  • Page findAll(Specification spec,Pageable pageable);//分页查询,加入分页参数
  • List findAll(Specification spec,Sort sort);//排序查询,加入排序参数
  • long count(Specification spec);//统计数量查询

Specification:代表查询条件
自定义Specification实现类,实现:toPredicate,封装查询条件
在这里插入图片描述
root:查询的根对象,查询的任何属性都可以从根对象中获取
CriteriaQuery:顶层查询对象,自定义查询方式(一般不用)
CriteriaBuilder:查询构造器,封装了很多查询条件(模糊查询,精准匹配等)
查询条件:
1.查询方式
cb对象
2.比较的属性名称
root对象
在这里插入图片描述
多条件查询
在这里插入图片描述
所有的条件构建都使用cb。
常见cb里面的方法:
gt,lt,ge,le,like等方法 需要得到path对象后,指定比较的参数类型,再去比较
as.class。
多结果就用findAll
在这里插入图片描述

排序查询,

  • List findAll(Specification spec,Sort sort);//排序查询,加入排序参数
    需要new一个sort
    构造方法中:
    参数1,正序还是倒序(枚举类型Sort.Direction.)。
    参数2,排序的属性。实体类中的属性名称。
    在这里插入图片描述

分页查询

  • Page findAll(Specification spec,Pageable pageable);//分页查询,加入分页参数
    返回一个Page对象,里面有封装好的总页数和总条数以及数据列表map。
    在这里插入图片描述
    pageable是一个接口,实现类PageRequest构造传入两个参数,页码与每页条数。页码从0开始

即分页又排序的查询

//实现可以多种查询方式结合:模糊搜索,排序,分页
    @Test
    public void testFindCustomerWithSort2() {
        Page<Customer> page = customerDao.findAll(new Specification<Customer>() {
            @Override
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Predicate predicate1 = criteriaBuilder.like(root.get("custName"), "%未来%");
                Predicate predicate = criteriaQuery.where(predicate1).orderBy(criteriaBuilder.asc(root.get("custId"))).getRestriction();
                return predicate;
            }
        }, new PageRequest(0, 10));
        System.out.println(page.getTotalElements());
        System.out.println(page.getTotalPages());
        List<Customer> list = page.getContent();
        for (Customer customer : list) {
            System.out.println(customer);
        }
    }

多表操作

表关系

  • 一对一:
  • 一对多:
    - 一的一方:主表
    - 多的一方:从表
    - 外键:需要再从表上新建一列作为外键,他的取值来源于主表的主键
  • 多对多:
    - 中间表:最少两个字段组成,分别是外键指向两个表的主键,有组成了联合主键

实体类的关系

  • 包含关系:可以通过实体类中的包含关系来描述表关系
分析步骤
1.明确表关系
2.确定表关系(描述 外键|中间表)
3.编写实体类,在实体类中描述表关系(包含关系)
4.配置映射关系
一对多

客户与联系人

  • 一个客户可以具有多个联系人
  • 一个联系人属于一家客户公司
    表关系:
  • 主表:客户表
  • 从表:联系人表,再从表上添加外键
    实体类:
    客户:实体类中应该包含一个联系人的聚合
    联系人:实体类包含一个客户对象
    映射关系:
    使用jpa注解配置一对多的映射
主表实体类
  • @OneToMany 配置实体类参数targetEntity对方的实体类
  • @JoinColumn 配置外键,参数name表示从表的外键名,referencedColumnName表示主表对应的键,配置多的一方的也要配置@JoinColumn
    在这里插入图片描述
从表实体类
  • @ManyToOne 配置实体类参数targetEntity对方的实体类
  • @JoinColumn 配置外键,参数name表示从表的外键名,referencedColumnName表示主表对应的键,
    在这里插入图片描述
数据库保存

双向均可维护,推荐从多对一的发送,如果同时发送的话,会多发一条update。
在这里插入图片描述

一的一方放弃外键维护,

主表(一的一方)
@OneToMany(mappedBy = “customer”) 参数为对方配置外键用的的属性名称
在这里插入图片描述
主表放弃外键维护后,不能随便删除主表数据,因为他不会去修改从表中的外键字段了,想删除使用级联删除引用。
如果没有外键维护。默认情况下删除后从表的外键会变为null。前提是外键可以为null。

级联操作

级联:操作一个对象同时操作他的关联对象

  • 级联添加,eg:当我保存一个客户的同时保存联系人
  • 级联删除,eg:当我删除一个客户的同时删除此客户的所有联系人
级联操作的步骤
  1. 区分操作主体
  2. 需要在操作主体的实体类上,添加级联属性(需要添加到映射关系的注解上)
  3. cascade(配置级联)
    在这里插入图片描述
    级联添加:
    在这里插入图片描述
    级联删除
    在这里插入图片描述

多对多操作

案例:
用户和角色

  • 用户:一个用户可以是多个角色
  • 角色:一个角色可以分配给多个用户
    分析步骤
  1. 确定表关系
    中间表
  2. 编写实体类
    用户:包含角色的集合
    角色:包含用户的集合
  3. 配置映射关系

@ManyToMany注解配置在set集合上,参数targetEntity表示对方的实体类,设置级联cascade
@JoinTablez注解表示中间表的配置:

  • 参数name:表示中间表名字
  • 参数joinColumns表示配置当前对象在中间表的外键
    JoinColumn中name表示外键名,referencedColumnName表示参照主表中的主键名
  • 参数inverseJoinColumns表示对方对象再中间表的外键
    JoinColumn与joinColumns中的的正好相反

实体类user
在这里插入图片描述
实体类role
在这里插入图片描述

多对多添加:
在这里插入图片描述

放弃外键维护

多对多通常是被动选择的一方放弃维护权利
@ManyToMany(mapped=“”)参数为对方外键的属性名称
role实体类:
在这里插入图片描述

多对多级联与一对多一样


多表的查询

  1. 对象导航查询
    查询一个对象的同时,通过此对象查询他的关联对象。
    在这里插入图片描述默认使用的延迟加载来查询,调用get方法不会立即发送查询。
    如果不想用延迟加载修改配置。fetch,需要配置到多表映射关系的注解上
    在这里插入图片描述
    FetchType.EAGER立即加载。不推荐立即加载,因为第二次加载的时候用的左连接,两个表一起加载,而第一个表已经查询过一次了。所以性能变慢。
    而从多的一方查一的一方,默认会在第一次就使用了左连接查了两个表。
    总结:
    从一方查多方默认使用延迟加载
    从多方查一方默认使用立即加载
    所以fetch一般不用改

可能的问题

1.no session错误。
解决方案 加上@Transactional注解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值