JPA第二章

JPA第二章

一、SpringDataJpa入门

1、需求

​ 使用SpringDataJpa实现数据库的CRUD

2、创建数据库

​ 还是使用Customer表实现数据增删改查

3、开发步骤

​ 1)创建一个maven工程
​ 2)添加jar包
​ mysql的数据库驱动
​ 数据库连接池。
​ Hibernate的jar包
​ SpringDataJpa
​ Spring相关的jar包

  • <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <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>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- spring end -->
        <!-- hibernate beg -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.2.1.Final</version>
        </dependency>
        <!-- hibernate end -->
        <!-- c3p0 beg -->
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>${c3p0.version}</version>
        </dependency>
        <!-- c3p0 end -->
        <!-- log end -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>${slf4j.version}</version>
        </dependency>
        <!-- log end -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
            <version>2.0.7.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>
    

​ 3)创建配置文件,spring和SpringDataJpa整合的配置文件
​ applicationContext.xml
​ 配置框架整合:
​ 员(数据源)工(工厂类对象)是(事务)爹(Dao包扫描器)
​ 数据源:数据库连接池
​ 工厂类对象:EntityManagerFactory对象,spring包装之后的。
​ 事务:事务管理器、可以使用切面。
​ dao包扫描器:扫描dao接口

  • <?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_sgw?characterEncoding=utf8"/>
            <property name="user" value="root"/>
            <property name="password" value="root"/>
        </bean>
        <!--2.工厂类对象-->
        <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
            <!--配置数据源-->
            <property name="dataSource" ref="dataSource"/>
            <!--实体类的包扫描器-->
            <property name="packagesToScan" value="cn.sgwks.jpa.entity"/>
            <!--配置供应商适配器-->
            <property name="jpaVendorAdapter">
                <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                    <!--是否向控制台输出sql语句-->
                    <property name="showSql" value="true"/>
                    <!--是否自动创建表
                       如果是true:相当于update,hibernate.hbm2ddl.auto属性配置成update
                       如果是false:相当于none
                   -->
                    <property name="generateDdl" value="true"/>
                    <!--使用的数据库类型-->
                    <property name="database" value="MYSQL"/>
                </bean>
            </property>
        </bean>
        <!--3配置事务-->
        <!-- 3.1 JPA事务管理器  -->
        <bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
            <property name="entityManagerFactory" ref="entityManagerFactory"/>
        </bean>
        <!-- 3.2.txAdvice-->
        <tx:advice id="txAdvice" transaction-manager="txManager">
            <tx:attributes>
                <tx:method name="get*" read-only="true"/>
                <tx:method name="find*" read-only="true"/>
                <tx:method name="query*" read-only="true"/>
                <tx:method name="*" propagation="REQUIRED"/>
            </tx:attributes>
        </tx:advice>
        <!-- 3.3.aop-->
        <aop:config>
            <!--        <aop:pointcut id="pointcut" expression="execution(* cn.sgwks.jpa.service.*.*(..))"/>-->
            <!-- pointcut-ref="pointcut" -->
            <aop:advisor advice-ref="txAdvice" pointcut="execution(* cn.sgwks.jpa.service.*.*(..))"/>
        </aop:config>
        <!--4.dao的包扫描器-->
        <jpa:repositories base-package="cn.sgwks.jpa.dao"
                          transaction-manager-ref="txManager"
                          entity-manager-factory-ref="entityManagerFactory"/>
    </beans>
    

​ 4)创建实体类

  • package cn.sgwks.jpa.entity;
      import javax.persistence.*;
      //代表是一个jpa的实体类
      @Entity
      //配置实体类和数据库中表的映射关系 name对应的表名
      @Table(name = "cst_customer")
      public class Customer {
          //配置主键的生成策略
          /**
           * 1: @GeneratedValue(strategy = GenerationType.IDENTITY)====>自增长
           * 2: @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "cust_seq")====>使用序列生成主键
           *      @SequenceGenerator(name = "cust_seq", sequenceName = "cust_sequence")
           * 3: @GeneratedValue(strategy = GenerationType.TABLE, generator = "tab_gen")====>使用表生成主键
           *      @TableGenerator(name = "tab_gen", table = "ids_gen", pkColumnName = "ids", valueColumnName = "vals", pkColumnValue = "customer", allocationSize = 1)
           * 4: @GeneratedValue(strategy = GenerationType.AUTO)
           */
          //在主键字段使用@Id标注
          @Id
          //配置属性和字段的映射关系
          @Column(name = "cust_id")
          //GenerationType.IDENTITY是自增长
          @GeneratedValue(strategy = GenerationType.IDENTITY)
          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;}
      }
    

