zoukankan      html  css  js  c++  java
  • 学习笔记_JPA

    P1.JPA

    C1.HelloWorld

    S1.步骤

    step1.配置jpa的核心配置文件

    • persistent.xml

      • <?xml version="1.0" encoding="UTF-8"?>
        <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
            <!--需要配置persistence-unit节点
                持久化单元:
                    name:持久化单元名称
                    transaction-type:事务管理的方式
                            JTA:分布式事务管理
                            RESOURCE_LOCAL:本地事务管理
            -->
            <persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL">
                <!--jpa的实现方式 -->
                <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        
                <!--可选配置:配置jpa实现方的配置信息-->
                <properties>
                    <!-- 数据库信息
                        用户名,javax.persistence.jdbc.user
                        密码,  javax.persistence.jdbc.password
                        驱动,  javax.persistence.jdbc.driver
                        数据库地址   javax.persistence.jdbc.url
                    -->
                    <property name="javax.persistence.jdbc.user" value="root"/>
                    <property name="javax.persistence.jdbc.password" value="111111"/>
                    <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
                    <property name="javax.persistence.jdbc.url" value="jdbc:mysql:///jpa"/>
        
                    <!--配置jpa实现方(hibernate)的配置信息
                        显示sql           :   false|true
                        自动创建数据库表    :  hibernate.hbm2ddl.auto
                                create      : 程序运行时创建数据库表(如果有表,先删除表再创建)
                                update      :程序运行时创建表(如果有表,不会创建表)
                                none        :不会创建表
        
                    -->
                    <property name="hibernate.show_sql" value="true" />
                    <property name="hibernate.hbm2ddl.auto" value="update" />
                </properties>
            </persistence-unit>
        </persistence>
        

    step2.编写客户实体类并配置映射关系

    • Customer.java

      • /**
         * 客户的实体类
         */
        @Entity
        @Table(name = "tbl_customer")
        public class Customer {
        
            /**
             * 客户id
             * @GeneratedValue => 主键的生成策略
             *      strategy => 主键生成策略
             *          GenerationType.IDENTITY => 自增
             *              底层数据库必须支持自动增长
             *              MySql
             *          GenerationType.SEQUENCE => 序列
             *              底层数据库必须支持序列
             *              Oracle
             *          GenerationType.TABLE => 通过一张数据库表的形式帮助我们完成主键自增
             *              JPA提供的一种机制
             *          GenerationType.AUTO => 由程序自动帮我们选择主键生成策略
             */
            @Id
            @GeneratedValue(strategy = GenerationType.IDENTITY)
            @Column(name = "customer_id")
            private Integer id;
        
            /**
             * 客户姓
             */
            @Column(name = "last_name", length = 50, nullable = false)
            private String lastName;
        
            /**
             * 电子邮件
             */
            @Column(length = 50)
            private String email;
        
            // 略
        }
        

    S2.测试步骤

    step1.加载配置文件,创建工厂对象(实体管理类工厂)

    • EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("持久化单元名称");
      
      • 静态方法

      • 根据持久化单元名称创建实体管理器工厂

      • Persistence对象

        • 主要作用:
          • 创建实体管理器工厂
      • EntityManagerFactory对象 => 实体管理器工厂

        • 主要作用:获取EntityManager对象

        • 内部维护了很多的内容:

          • 维护了数据库信息
          • 维护了所有的实体管理器对象
          • 在创建EntityManagerFactory的过程中会根据配置创建数据库表
        • EntityManagerFactory创建过程比较浪费资源

          • 如何解决?

            • 创建一个公共的EntityManagerFactory对象

            • 静态代码块

            • /**
               * 解决EntityManagerFactory创建耗费资源的问题
               *      通过静态代码块的形式
               *      当程序第一次访问此工具类是,创建一个公共的EntityManagerFactory对象
               *
               * 第一访问getEntityManagerFactory():
               *      经过静态代码块,创建一个factory对象,再调用方法创建一个EntityManager对象
               * 第二访问getEntityManagerFactory():
               *      直接通过一个已经创建好的factory对象,创建EntityManager对象
               */
              public class JpaUtil {
                  private static EntityManagerFactory entityManagerFactory;
              
                  static {
                      entityManagerFactory = Persistence.createEntityManagerFactory("myJpa");
                  }
              
                  /**
                   * 获取EntityManager对象
                   */
                  public static EntityManager getEntityManagerFactory() {
                      return entityManagerFactory.createEntityManager();
                  }
              }
              
        • 线程安全的对象

          • 多个线程访问同一个EntityManagerFactory不会有安全问题

    step2.通过实体管理工程获取实体管理器

    • EntityManager entityManager = entityManagerFactory.createEntityManager();
      
    • EntityManager对象

      • 实体类管理器
      • 真正和数据库打交道的对象
      • JPA操作的核心
        • EntityManager里面的方法来完成增删改查,开启、获取事务对象
        • beginTransaction:创建事务对象
        • persist:保存
        • merge:更新
        • remove:删除
        • find/getReference:根据id查询

    step3.获取事务对象,开启事务

    • 增删改之前要记得开启事务

    • // 获取事务对象
      EntityTransaction tx = entityManager.getTransaction();
      // 开启事务
      tx.begin();
      
    • EntityTransaction对象:

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

    step4.增删改查

    step5.提交事务、回滚事务

    step6.释放资源

    • public class TestStep {
          /**
           * 测试jpa的保存
           *      保存一个用户到数据库中
           */
          @Test
          public void testSave() {
              System.out.println("testSave...");
              
              // step1.加载配置文件,创建工厂对象(实体管理类工厂)
              EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("myJpa");
      
              // step2.通过实体管理工程获取实体管理器
              EntityManager entityManager = entityManagerFactory.createEntityManager();
      
              // step3.获取事务对象,开启事务
              EntityTransaction tx = entityManager.getTransaction(); // 获取事务对象
              tx.begin(); // 开启事务
      
              // step4.增删改查
              Customer customer = new Customer(null, "zhangsan", "123@qq.com");
              entityManager.persist(customer);
      
              // step5.提交事务、回滚事务
              tx.commit();
      
              // step6.释放资源
              entityManager.close();
              entityManagerFactory.close();
          }
      }
      

    S3.JpaUtil

    • 起因:

      • EntityManagerFactory创建过程比较浪费资源,所以要创建一个公共的EntityManagerFactory对象
    • /**
       * 解决EntityManagerFactory创建耗费资源的问题
       *      通过静态代码块的形式
       *      当程序第一次访问此工具类是,创建一个公共的EntityManagerFactory对象
       *
       * 第一访问getEntityManagerFactory():
       *      经过静态代码块,创建一个factory对象,再调用方法创建一个EntityManager对象
       * 第二访问getEntityManagerFactory():
       *      直接通过一个已经创建好的factory对象,创建EntityManager对象
       */
      public class JpaUtil {
          private static EntityManagerFactory entityManagerFactory;
      
          static {
              entityManagerFactory = Persistence.createEntityManagerFactory("myJpa");
          }
      
          /**
           * 获取EntityManager对象
           */
          public static EntityManager getEntityManagerFactory() {
              return entityManagerFactory.createEntityManager();
          }
      }
      

    C2.CRUD

    • persist ------------> 保存
    • merge --------------> 更新
    • remove -------------> 删除
    • find/getReference -> 查找

    S1.插入

    Customer customer = new Customer(null, "lisi", "123456@qq.com");
    entityManager.persist(customer);
    

    S2.查找

    一、find

    Customer customer = entityManager.find(Customer.class, 1);
    
    • 立即加载
    • 使用find方法查询:
      1. 获取的对象就是当前客户对象本身
      2. 在调用find方法时,就会发送sql语句查询数据库

    二、getReference

    Customer customer = entityManager.getReference(Customer.class, 1);
    
    • 延迟加载,懒加载
    • 一般使用这个方法
    • 调用getReference方法查询:
      1. 获取的对象是一个动态代理对象
      2. 调用getReference方法不会立即发送sql语句查询数据库;
        而是在调用查询结果对象的时候才会发送查询的sql语句
        • 什么时候用,什么时候发送sql语句查询数据库

    S3.删除

    Customer customer = entityManager.find(Customer.class, 1);
    entityManager.remove(customer);
    

    S4.更新

    Customer customer = entityManager.find(Customer.class, 2);
    customer.setLastName("王五");
    entityManager.merge(customer);
    

    S5.Demo

    public class TestJpaUtil {
        /**
         * 测试jpa的保存
         *      保存一个用户到数据库中
         */
        @Test
        public void testSave() {
            System.out.println("testSave...");
            
            EntityManager entityManager = JpaUtil.getEntityManager();
    
            EntityTransaction tx = entityManager.getTransaction(); // 获取事务对象
            tx.begin(); // 开启事务
    
            Customer customer = new Customer(null, "lisi", "123456@qq.com");
            entityManager.persist(customer);
    
            tx.commit();
    
            entityManager.close();
        }
    
        /**
         * 根据id查询客户
         */
        @Test
        public void testFind() {
            System.out.println("testFind...");
    
            EntityManager entityManager = JpaUtil.getEntityManager();
            Customer customer = entityManager.find(Customer.class, 1);
            System.out.println("查询结果:" + customer);
            entityManager.close();
        }
    
        /**
         * 根据id查询客户
         */
        @Test
        public void testGetReference() {
            System.out.println("testGetReference...");
    
            EntityManager entityManager = JpaUtil.getEntityManager();
            Customer customer = entityManager.getReference(Customer.class, 1);
            System.out.println("查询结果:" + customer);
            entityManager.close();
        }
    
        /**
         * 测试jpa的删除
         */
        @Test
        public void testRemove() {
            System.out.println("testRemove...");
    
            EntityManager entityManager = JpaUtil.getEntityManager();
    
            EntityTransaction tx = entityManager.getTransaction(); // 获取事务对象
            tx.begin(); // 开启事务
    
            Customer customer = entityManager.find(Customer.class, 1);
            entityManager.remove(customer);
    
            tx.commit();
    
            entityManager.close();
        }
    
        /**
         * 测试jpa的更新
         */
        @Test
        public void testUpdate() {
            System.out.println("testUpdate...");
    
            EntityManager entityManager = JpaUtil.getEntityManager();
    
            EntityTransaction tx = entityManager.getTransaction(); // 获取事务对象
            tx.begin(); // 开启事务
    
            Customer customer = entityManager.find(Customer.class, 2);
            customer.setLastName("王五");
            entityManager.merge(customer);
    
            tx.commit();
    
            entityManager.close();
        }
    }
    

    C3.JPQL

    S1.简介

    • JPA提供的一种查询语句
    • Java Persistence Query Language
    • 面向对象的查询方式
    • SQL:查询的是表和表中的属性
      JPQL:查询的是实体类和类中的属性
    • 语法和SQL相似
    • 会对SQL语句进行优化

    S2.查询

    • 查询的步骤:
      1. 编写jpql语句
      2. 根据jpql语句创建查询对象
      3. 查询,并得到返回结果

    一、查询全部

    • JPQL语句:from xqy.jpa.entity.Customer
    String jpql = "from xqy.jpa.entity.Customer";
    Query query = entityManager.createQuery(jpql);
    List list = query.getResultList();
    

    二、分页查询

    • SQL语句:select * from customer limit ?,?
    • JPQL语句:from xqy.jpa.entity.Customer
    String jpql = "from xqy.jpa.entity.Customer";
    Query query = entityManager.createQuery(jpql);
    query.setFirstResult(0);
    query.setMaxResults(5);
    List list = query.getResultList();
    

    三、统计查询

    • SQL语句:select count(id) from customer
    • JPQL语句:select count(id) from xqy.jpa.entity.Customer
    String jpql = "select count(id) from xqy.jpa.entity.Customer";
    Query query = entityManager.createQuery(jpql);
    Object singleResult = query.getSingleResult();
    

    四、条件查询

    • JPQL语句:from xqy.jpa.entity.Customer where lastName like ?
    String jpql = "from xqy.jpa.entity.Customer where lastName like ?";
    Query query = entityManager.createQuery(jpql);
    query.setParameter(1, "l%");
    List list = query.getResultList();
    

    五、排序

    • SQL语句:select * from customer order by id desc
    • JPQL语句:from xqy.jpa.entity.Customer order by id desc
    String jpql = "from xqy.jpa.entity.Customer order by id desc";
    Query query = entityManager.createQuery(jpql);
    List list = query.getResultList();
    

    P2.SpringDataJPA

    C1.简述

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

    C2.HelloWorld

    S1.步骤

    step1.配置Spring的配置文件

    <?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">
    
        <!-- Spring 和 Spring Data JPA的配置 -->
    
        <!-- 1.创建entityManagerFactory对象交给Spring容器管理 -->
        <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
            <!-- 配置数据源 -->
            <property name="dataSource" ref="dataSource"/>
    
            <!-- 配置扫描的包(实体类所在的包) -->
            <property name="packagesToScan" value="xqy.bean"/>
    
            <!-- JPA的实现厂家 -->
            <property name="persistenceProvider">
                <bean class="org.hibernate.jpa.HibernatePersistenceProvider"></bean>
            </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" />
                    <!--是否显示sql -->
                    <property name="showSql" value="true" />
                </bean>
            </property>
    
            <!-- JPA的方言(可选):高级特性 -->
            <property name="jpaDialect">
                <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"></bean>
            </property>
    
        </bean>
    
        <!-- 2.创建数据库连接池 -->
        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="user" value="root"></property>
            <property name="password" value="123456"></property>
            <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
            <property name="jdbcUrl" value="jdbc:mysql://192.168.252.128:3306/jpa"></property>
        </bean>
        
        <!-- 3.整合Spring Data JPA -->
        <jpa:repositories base-package="xqy.dao" transaction-manager-ref="transactionManager" entity-manager-factory-ref="entityManagerFactory"></jpa:repositories>
    
        <!-- 4.配置事务管理器 -->
        <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
            <property name="entityManagerFactory" ref="entityManagerFactory"></property>
        </bean>
    
        <!-- 5.声明式事务 -->
    
        <!-- 6.配置包扫描 -->
        <context:component-scan base-package="xqy"></context:component-scan>
    </beans>
    

    step2.编写实体类

    @Entity
    @Table(name = "tbl_customer")
    public class Customer {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "customer_id")
        private Integer id;
        
        @Column(name = "last_name", length = 50, nullable = false)
        private String lastName;
        
        @Column(length = 50)
        private String email;
    
        // 略
    }
    

    step3.编写dao层接口

    • 只需要编写dao层接口,不需要编写dao层接口的实现类
    • dao层接口规范:
      1. 继承两个接口:
        1. JpaRepository
          • 封装了基本CRUD操作
        2. JpaSpecificationExecutor
          • 封装了复杂查询(分页)
      2. 需要提供响应的泛型
    public interface CustomerDao extends JpaRepository<Customer, Integer>, JpaSpecificationExecutor<Customer> {}
    

    S2.测试

    @RunWith(SpringJUnit4ClassRunner.class) // 声明Spring提供的单元测试环境
    @ContextConfiguration(locations = "classpath:applicationContext.xml") // 指定Spring容器的配置信息
    public class test4SpringDataJpa {
    
        @Autowired
        CustomerDao customerDao;
    
        /**
         * 根据id查询
         */
        @Test
        public void testFindOne() {
            System.out.println("testFindOne...");
            
            Customer customer = customerDao.findOne(2);
            System.out.println(customer);
        }
    
        /**
         * 保存或者更新
         *      没有id => 保存
         *      有id => 更新
         */
        @Test
        public void testSave() {
            System.out.println("testSave...");
    
            Customer customer = new Customer();
    //        customer.setId(2);
            customer.setLastName("wangermazi");
            customer.setEmail("wangermazi@qq.com");
            
            Customer save = customerDao.save(customer);
            System.out.println(save);
        }
    
        /**
         * 测试删除
         */
        @Test
        public void testDelete() {
            System.out.println("testDelete...");
    
            customerDao.delete(16);
        }
    
        /**
         * 查询所有
         */
        @Test
        public void testFindAll() {
            System.out.println("testFindAll...");
    
            List<Customer> all = customerDao.findAll();
            for (Customer c: all) {
                System.out.println(c);
            }
        }
    }
    

    S3.总结

    • findOne(id) ----> 根据id查询
    • save(customer) -> 保存或更新(保存:无主键;更新:有主键)
    • delete(id) -----> 根据id删除
    • findAll() ------> 查询全部

    C3.运行过程和原理剖析

    • Dao层只是接口,而真正发挥作用的是接口的实现类

      • 在程序的执行过程中,自动的帮我们动态生成了接口的实现类对象
      • 如何动态地生成实现类对象?
        • 动态代理(生成基于接口的实现类对象)
    • springdatajpa的运行过程:

      • 03-springdatajpa的运行过程
    • 原理:

      1. 通过JdkDynamicAopProxy的invoke方法创建了一个动态代理对象
      2. SimpleJpaRepository当中封装了JPA的操作(借助JPA的api完成数据库的CRUD)
      3. 通过hibernate完成数据库操作(封装了jdbc)

    P3.查询的方法

    法一.JpaRepository接口中定义的方法

    一、统计查询

    /**
     * 统计查询
     */
    @Test
    public void testCount() {
        System.out.println("testCount...");
    
        long count = customerDao.count();
        System.out.println(count);
    }
    

    二、判断是否存在

    /**
     * 测试是否存在
     */
    @Test
    public void testExists() {
        System.out.println("testExists...");
    
        boolean exists = customerDao.exists(4);
        System.out.println(exists);
    }
    

    三、根据id查询单个实体

    findOne()和getOne()区别

    • findOne():
      • em.find() => 立即加载
    • getOne():
      • em.getReference() => 延迟加载
        • 延迟加载和事务有关系,所以要加上@Transactional
        • 返回的是一个客户的动态代理对象
        • 什么时候用,什么时候查询
    • findOne()

      • @Test
        public void testFindOne() {
            System.out.println("testFindOne...");
        
            Customer customer = customerDao.findOne(2);
            System.out.println(customer);
        }
        
    • getOne()

      • /**
         * 根据id从数据库查询
         * @Transactional => 使用事务
         *      保证getOne正常进行
         */
        @Test
        @Transactional
        public void testGetOne() {
        	System.out.println("testGetOne...");
        
        	Customer customer = customerDao.getOne(4);
        	System.out.println(customer);
        }
        

    四、查询所有

    @Test
    public void testFindAll() {
    	System.out.println("testFindAll...");
    
    	List<Customer> all = customerDao.findAll();
    	for (Customer c: all) {
    		System.out.println(c);
    	}
    }
    

    五、保存或者更新

    • 没有id => 保存
    • 有id => 更新
    @Test
    public void testSave() {
    	System.out.println("testSave...");
    
    	Customer customer = new Customer();
    //        customer.setId(2);
    	customer.setLastName("wangermazi");
    	customer.setEmail("wangermazi@qq.com");
    	
    	Customer save = customerDao.save(customer);
    	System.out.println(save);
    }
    
    

    六、删除

    @Test
    public void testDelete() {
    	System.out.println("testDelete...");
    
    	customerDao.delete(16);
    }
    

    法二.JpaSpecificationExecutor接口中定义的方法

    S1.方法列表

    1. T findOne(Specification<T> spec);
      • 查询单个对象
    2. long count(Specification<T> spec);
      • 统计查询
    3. List<T> findAll(Specification<T> spec);
    • 查询列表
    1. Page<T> findAll(Specification<T> spec, Pageable pageable);
    • 查询全部,分页
    • pageable:分页参数
    • 返回值:分页pageBean(page:是springdatajpa提供的)
    1. List<T> findAll(Specification<T> spec, Sort sort);
    • 查询列表
    • Sort:排序参数

    S2.Specification类

    自定义我们自己的Specification实现类

    • 该类通过实现public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);方法,来指明查询条件
      • Root
        • 获取需要查询的对象属性,查询的任何属性都可以从根对象中获取
      • CriteriaQuery
        • 顶层查询对象,自定义查询方式(了解:一般不用)
      • CriteriaBuilder
        • 构造查询条件,内部封装了很多的查询条件

    一、精确匹配查询

    @Test
    public void test() {        
        Specification<Customer> spec = new Specification<Customer>() {
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                // 1.获取比较的属性
                Path<Object> lastName = root.get("lastName");
                // 2.构造查询条件
                Predicate predicate = criteriaBuilder.equal(lastName, "李四"); // 进行精准匹配
                return predicate;
            }
        };
    
        Customer customer = customerDao.findOne(spec);
        System.out.println(customer);
    }
    

    二、模糊条件查询

    @Test
    public void testLike() {
        Specification<Customer> spec = new Specification<Customer>() {
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Path<Object> lastName = root.get("lastName");
                Expression<String> expression = lastName.as(String.class); // 模糊查询时需要指定属性类型
                Predicate predicate = criteriaBuilder.like(expression, "%ah%");
                return predicate;
            }
        };
    
        List<Customer> list = customerDao.findAll(spec);
        for (Customer customer : list) {
            System.out.println(customer);
        }
    }
    

    三、对查询结果排序

    @Test
    public void testOrder() {
        Specification<Customer> spec = new Specification<Customer>() {
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Path<Object> lastName = root.get("lastName");
                Expression<String> expression = lastName.as(String.class);
                Predicate predicate = criteriaBuilder.like(expression, "%ah%");
                return predicate;
            }
        };
        Sort sort = new Sort(Sort.Direction.DESC, "id");
    
        List<Customer> list = customerDao.findAll(spec, sort);
        for (Customer customer : list) {
            System.out.println(customer);
        }
    }
    

    四、分页查询

    • Page<T> findAll(Specification<T> var1, Pageable var2) => 有条件的分页
      • Specification:查询条件
      • Pageable:分页参数
        • 查询的页码,每页的条数
      • 返回:Page
        • SpringDataJpa为我们创建的PageBean对象
    • Page<T> findAll(Pageable var2) => 没有条件的分页
    @Test
    public void testPagging() {
        Specification<Customer> spec = new Specification<Customer>() {
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Path<Object> lastName = root.get("lastName");
                Expression<String> expression = lastName.as(String.class);
    
                Predicate predicate = criteriaBuilder.like(expression, "%ah%");
    
                return predicate;
            }
        };
    
        Pageable pageable = new PageRequest(0, 5);
    
        Page<Customer> page = customerDao.findAll(spec, pageable);
        for (Customer customer : page.getContent()) {
            System.out.println(customer);
        }
    }
    

    五、多条件查询

    每一个Predicate就是一个条件

    @Test
    public void testMulCondition() {
        Specification<Customer> spec = new Specification<Customer>() {
            public Predicate toPredicate(Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Path<Object> id = root.get("id");
                Path<Object> lastName = root.get("lastName");
    
                Predicate predicate0 = criteriaBuilder.equal(id, 7);
                Predicate predicate1 = criteriaBuilder.equal(lastName, "haha");
    
                Predicate predicate = criteriaBuilder.and(predicate0, predicate1);
    
                return predicate;
            }
    
        };
    
        Customer customer = customerDao.findOne(spec);
        System.out.println(customer);
    }
    

    法三.JPQL

    • JPQL的查询方式

    • 对于多个占位符参数

      • 赋值的时候,默认情况下,占位符的位置需要和方法参数的位置一致
      • 否则,需要指定此占位符的取值来源
        • ?1
    • 代码示例:

      • CustomerDao.java

        • public interface CustomerDao extends JpaRepository<Customer, Integer>, JpaSpecificationExecutor<Customer> {
          
              @Query(value = "from Customer where last_name=?")
              public List<Customer> findJpql(String lastName);
          
              @Query(value = "from Customer where id=? and lastName=?")
              public Customer findByNameAndIdJpql(Integer id, String lastName);
          
              /**
               * 对于多个占位符参数
               *      赋值的时候,默认情况下,占位符的位置需要和方法参数的位置一致
               * 否则的话,需要指定此占位符的取值来源
               */
              @Query(value = "from Customer where id=?2 and lastName=?1")
              public Customer findByNameAndIdOrderJpql(String lastName, Integer id);
          
              /**
               * 根据客户id,更新客户名称
               * @Modifying => 当前是一个更新操作
               */
              @Query(value = "update Customer set lastName=? where id=?")
              @Modifying
              public void updateCustomerJpql(String lastName, Integer id);
          }
          
      • 测试类

        • @RunWith(SpringJUnit4ClassRunner.class) // 声明Spring提供的单元测试环境
          @ContextConfiguration(locations = "classpath:applicationContext.xml") // 指定Spring容器的配置信息
          public class test4JPQL {
          
              @Autowired
              CustomerDao customerDao;    
              
              /**
               * 测试Jpql,根据id查询用户
               */
              @Test
              public void testFindJpql() {
                  List<Customer> list = customerDao.findJpql("lisi");
                  for (Customer customer: list) {
                      System.out.println(customer);
                  }
              }
              
              /**
               * 测试Jpql,根据id和名称查询客户
               */
              @Test
              public void testFindByNameAndIdJpql() {        
                  Customer customer = customerDao.findByNameAndIdOrderJpql("lisi", 3);
                  System.out.println(customer);
              }
          
              /**
               * 测试Jpa的更新操作
               *      Spring Data JPA默认执行结束后会回滚事务
               *      @Rollback(value = false) => 设置是否自动回滚
               */
              @Test
              @Transactional
              @Rollback(value = false)
              public void testModifying() {
                  customerDao.updateCustomerJpql("李四", 3);
              }
          
          }
          

    法四.SQL

    • SQL语句的查询

    • @Query

      • value:Jpql语句、Sql语句
      • nativeQuery
        • 使用SQL查询 --> true
        • 使用JPQL查询 -> false
    • 返回值类型都必须为:List<Object[]>

    • 代码示例:

      • CustomerDao.java

        • public interface CustomerDao extends JpaRepository<Customer, Integer>, JpaSpecificationExecutor<Customer> {
          
              @Query(value = "select * from tbl_customer", nativeQuery = true)
              public List<Object[]> findSql();
          
              @Query(value = "select * from tbl_customer where last_name like ?", nativeQuery = true)
              public List<Object[]> findLikeSql(String name);
          
          }
          
      • 测试:

        • @RunWith(SpringJUnit4ClassRunner.class) // 声明Spring提供的单元测试环境
          @ContextConfiguration(locations = "classpath:applicationContext.xml") // 指定Spring容器的配置信息
          public class test4SQL {
          
              @Autowired
              CustomerDao customerDao;
          
              @Test
              public void testFind() {
                  System.out.println("testFind...");
          
                  List<Object[]> objects = customerDao.findSql();
                  for (Object[] obj: objects) {
                      System.out.println(Arrays.toString(obj));
                  }
              }
          
              @Test
              public void testFuzzyQuery() {
                  System.out.println("testFuzzyQuery...");
          
                  List<Object[]> list = customerDao.findLikeSql("%is%");
                  for (Object[] obj: list) {
                      System.out.println(Arrays.toString(obj));
                  }
              }
          
          }
          

    法五.方法名称规则查询

    • 对jpql查询更加深入一层的封装

    • 我们只需要按照SpringDataJpa提供的方法名称规则定义方法,不需要再去配置jpql语句,完成查询

    • 约定:

      • findBy+属性名(对象,首字母大写)
        • 如:findByLastName
        • 在Spring Data Jpa的运行阶段,会根据方法名称进行解析:
          • findBy => from xxx(实体类)
          • 属性名称 => where 属性名=
        • 根据属性名称进行完全匹配
      • findBy+属性名+查询方式
        • 如:findByLastNameLike
      • findBy+属性名+[查询方式]+And|Or+属性名+[查询方式]
    • 代码示例:

      • Customer.java

        • public interface CustomerDao extends JpaRepository<Customer, Integer>, JpaSpecificationExecutor<Customer> {
          
              public List<Customer> findByLastName(String lastName);
          
              public List<Customer> findByLastNameLike(String lastName);
          
              public List<Customer> findByLastNameLikeOrEmail(String lastName, String email);
          
          }
          
      • 测试:

        • @RunWith(SpringJUnit4ClassRunner.class) // 声明Spring提供的单元测试环境
          @ContextConfiguration(locations = "classpath:applicationContext.xml") // 指定Spring容器的配置信息
          public class test4NameRule {
          
              @Autowired
              CustomerDao customerDao;
          
              @Test
              public void testQueryByLastName() {
                  System.out.println("testQueryByLastName...");
          
                  List<Customer> list = customerDao.findByLastName("lisi");
                  for (Customer c: list) {
                      System.out.println(c);
                  }
              }
          
              @Test
              public void testFindByLastNameLike() {
                  System.out.println("testFindByLastNameLike...");
          
                  List<Customer> list = customerDao.findByLastNameLike("%ah%");
                  for (Customer customer : list) {
                      System.out.println(customer);
                  }
              }
          
              @Test
              public void testFindByLastNameLikeOrEmail() {
                  System.out.println("testFindByLastNameLikeOrEmail...");
          
                  List<Customer> list = customerDao.findByLastNameLikeOrEmail("%四%", "wangermazi@qq.com");
                  for (Customer customer : list) {
                      System.out.println(customer);
                  }
              }
          }
          

    P4.多表

    C1.多表之间的关系

    • 表关系

      • 一对一
      • 一对多
        • 一 => 主表
        • 多 => 从表
        • 外键:在从表上
      • 多对多
        • 中间表
    • 实体类中的关系

      • 包含关系
      • 继承关系
    • 分析步骤

      1. 明确表关系
      2. 确定表关系
      3. 编写实体类
      4. 配置映射关系

    C2.多表操作

    S1.一对多

    一、普通操作代码示例

    • 配置外键的过程,配置到多的一方,就会由多的一方维护外键;配置到少的一方,就会由少的一方维护外键

      • 两边都配置 => 双向配置
        只配置一边 => 单向配置

      • 由一的一方维护外键,会发送update语句,所以一般一的一方会放弃维护权

    • 使用注解的形式配置多表关系

      1. 声明关系
        • @OneToMany
          • targetEntity => 对方对象的class
          • mappedBy => 指定参考多一方的哪一个属性
          • cascade => 指定级联的范围
            • ALL => Cascade all operations
            • PERSIST => Cascade persist operation
            • MERGE => Cascade merge operation
            • REMOVE => Cascade remove operation
            • REFRESH => Cascade refresh operation
            • DETACH => Cascade detach operation
        • @ManyToOne => 配置多对一关系
      2. 配置关系(中间表)
        • @JoinColumn => 配置外键
          • name => 外键字段名称
          • referencedColumnName => 主表中的主键字段名称
    • 配置外键的过程,配置到One的一方,就会在One的一方维护外键

    • 实体类

      • @Entity
        @Table(name = "tbl_company")
        public class Company {
        
            @Id
            @GeneratedValue(strategy = GenerationType.IDENTITY)
            @Column(name = "company_id")
            private Integer companyId;
        
            @Column(name = "last_name", length = 50, nullable = false)
            private String lastName;
        
            @Column(length = 50)
            private String email;
        
            /* 配置一对多关系 */
        //    @OneToMany(targetEntity = Employee.class)
        //    @JoinColumn(name = "c_id", referencedColumnName = "company_id")
            @OneToMany(mappedBy = "company") // 一的一方放弃维护外键
            private Set<Employee> employees = new HashSet<Employee>();
        
           // 略
        }
        
      • @Entity
        @Table(name = "tbl_employee")
        public class Employee {
        
            @Id
            @GeneratedValue(strategy = GenerationType.IDENTITY)
            @Column(name = "employee_id")
            private Integer employeeId;
        
            @Column(name = "last_name", length = 50, nullable = false)
            private String lastName;
        
            @Column
            private Integer age;
        
            /* 配置多对一的关系 */
            @ManyToOne(targetEntity = Company.class)
            @JoinColumn(name = "c_id", referencedColumnName = "company_id")
            private Company company;
        
            // 略
        }
        
    • OneToManyTest.java

      • @RunWith(SpringJUnit4ClassRunner.class)
        @ContextConfiguration(locations = "classpath:applicationContext.xml")
        public class OneToManyTest {
        
            @Autowired
            private CompanyDao companyDao;
        
            @Autowired
            private EmployeeDao employeeDao;
        
            /**
             * 保存一个客户,保存一个联系人
             */
            @Test
            @Transactional
            @Rollback(false)
            public void testAdd() {
                Company company = new Company();
                company.setLastName("百度");
        
                Employee employee = new Employee();
                employee.setLastName("小李");
        
                employee.setCompany(company);
                company.getEmployees().add(employee);
        
                companyDao.save(company);
                employeeDao.save(employee);
            }
        }
        
    • pom.xml

      • <?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">
            <groupId>xqy.maven.jpa</groupId>
            <artifactId>jjpa-demo5-onetomany</artifactId>
            <version>1.0-SNAPSHOT</version>
            <modelVersion>4.0.0</modelVersion>
        
            <properties>
                <spring.version>5.0.2.RELEASE</spring.version>
                <hibernate.version>5.0.7.Final</hibernate.version>
                <slf4j.version>1.6.6</slf4j.version>
                <log4j.version>1.2.12</log4j.version>
                <c3p0.version>0.9.1.2</c3p0.version>
                <mysql.version>5.1.6</mysql.version>
            </properties>
        
            <dependencies>
                <!-- junit单元测试 -->
                <dependency>
                    <groupId>junit</groupId>
                    <artifactId>junit</artifactId>
                    <version>4.12</version>
                    <scope>test</scope>
                </dependency>
        
                <!-- spring beg -->
                <dependency>
                    <groupId>org.aspectj</groupId>
                    <artifactId>aspectjweaver</artifactId>
                    <version>1.6.8</version>
                </dependency>
        
                <dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-aop</artifactId>
                    <version>${spring.version}</version>
                </dependency>
        
                <dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-context</artifactId>
                    <version>${spring.version}</version>
                </dependency>
        
                <dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-context-support</artifactId>
                    <version>${spring.version}</version>
                </dependency>
        
                <!-- spring对orm框架的支持包-->
                <dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-orm</artifactId>
                    <version>${spring.version}</version>
                </dependency>
        
                <dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-beans</artifactId>
                    <version>${spring.version}</version>
                </dependency>
        
                <dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-core</artifactId>
                    <version>${spring.version}</version>
                </dependency>
        
                <!-- spring end -->
        
                <!-- hibernate beg -->
                <dependency>
                    <groupId>org.hibernate</groupId>
                    <artifactId>hibernate-core</artifactId>
                    <version>${hibernate.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.hibernate</groupId>
                    <artifactId>hibernate-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>
        
                <!-- spring data jpa 的坐标-->
                <dependency>
                    <groupId>org.springframework.data</groupId>
                    <artifactId>spring-data-jpa</artifactId>
                    <version>1.9.0.RELEASE</version>
                </dependency>
        
                <dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-test</artifactId>
                    <version>${spring.version}</version>
                </dependency>
        
                <!-- el beg 使用spring data jpa 必须引入 -->
                <dependency>
                    <groupId>javax.el</groupId>
                    <artifactId>javax.el-api</artifactId>
                    <version>2.2.4</version>
                </dependency>
        
                <dependency>
                    <groupId>org.glassfish.web</groupId>
                    <artifactId>javax.el</artifactId>
                    <version>2.2.4</version>
                </dependency>
                <!-- el end -->
            </dependencies>
        
        </project>
        
    • 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:jdbc="http://www.springframework.org/schema/jdbc"
               xmlns:jpa="http://www.springframework.org/schema/data/jpa"
               xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        		http://www.springframework.org/schema/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/data/jpa
        		http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
        
            <!-- Spring 和 Spring Data JPA的配置 -->
        
            <!-- 1.创建entityManagerFactory对象交给Spring容器管理 -->
            <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
                <!-- 配置数据源 -->
                <property name="dataSource" ref="dataSource"/>
        
                <!-- 配置扫描的包(实体类所在的包) -->
                <property name="packagesToScan" value="xqy.bean"/>
        
                <!-- JPA的实现厂家 -->
                <property name="persistenceProvider">
                    <bean class="org.hibernate.jpa.HibernatePersistenceProvider"></bean>
                </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"/>
                        <!--是否显示sql -->
                        <property name="showSql" value="true"/>
                    </bean>
                </property>
        
                <!-- JPA的方言(可选):高级特性 -->
                <property name="jpaDialect">
                    <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"></bean>
                </property>
        
                <!-- 注入jpa的配置信息
                    加载jpa的基本配置信息和jpa实现方式(hibernate)的配置信息
                    hibernate.hbm2ddl.auto => 自动创建数据库表
                        create => 每次都会重新创建数据库表
                        update => 有表不会重新创建,没有表会重新创建表
                -->
                <property name="jpaProperties">
                    <props>
                        <prop key="hibernate.hbm2ddl.auto">create</prop>
                    </props>
                </property>
        
            </bean>
        
            <!-- 2.创建数据库连接池 -->
            <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
                <property name="user" value="root"></property>
                <property name="password" value="123456"></property>
                <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
                <property name="jdbcUrl"
                          value="jdbc:mysql://192.168.252.128:3306/jpa?useUnicode=true&amp;characterEncoding=utf8"/>
            </bean>
        
            <!-- 3.整合Spring Data JPA -->
            <jpa:repositories base-package="xqy.dao" transaction-manager-ref="transactionManager"
                              entity-manager-factory-ref="entityManagerFactory"></jpa:repositories>
        
            <!-- 4.配置事务管理器 -->
            <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
                <property name="entityManagerFactory" ref="entityManagerFactory"></property>
            </bean>
        
            <!-- 5.声明式事务 -->
        
            <!-- 6.配置包扫描 -->
            <context:component-scan base-package="xqy"></context:component-scan>
        </beans>
        

    二、级联操作代码示例

    • Employee.java

      • @Entity
        @Table(name = "tbl_employee")
        public class Employee {
        
            @Id
            @GeneratedValue(strategy = GenerationType.IDENTITY)
            @Column(name = "employee_id")
            private Integer employeeId;
        
            @Column(name = "last_name", length = 50, nullable = false)
            private String lastName;
        
            @Column
            private Integer age;
        
            /* 配置多对一的关系 */
            @ManyToOne(targetEntity = Company.class)
            @JoinColumn(name = "c_id", referencedColumnName = "company_id")
            private Company company;
        
            // 略
        }
        
    • Company.java

      • @Entity
        @Table(name = "tbl_company")
        public class Company {
        
            @Id
            @GeneratedValue(strategy = GenerationType.IDENTITY)
            @Column(name = "company_id")
            private Integer companyId;
        
            @Column(name = "last_name", length = 50, nullable = false)
            private String lastName;
        
            @Column(length = 50)
            private String email;
        
            /* 配置一对多关系 */
            @OneToMany(mappedBy = "company", cascade = CascadeType.ALL) // 配置级联
            private Set<Employee> employees = new HashSet<Employee>();
        
            // 略
        }
        
    • OneToManyTest.java

      • @RunWith(SpringJUnit4ClassRunner.class)
        @ContextConfiguration(locations = "classpath:applicationContext.xml")
        public class OneToManyTest {
        
            @Autowired
            private CompanyDao companyDao;
        
            @Autowired
            private EmployeeDao employeeDao;    
            
            /**
             * 级联添加
             */
            @Test
            @Transactional
            @Rollback(false)
            public void testCascadeAdd() {
                Company company = new Company();
                company.setLastName("阿里3");
        
                Employee employee = new Employee();
                employee.setLastName("二狗子3");
        
                Employee employee2 = new Employee();
                employee2.setLastName("小李3");
        
                // 设置好双方的关系
                company.getEmployees().add(employee);
                employee.setCompany(company);
                company.getEmployees().add(employee2);
                employee2.setCompany(company);
        
                companyDao.save(company); // 不用再手动保存employee,employee会自动保存到数据库中
            }
            
            /**
             * 级联删除
             */
            @Test
            @Transactional
            @Rollback(false)
            public void testCascadeRemove() {
                Company company = companyDao.getOne(3);
                companyDao.delete(company);
            }
        }
        

    S2.多对多

    • 配置和“一对多”的配置一样
    • 多对多的某一方必须放弃维护权,否则会报错
    • @ManyToMany
      • targetEntity
      • cascade
      • mappedBy => 参照对方实体中哪个属性的配置
    • @JoinTable => 配置中间表
      • name => 中间表的名称
      • joinColumns => 配置当前对象在中间表中的外键
        • @JoinColumn
          • name => 中间表中的字段名
          • referencedColumnName => 实体中对应的属性名
      • inverseJoinColumns => 配置对方对象在中间表中的外键
        • @JoinColumn
          • name => 中间表中的字段名
          • referencedColumnName => 实体中对应的属性名

    一、普通操作代码示例

    • Person.java

      • @Entity
        @Table(name = "tbl_person")
        public class Person {
        
            @Id
            @GeneratedValue(strategy = GenerationType.IDENTITY)
            @Column(name = "person_id")
            private Integer personId;
        
            @Column(name = "name")
            private String name;
        
            /* 配置多对多关系的映射关系 */
            @ManyToMany(targetEntity = Job.class)
            @JoinTable(name = "sys_person_job",
                joinColumns = {@JoinColumn(name = "p_id", referencedColumnName = "person_id")},
                inverseJoinColumns = {@JoinColumn(name = "j_id", referencedColumnName = "job_id")}
            )
            private Set<Job> jobs = new HashSet<Job>();
        
           // 略
        }
        
    • Job.java

      • @Entity
        @Table(name = "tbl_job")
        public class Job {
        
            @Id
            @GeneratedValue(strategy = GenerationType.IDENTITY)
            @Column(name = "job_id")
            private Integer jobId;
        
            @Column(name = "name")
            private String name;
        
            /* 配置多对多关系的映射关系 */
            @ManyToMany(mappedBy = "jobs") // 参照对方实体中哪个属性的配置
            private Set<Person> people = new HashSet<Person>();
        
            // 略
        }
        
    • 测试类:

      • @RunWith(SpringJUnit4ClassRunner.class)
        @ContextConfiguration(locations = "classpath:applicationContext.xml")
        public class ManyToManyTest {
        
            @Autowired
            private PersonDao personDao;
        
            @Autowired
            private JobDao jobDao;
            
            @Test
            @Transactional
            @Rollback(false)
            public void testAdd() {
                System.out.println("testAdd...");
        
                Person person = new Person();
                person.setName("李四");
        
                Job job = new Job();
                job.setName("工程师");
        
                person.getJobs().add(job);
        
                personDao.save(person);
                jobDao.save(job);
            }
        }
        

    二、级联操作代码示例

    • Person.java

      • @Entity
        @Table(name = "tbl_person")
        public class Person {
        
            @Id
            @GeneratedValue(strategy = GenerationType.IDENTITY)
            @Column(name = "person_id")
            private Integer personId;
        
            @Column(name = "name")
            private String name;
            
            /* 配置多对多关系的映射关系 */
            @ManyToMany(targetEntity = Job.class, cascade = CascadeType.ALL)
            @JoinTable(name = "sys_person_job",
                joinColumns = {@JoinColumn(name = "p_id", referencedColumnName = "person_id")},
                inverseJoinColumns = {@JoinColumn(name = "j_id", referencedColumnName = "job_id")}
            )
            private Set<Job> jobs = new HashSet<Job>();
        
            // 略
        }
        
    • Job.java

      • @Entity
        @Table(name = "tbl_job")
        public class Job {
        
            @Id
            @GeneratedValue(strategy = GenerationType.IDENTITY)
            @Column(name = "job_id")
            private Integer jobId;
        
            @Column(name = "name")
            private String name;
        
            /* 配置多对多关系的映射关系 */
            @ManyToMany(mappedBy = "jobs")
            private Set<Person> people = new HashSet<Person>();
        
            // 略
        }
        
    • 测试类:

      • /**
         * 另外一张表、中间表中的对应元组都会被删除
         */
        @Test
        public void testCascadeDelete() {
            System.out.println("testCascadeDelete...");
        
            Person person = personDao.getOne(1);
            personDao.delete(person);
        }
        

    S3.对象导航查询

    一、从一查多

    • 查询一个对象的时候,通过此对象查询所有的关联对象
    • 从一查多默认使用的是延迟加载
      • 若不想延迟加载,则可以修改配置:
        • OneToManyManyToOneManyToMany上配置fetch
          • FetchType.EAGER => 立即查询(不推荐)
          • FetchType.LAZY => 懒加载
    @Test
    @Transactional
    @Rollback(false)
    public void testQuery1() {
        Company company = companyDao.getOne(2);
        Set<Employee> employees = company.getEmployees();
        for (Employee employee : employees) {
            System.out.println(employee);
        }
    }
    

    二、从多查一

    • 从多查一默认使用立即加载
    @Test
    @Transactional
    @Rollback(false)
    public void testQuery2() {
        Employee employee = employeeDao.findOne(2);
        System.out.println(employee.getCompany());
    }
    
  • 相关阅读:
    window多线程编程
    强大的字符数组
    linux设置环境变量一些坑的总结
    Java hello world
    一次音频波形的问题
    0xfffxxx的负数表示
    pcm数据格式存储格式
    Pooled genome sequence strategies |representative genome assembly approaches|Domestication|GERP|selective sweep|Hybridization|Introgression|iHS|SNP genotyping arrays|haplotype
    【转】Fst指数
    index|substr
  • 原文地址:https://www.cnblogs.com/daheww/p/14081174.html
Copyright © 2011-2022 走看看