美文网首页Spring Data JPA
JPA(二)Spring Data JPA

JPA(二)Spring Data JPA

作者: guideEmotion | 来源:发表于2019-06-26 23:22 被阅读0次

    一 概述

    Spring Data JPA 是 Spring 基于 ORM 框架、JPA 规范的基础上封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据库的访问和操作。它提供了包括增删改查等在内的常用功能,且易于扩展!学习并使用 Spring Data JPA 可以极大提高开发效率!

    推荐组合

    Spring Data JPA 让我们解脱了DAO层的操作,基本上所有CRUD都可以依赖于它来实现,在实际的工作工程中,推荐使用Spring Data JPA + ORM(如:hibernate)完成操作,这样在切换不同的ORM框架时提供了极大的方便,同时也使数据库层操作更加简单,方便解耦

    特性

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

    和其他框架的关系

    Spring Data JPA 与 JPA和hibernate之间的关系
    JPA是一套规范,内部是有接口和抽象类组成的。hibernate是一套成熟的ORM框架,而且Hibernate实现了JPA规范,所以也可以称hibernate为JPA的一种实现方式,我们使用JPA的API编程,意味着站在更高的角度上看待问题(面向接口编程)

    Spring Data JPA是Spring提供的一套对JPA操作更加高级的封装,是在JPA规范下的专门用来进行数据持久化的解决方案。


    注意
    真正干活的还是hibernate

    二 搭建环境

    依赖

    <?xml version="1.0" encoding="UTF-8"?>
    <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>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.1.6.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.zyc</groupId>
        <artifactId>springDateJpa</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>springDateJpa</name>
        <description>Demo project for Spring Boot</description>
    
        <properties>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-jpa</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    
    

    dao

    使用Spring Data JPA,只需要按照框架的规范提供dao接口,不需要实现类就可以完成数据库的增删改查、分页查询等方法的定义,极大的简化了我们的开发过程。
    规范

    1. 创建一个Dao层接口,并实现JpaRepositoryJpaSpecificationExecutor
    2. 提供相应的泛型
    package com.zyc.springDateJpa.dao;
    
    import com.zyc.springDateJpa.entity.Customer;
    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 java.util.List;
    
    /**
     * 符合SpringDataJpa的dao层接口规范
     *      JpaRepository<操作的实体类类型,实体类中主键属性的类型>
     *          * 封装了基本CRUD操作
     *      JpaSpecificationExecutor<操作的实体类类型>
     *          * 封装了复杂查询(分页)
     */
    public interface CustomerDao extends JpaRepository<Customer,Long> ,JpaSpecificationExecutor<Customer> {
    
    
        public Customer findByCustName(String custName);
    
    }
    
    

    测试

    package com.zyc.springDateJpa;
    
    import com.zyc.springDateJpa.dao.CustomerDao;
    import com.zyc.springDateJpa.entity.Customer;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.SpringRunner;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class SpringDateJpaApplicationTests {
    
        @Autowired
        private CustomerDao customerDao;
    
    
        @Test
        public void contextLoads() {
            Customer c = new Customer();
            c.setCustName("zhuyc");
            customerDao.save(c);
    
    
        }
    
    }
    
    

    三 CRUD

    查询

            Optional<Customer> c = customerDao.findById(1l);
            System.out.println(c.get());
    

    保存/更新

    svae:保存或者更新

    • 根据传递的对象是否存在主键id,如果没有id主键属性:保存
    • 存在id主键属性,根据id查询数据,更新数据.如果没查到,还是更新
                    Customer c = new Customer();
            c.setCustName("zhuyc");
            customerDao.save(c);
    

    删除

    根据id删除

    springDataJpa会先查询,再删除;没查到,会报错

    customerDao.deleteById(2l);
    

    查询所有

    List<Customer> list = customerDao.findAll();
            for(Customer customer : list) {
                System.out.println(customer);
            }
    

    四 执行过程

    在SpringDataJpa中我们只需要声明接口,框架会自动帮我们通过jdk动态代理生成接口实现类,然后注入导spring中。
    动态代理对象中一般都是默认调用SimpleJpaRepository中的方法来工作的

    image.png

    五 复杂查询

    查询总数

    long count = customerDao.count();
    

    查询id是否存在

    boolean exists = customerDao.existsById(4l);
    

    getOne

    • findById:
      em.find() :立即加载
    • getOne:
      em.getReference :延迟加载;返回的是一个客户的动态代理对象. 什么时候用,什么时候查询
    Customer customer = customerDao.getOne(4l);
    

    JPQL

    @Query注解的使用非常简单,只需在方法上面标注该注解,同时提供一个JPQL查询语句即可

        @Query(value="from Customer where custName = ?1")
        public Customer findJpql(String custName);
    

    占位符

    通过索引

        /**
         * 案例:根据客户名称和客户id查询客户
         *      jpql: from Customer where custName = ? and custId = ?
         *
         *  对于多个占位符参数
         *      赋值的时候,默认的情况下,占位符的位置需要和方法参数中的位置保持一致
         *
         *  可以指定占位符参数的位置
         *      ? 索引的方式,指定此占位的取值来源
         */
        @Query(value = "from Customer where custName = ?2 and custId = ?1")
        public Customer findCustNameAndId(Long id, String name);
    

    实现更新

    @Query : 代表的是进行查询
    @Modifying:当前执行的是一个更新操作.有点组合的感觉,补充@Query

        /**
         *
         *  sql  :update cst_customer set cust_name = ? where cust_id = ?
         *  jpql : update Customer set custName = ? where custId = ?
         */
        @Query(value = " update Customer set custName = ?2 where custId = ?1 ")
        @Modifying
        public void updateCustomer(long custId, String custName);
    

    @Rollback
    设置是否自动回滚,本地测试:默认不回滚。

        @Test
        @Transactional //添加事务的支持
        @Rollback(value = true)
        public void testUpdateCustomer() {
            customerDao.updateCustomer(4l,"黑马程序员");
        }
    

    sql查询

    @Query有一个nativeQuery属.

        /**
         *  sql : select * from cst_customer;
         *  Query : 配置sql查询
         *      value : sql语句
         *      nativeQuery : 查询方式
         *          true : sql查询
         *          false:jpql查询(默认)
         *
         */
        //@Query(value = " select * from cst_customer" ,nativeQuery = true)
        @Query(value="select * from cst_customer where cust_name like ?1",nativeQuery = true)
        public List<Object [] > findSql(String name);
    
    

    查询Map

    有时会用到

        @Test
        public void testNativeQuery(){
            Query query = em.createNativeQuery("select * from cst_customer ");
            List<Map<String,Object>> list = query.unwrap(NativeQuery.class).addScalar("cust_id", StandardBasicTypes.LONG).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();
            for(Map<String,Object> map:list){
                System.out.println(map.values());
            }
    
        }
    

    方法命名规则查询

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

        /**
         * 方法名的约定:
         *      findBy : 查询
         *            对象中的属性名(首字母大写) : 查询的条件
         *            CustName
         *            * 默认情况 : 使用 等于的方式查询
         *                  特殊的查询方式
         *
         *  findByCustName   --   根据客户名称查询
         *
         *  再springdataJpa的运行阶段
         *          会根据方法名称进行解析  findBy    from  xxx(实体类)
         *                                      属性名称      where  custName =
         *
         *      1.findBy  + 属性名称 (根据属性名称进行完成匹配的查询=)
         *      2.findBy  + 属性名称 + “查询方式(Like | isnull)”
         *          findByCustNameLike
         *      3.多条件查询
         *          findBy + 属性名 + “查询方式”   + “多条件的连接符(and|or)”  + 属性名 + “查询方式”
         */
        public Customer findByCustName(String custName);
    
        public Customer findByCustNameLikeAndCustIndustry(String custName, String custIndustry);
    

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

    image.png
    image.png

    参考

    1. 黑马Spring Data Jpa教学资料

    相关文章

      网友评论

        本文标题:JPA(二)Spring Data JPA

        本文链接:https://www.haomeiwen.com/subject/tsdfcctx.html