​ 5)创建dao,创建接口即可。要求接口继承JpaRepository接口。

  • package cn.sgwks.jpa.dao;
    import cn.sgwks.jpa.entity.Customer;
    import org.springframework.data.jpa.repository.JpaRepository;
    /**
     * Customer管理的Dao
     * 只需要创建一个接口即可,需要继承JpaRepository接口。
     * 泛型:
     *  dao关联的Entity类
     *  对应表的主键的数据类型
     */
    public interface CustomerDao extends JpaRepository<Customer,Long> {}
    

​ 6)编写测试程序。
​ 应该是使用dao实现增删改查。
​ 1、初始化spring容器
​ 2、从容器中获得Dao的代理对象。
​ 3、使用dao实现增删改查

​ 4、测试方法上:

  • @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext.xml")
    public class JpaFirst {
        @Autowired
        private CustomerDao customerDao;
    }    
    
  • 添加数据:save

    • /**
       * 通过容器获取代理对象
       */
      @Test
      public void addCustomer(){
          ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
          CustomerDao customerDao = context.getBean(CustomerDao.class);
          Customer customer = new Customer();
          customer.setCustName("张帅");
          customer.setCustSource("美女推荐");
          customer.setCustIndustry("吃货");
          customer.setCustLevel("农民");
          customer.setCustAddress("河南省南阳市");
          customer.setCustPhone("16677889900");
          //插入数据
          customerDao.save(customer);
      }
      
    • sql结果:

      Hibernate: insert into cst_customer (cust_address, cust_industry, cust_level, cust_name, cust_phone, cust_source) values (?, ?, ?, ?, ?, ?)
      
  • 删除:delete

    • /**
       * 删除指定数据
       */
      @Test
      public void deleteCustomer() {
          customerDao.delete(9L);
      }
      
    • sql结果:

      Hibernate: select customer0_.cust_id as cust_id1_0_0_, customer0_.cust_address as cust_add2_0_0_, customer0_.cust_industry as cust_ind3_0_0_, customer0_.cust_level as cust_lev4_0_0_, customer0_.cust_name as cust_nam5_0_0_, customer0_.cust_phone as cust_pho6_0_0_, customer0_.cust_source as cust_sou7_0_0_ from cst_customer customer0_ where customer0_.cust_id=?
      Hibernate: delete from cst_customer where cust_id=?
      
  • 修改:save

    • 根据id查询一条数据,返回一个对象

    • 修改对象的属性

    • 把修改结果更新到数据库

    • /**
       * 修改指定数据
       */
      @Test
      public void updateCustomer() {
          //根据id查询一条数据,返回一个对象
          Customer customer = customerDao.findOne(10L);
          //修改对象的属性
          customer.setCustPhone("12345678901");
          customer.setCustSource("jpa学习");
          //把修改结果更新到数据库
          customerDao.save(customer);
      }
      
    • sql结果:

      Hibernate: select customer0_.cust_id as cust_id1_0_0_, customer0_.cust_address as cust_add2_0_0_, customer0_.cust_industry as cust_ind3_0_0_, customer0_.cust_level as cust_lev4_0_0_, customer0_.cust_name as cust_nam5_0_0_, customer0_.cust_phone as cust_pho6_0_0_, customer0_.cust_source as cust_sou7_0_0_ from cst_customer customer0_ where customer0_.cust_id=?
      Hibernate: select customer0_.cust_id as cust_id1_0_0_, customer0_.cust_address as cust_add2_0_0_, customer0_.cust_industry as cust_ind3_0_0_, customer0_.cust_level as cust_lev4_0_0_, customer0_.cust_name as cust_nam5_0_0_, customer0_.cust_phone as cust_pho6_0_0_, customer0_.cust_source as cust_sou7_0_0_ from cst_customer customer0_ where customer0_.cust_id=?
      Hibernate: update cst_customer set cust_address=?, cust_industry=?, cust_level=?, cust_name=?, cust_phone=?, cust_source=? where cust_id=?
      
  • 查询:
    findOne:根据id查询

    • /**
       * 查询指定id数据
       */
      @Test
      public void findById() {
          Customer customer = customerDao.findOne(3L);
          System.out.println(customer);
      }
      
    • Hibernate: select customer0_.cust_id as cust_id1_0_0_, customer0_.cust_address as cust_add2_0_0_, customer0_.cust_industry as cust_ind3_0_0_, customer0_.cust_level as cust_lev4_0_0_, customer0_.cust_name as cust_nam5_0_0_, customer0_.cust_phone as cust_pho6_0_0_, customer0_.cust_source as cust_sou7_0_0_ from cst_customer customer0_ where customer0_.cust_id=?
      

二、SpringDataJpa的原理

​ 底层还是使用jpa的原生api来实现。
​ 实现封装在SimpleJpaRepository类中,由此类提供dao的支持。

  1. 在这里插入图片描述

三、SpringDataJpa中的查询

1、使用dao提供的方法查询

  • 1)根据id查询

    • findOne:根据id查询,即时加载

      @Test
      public void testFindOne() {
          Customer customer = customerDao.findOne(3L);
          System.out.println("================");
          System.out.println(customer);
      }
      --sql结果:
      Hibernate: select customer0_.cust_id as cust_id1_0_0_, customer0_.cust_address as cust_add2_0_0_, customer0_.cust_industry as cust_ind3_0_0_, customer0_.cust_level as cust_lev4_0_0_, customer0_.cust_name as cust_nam5_0_0_, customer0_.cust_phone as cust_pho6_0_0_, customer0_.cust_source as cust_sou7_0_0_ from cst_customer customer0_ where customer0_.cust_id=?
      ================
      Customer{custId=3, custName='sgw', custSource='电话营销', custIndustry='程序员', custLevel='码农', custAddress='AB市', custPhone='12345678901'}
      
    • getOne:根据id查询,懒加载,底层调用的就是getReference方法实现查询。

      @Test
      /*这里开启事务,保证会话在方法结束前不会销毁,否则会报:org.hibernate.LazyInitializationException: could not initialize proxy - no Session 异常
      */
      @Transactional
      public void testGetOne() {
          Customer customer = customerDao.getOne(3l);
          System.out.println("================");
          System.out.println(customer);
      }
      --sql结果:
      ================
      Hibernate: select customer0_.cust_id as cust_id1_0_0_, customer0_.cust_address as cust_add2_0_0_, customer0_.cust_industry as cust_ind3_0_0_, customer0_.cust_level as cust_lev4_0_0_, customer0_.cust_name as cust_nam5_0_0_, customer0_.cust_phone as cust_pho6_0_0_, customer0_.cust_source as cust_sou7_0_0_ from cst_customer customer0_ where customer0_.cust_id=?
      Customer{custId=3, custName='石国旺', custSource='电话营销', custIndustry='程序员', custLevel='码农', custAddress='贵州省安顺市', custPhone='18208533574'}
      
  • 2)查询全部数据

    • 1、可以使用findAll方法查询。

      @Test
      public void testFindAll() {
          List<Customer> customerList = customerDao.findAll();
          for (Customer customer : customerList) {
              System.out.println(customer);
          }
      }
      --sql结果:
      Hibernate: select customer0_.cust_id as cust_id1_0_, customer0_.cust_address as cust_add2_0_, customer0_.cust_industry as cust_ind3_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_
      
    • 2、查询全部数据带分页:

      @Test
      public void testFindAllWithPage() {
          //参数1:页面从0开始
          //参数2:每页的行数
          //在Pageable对象中设置分页信息
          /*
          	需要使用PageRquest类创建对象
      			page:页码,从0开始
      			size:每页的行数
          */
          Pageable pageable = new PageRequest(1, 5);
          //需要使用带参数的findAll(Pageable pageable)
          Page<Customer> page = customerDao.findAll(pageable);
          /*
          	返回一个Page对象:
      			totalElements:总记录数
      			totalPages:总页数	
      			content:结果列表
          */
          System.out.println("总记录数:" + page.getTotalElements());
          System.out.println("总页数:" + page.getTotalPages());
          List<Customer> list = page.getContent();
          for (Customer customer : list) {
              System.out.println(customer);
          }
      }
      --sql结果:
      Hibernate: select count(customer0_.cust_id) as col_0_0_ from cst_customer customer0_
      Hibernate: select customer0_.cust_id as cust_id1_0_, customer0_.cust_address as cust_add2_0_, customer0_.cust_industry as cust_ind3_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_ limit ?, ?
      总记录数:7
      总页数:2
      
    • 3、查询全部带排序处理
      findAll(Sort)

      @Test
      public void testFindAllWithSort() {
          //创建一个sort对象
          //参数1:排序方式
          //参数2:排序的字段,应该是实体类的属性名
          Sort sort = new Sort(Sort.Direction.DESC, "custId");
          List<Customer> list = customerDao.findAll(sort);
          for (Customer customer : list) {
              System.out.println(customer);
          }
      }
      --sql结果:
      Hibernate: select customer0_.cust_id as cust_id1_0_, customer0_.cust_address as cust_add2_0_, customer0_.cust_industry as cust_ind3_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_ order by customer0_.cust_id desc
      
  • 3)其他查询方法

    • count:统计

      @Test
      public void testcount() {
          long count = customerDao.count();
          System.out.println(count);
      }
      --sql结果:
      Hibernate: select count(*) as col_0_0_ from cst_customer customer0_
      7
      
    • exists:判断记录是否存在。

      @Test
      public void testExists() {
          boolean exists = customerDao.exists(1l);
          System.out.println(exists);
      }
      --sql结果:
      Hibernate: select count(*) as col_0_0_ from cst_customer customer0_ where customer0_.cust_id=? and 1=1
      true
      

2、使用jpql查询

​ 使用方法:
​ 1)在dao接口中定义一个方法。使用方法的参数设置jpql的参数,使用方法的返回值接收查询结果。
​ 2)在方法上添加一个@Query注解。

​ 3)在注解中编写jpql。
​ 4)测试

  • 使用jpql查询全部数据。

    • jpql: from Customer

      //接口
      @Query("from Customer")
      List<Customer> getAllCustomer();
      //测试方法
      @Test
      public void getAllCustomer(){
          List<Customer> customerList = customerDao.getAllCustomer();
          for (Customer customer : customerList) {
              System.out.println(customer);
          }
      }
      --sql结果:
      Hibernate: select customer0_.cust_id as cust_id1_0_, customer0_.cust_address as cust_add2_0_, customer0_.cust_industry as cust_ind3_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_
      
    • 查询分页:在查询方法中添加一个参数Pageable,可以实现分页

      //接口
      @Query("from Customer")
      List<Customer> getAllCustomerByPage(Pageable pageable);
      //测试方法
      @Test
      public void getAllCustomerByPage(){
          PageRequest pageRequest = new PageRequest(0, 3);
          List<Customer> customerList = customerDao.getAllCustomerByPage(pageRequest);
          for (Customer customer : customerList) {
              System.out.println(customer);
          }
      }
      --sql结果:
      Hibernate: select customer0_.cust_id as cust_id1_0_, customer0_.cust_address as cust_add2_0_, customer0_.cust_industry as cust_ind3_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_ limit ?
      
    • 根据客户名称和地址查询:

      sqlSELECT * FROM `cst_customer` WHERE cust_name LIKE '%会%' and 			cust_address LIKE '%界%'
      jpql:from Customer where custName like ? and custAddress like ?
      
      //接口
      //@Query("from Customer where custName like ? and custAddress like ?")
      //List<Customer> getCustList(String name, String address);
      @Query("from Customer where custName like ?2 and custAddress like ?1")
      List<Customer> getCustList(String address, String name);
      //测试方法
      @Test
      public void getCustList(){
          //List<Customer> customerList = customerDao.getCustList("%会%", "%界%");
          List<Customer> customerList = customerDao.getCustList("%界%", "%会%");
          for (Customer customer : customerList) {
              System.out.println(customer);
          }
      }
      --sql结果:
      Hibernate: select customer0_.cust_id as cust_id1_0_, customer0_.cust_address as cust_add2_0_, customer0_.cust_industry as cust_ind3_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_address like ?)
      
    • 使用jpql执行更新操作:可以执行更新、删除操作。

      sqlUPDATE cst_customer set cust_source = '互联网' where cust_id = 3
      jpql: update Customer set custSource = ? where custId = ?
      使用方法:
      	1)在dao接口中定义一个方法。
      	2)在方法上添加@Query注解,在注解中编写jpql语句
      	3)在方法上添加@Modifying注解
      	4)测试
      
      //接口
      @Query("update Customer set custSource = ? where custId = ?")
      @Modifying
      @Transactional
      void updateSource(String source, long id);
      //测试方法
      @Test
      /*@Transactional
      @Commit*/
      public void updateSource(){
          customerDao.updateSource("互联网", 11L);
      }
      --sql结果:
      Hibernate: update cst_customer set cust_source=? where cust_id=?
      

3、使用原生的sql语句

​ 使用方法:
​ 1)在dao中定义一个方法
​ 2)在方法上添加@Query注解
​ 3)在注解中添加原生的sql语句,添加一个属性nativeQuery=true

  • //接口
    @Query(value = "select * from cst_customer where cust_name LIKE ?", nativeQuery = true)
    List<Customer> getCustomerListByNative(String name);
    //测试方法
    @Test
    public void getCustomerListByNative(){
        List<Customer> customerList = customerDao.getCustomerListByNative("%国%");
        for (Customer customer : customerList) {
            System.out.println(customer);
        }
    }
    --sql结果:
    Hibernate: select * from cst_customer where cust_name LIKE ?
    

4、方法命名规则查询(推荐使用,重点)

​ 通过一定的规则定义一个方法,框架就可以根据方法名生成一个sql语句进行查询。
​ 规则:
​ 1)应该使用findBy开头
​ 2)查询某个字段,findBy后跟实体类的属性的名称,默认是等于
​ 3)如果有多个条件,就在方法后加And+实体类的属性名。
​ 4)方法的参数对应查询定义。
​ 5)返回值根据返回的数据类型定义。
​ 如果需要分页在方法中添加一个参数Pageable即可。

  • //接口
    Customer findByCustId(Long custId);
    //测试方法
    @Test
    public void testfindByCustId(){
        Customer customer = customerDao.findByCustId(3L);
        System.out.println(customer);
    }
    --sql结果:
    Hibernate: select customer0_.cust_id as cust_id1_0_, customer0_.cust_address as cust_add2_0_, customer0_.cust_industry as cust_ind3_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_id=?
    
  • //接口
    List<Customer> findByCustNameLikeAndCustAddressLike(String name, String address);
    //测试方法
    @Test
    public void testfindByCustNameLikeAndCustAddressLike(){
        List<Customer>  customerList = customerDao.findByCustNameLikeAndCustAddressLike("%会%","%界%");
        for (Customer customer : customerList) {
            System.out.println(customer);
        }
    }
    --sql结果:
    Hibernate: select customer0_.cust_id as cust_id1_0_, customer0_.cust_address as cust_add2_0_, customer0_.cust_industry as cust_ind3_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_address like ?)
    
  • //接口
    Page<Customer> findByCustAddressLike(String address, Pageable pageable);
    //测试方法
    @Test
    public void testfindByCustAddressLike(){
        Page<Customer> page = customerDao.findByCustAddressLike("%阳%", new PageRequest(0, 5));
        System.out.println("查到的记录数: "+page.getTotalElements());
        System.out.println("查到的总页数: "+page.getTotalPages());
        List<Customer> content = page.getContent();
        for (Customer customer : content) {
            System.out.println(customer);
        }
    }
    --sql结果:
    Hibernate: select count(customer0_.cust_id) as col_0_0_ from cst_customer customer0_ where customer0_.cust_address like ?
    Hibernate: select customer0_.cust_id as cust_id1_0_, customer0_.cust_address as cust_add2_0_, customer0_.cust_industry as cust_ind3_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_address like ? limit ?
    

5、使用Specification方式进行查询

​ 说明书方式查询。
​ 最强大的查询方式,最复杂的查询方式。
​ 使用方法:
​ 1)需要dao继承JpaSpecificationExecutor接口

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

​ 2)使用JpaSpecificationExecutor接口中提供方法进行查询。
​ 每个方法都需要使用Specification对象作为参数。

接口:JpaSpecificationExecutor

其中有三个方法:
findOne:查询一条记录

  • //测试
    @Test
    public void testFindByIdSpecification() {
        Customer customer = customerDao.findOne(new Specification<Customer>() {
             /**
                 * @param root 代表sql语句的根节点。相当于sql语句中from后的表名。
                 * @param query 查询对象。sql语句中的关键字包含在其中。例如:where,order by,group by,having等
                 * @param cb 就是 where 条件后面的条件查询,工具对象。
                 * @return
                 */
            @Override
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                /**
                     * Root<Customer>
                     * 参数1:字段名称,就是实体类指定的属性名
                     * 参数2:字段的值,设置实体类指定属性的值
                     */
                Predicate predicate = cb.equal(root.get("custId"), 3L);
                return predicate;
            }
        });
        System.out.println(customer);
    }
    --sql结果:
    Hibernate: select customer0_.cust_id as cust_id1_0_, customer0_.cust_address as cust_add2_0_, customer0_.cust_industry as cust_ind3_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_id=3
        
    //简洁版(Lambda)->一个接口有且仅有一个实现的方法,而且是jdk1.8版本新的内容!
    @Test
    public void testFindByIdSpecificationEasy() {
        //customerDao.findOne((root, query, cb) -> {
        //    Predicate predicate = cb.equal(root.get("custId"), 3L);
        //    return predicate;
        //});
        Customer customer = customerDao.findOne((root, query, cb) -> cb.equal(root.get("custId"), 3L));
        System.out.println(customer);
    }
    

​ findAll:查询多条记录

  • //测试
    @Test
    public void testFincByNameAndAddress() {
        List<Customer> customerList = customerDao.findAll(new Specification<Customer>() {
            @Override
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                //创建根据名称模糊查询的条件,第一个参数实体类的属性名,第二个参数是属性的值
                Predicate predicate1 = cb.like(root.get("custName"),"%会%");
                //创建一个根据地址模糊查询的条件
                Predicate predicate2 = cb.like(root.get("custAddress"), "%界%");
                //组合两个条件and
                Predicate predicate = cb.and(predicate1, predicate2);
                //返回组合之后的条件
                return predicate;
            }
        });
        for (Customer customer : customerList) {
            System.out.println(customer);
        }
        //customerDao.findAll((root, query, cb)->cb.equal(root.get("custId"), 3L)).forEach(System.out::println);
    }
    --sql结果:
    Hibernate: select customer0_.cust_id as cust_id1_0_, customer0_.cust_address as cust_add2_0_, customer0_.cust_industry as cust_ind3_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_address like ?)
    //简洁版
    @Test
    public void testFincByNameAndAddressEasy() {
        customerDao.findAll((root, query, cb) -> cb.and(cb.like(root.get("custName"), "%会%"),cb.like(root.get("custAddress"), "%界%"))).forEach(System.out::println);}
    

​ page:查询全部+分页

  • //测试
    @Test
    public void testFincByNameAndAddressWithPage() {
        Page<Customer> page = customerDao.findAll(new Specification<Customer>() {
            @Override
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                //创建根据名称模糊查询的条件,第一个参数实体类的属性名,第二个参数是属性的值
                Predicate predicate1 = cb.like(root.get("custName"), "%帅%");
                //创建一个根据地址模糊查询的条件
                Predicate predicate2 = cb.like(root.get("custAddress"), "%阳%");
                //组合两个条件and
                Predicate predicate = cb.and(predicate1, predicate2);
                //返回组合之后的条件
                return predicate;
            }
        }, new PageRequest(0, 3));
        System.out.println("查询到的总记录数:"+page.getTotalElements());
        System.out.println("查询到的总页数"+page.getTotalPages());
        List<Customer> content = page.getContent();
        for (Customer customer : content) {
            System.out.println(customer);
        }
    }
    --sql结果:
    Hibernate: select count(customer0_.cust_id) as col_0_0_ from cst_customer customer0_ where (customer0_.cust_name like ?) and (customer0_.cust_address like ?)
    Hibernate: select customer0_.cust_id as cust_id1_0_, customer0_.cust_address as cust_add2_0_, customer0_.cust_industry as cust_ind3_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_address like ?) limit ?
    --简洁版
    customerDao.findAll((root,query, cb)->cb.and(cb.like(root.get("custName"), "%会%"),cb.like(root.get("custAddress"), "%阳%")),new PageRequest(0, 3)).getContent().forEach(System.out::println);
    

    sort:排序

  • //测试
     @Test
    public void testFindCustomerWithSort() {
        List<Customer> customerList = customerDao.findAll(new Specification<Customer>() {
            @Override
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                Predicate predicate = cb.like(root.get("custName"), "%帅%");
                return predicate;
            }
        }, new Sort(Sort.Direction.DESC, "custId"));
        for (Customer customer : customerList) {
            System.out.println(customer);
        }
    }
    --sql结果:
    Hibernate: select customer0_.cust_id as cust_id1_0_, customer0_.cust_address as cust_add2_0_, customer0_.cust_industry as cust_ind3_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 ? order by customer0_.cust_id desc
    

    sort2:排序

  • //测试
    @Test
    public void testFindCustomerWithSort2() {
        List<Customer> customerList = customerDao.findAll(new Specification<Customer>() {
            //根据sql语句: select * from cst_customer where cust_name like '%帅%' order by 'cust_id'
            @Override
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                Predicate predicate = cb.like(root.get("custName"), "%帅%");
                //添加排序
                Predicate result = query.where(predicate).orderBy(cb.desc(root.get("custId"))).getRestriction();
                return result;
            }
        });
        for (Customer customer : customerList) {
            System.out.println(customer);
        }
    }
    --sql结果:
    Hibernate: select customer0_.cust_id as cust_id1_0_, customer0_.cust_address as cust_add2_0_, customer0_.cust_industry as cust_ind3_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 ? order by customer0_.cust_id desc
    
  1. Specification:

    • toPredicate:返回一个查询条件。在方法中应该创建一个查询条件并返回。

      返回值:
      	Predicate:查询条件。
      参数:
          Root:代表sql语句的根节点。相当于sql语句中from后的表名。
      CriteriaQuery:
          查询对象。sql语句中的关键字包含在其中。
          where
          order by
          group by
          having
      CriteriaBuilder:工具对象。
          所有的条件的生成都是使用CriteriaBuilder。
          只要涉及判断都需要使用CriteriaBuilder对象。
          主要使用CriteriaBuilder创建条件。
      

四、总结

1、入门程序

​ 1)框架整合
​ 员(数据源)工(工厂类对象)是(事务)爹(dao包扫描器)
​ 2)Entity
​ 3)dao
​ 定义接口即可,要求接口继承JpaRepository

2、使用dao实现CRUD(重点)

​ 添加:save
​ 修改:save
​ 删除:delete
​ 查询:findOne、getOne

3、查询方法

​ 1)使用dao提供的方法
​ findOne、getOne
​ findAll
​ 可以分页、排序
​ 2)使用jpql查询
​ 查询@Query注解
​ 更新、删除也支持:需要添加注解@Modifying注解
​ 3)原生的sql
​ 使用@Query注解,添加属性nativeQuery=true
​ 4)方法命名规则查询(重点)
​ 5)使用Specification方式查询
​ dao继承JpaSpecificationExecutor接口。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值