Specification动态查询 前提 Dao接口必须继承JpaSpecificationExecutor接口 
能够使用动态查询的方法 1 2 3 4 5 6 7 8 9 10 11 12  public  interface  JpaSpecificationExecutor <T >  {    	  	T findOne (Specification<T> spec)  ;	    	  	List<T> findAll (Specification<T> spec)  ;    	  	Page<T> findAll (Specification<T> spec, Pageable pageable)  ;    	  	List<T> findAll (Specification<T> spec, Sort sort)  ;    	  	long  count (Specification<T> spec)  ; } 
 
环境搭建 创建项目 引入依赖[配置pom.xml] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 <?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 >      <groupId > cn.itcast</groupId >      <artifactId > jpa-day2</artifactId >      <version > 1.0-SNAPSHOT</version >      <properties >          <spring.version > 5.0.2.RELEASE</spring.version >          <hibernate.version > 5.0.7.Final</hibernate.version >          <slf4j.version > 1.6.6</slf4j.version >          <log4j.version > 1.2.12</log4j.version >          <c3p0.version > 0.9.1.2</c3p0.version >          <mysql.version > 5.1.6</mysql.version >      </properties >      <dependencies >                   <dependency >              <groupId > junit</groupId >              <artifactId > junit</artifactId >              <version > 4.12</version >              <scope > test</scope >          </dependency >                   <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 >                            <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 >                            <dependency >              <groupId > c3p0</groupId >              <artifactId > c3p0</artifactId >              <version > ${c3p0.version}</version >          </dependency >                            <dependency >              <groupId > log4j</groupId >              <artifactId > log4j</artifactId >              <version > ${log4j.version}</version >          </dependency >          <dependency >              <groupId > org.slf4j</groupId >              <artifactId > slf4j-api</artifactId >              <version > ${slf4j.version}</version >          </dependency >          <dependency >              <groupId > org.slf4j</groupId >              <artifactId > slf4j-log4j12</artifactId >              <version > ${slf4j.version}</version >          </dependency >                   <dependency >              <groupId > mysql</groupId >              <artifactId > mysql-connector-java</artifactId >              <version > ${mysql.version}</version >          </dependency >                   <dependency >              <groupId > org.springframework.data</groupId >              <artifactId > spring-data-jpa</artifactId >              <version > 1.9.0.RELEASE</version >          </dependency >          <dependency >              <groupId > org.springframework</groupId >              <artifactId > spring-test</artifactId >              <version > ${spring.version}</version >          </dependency >                   <dependency >              <groupId > javax.el</groupId >              <artifactId > javax.el-api</artifactId >              <version > 2.2.4</version >          </dependency >          <dependency >              <groupId > org.glassfish.web</groupId >              <artifactId > javax.el</artifactId >              <version > 2.2.4</version >          </dependency >               </dependencies >  </project > 
 
创建包 cn.itcast.service
cn.itcast.dao
cn.itcast.domain
创建applicationContext.xml 
Spring整合Jpa就两步
    1.由spring创建entityManagerFactory
    2.使用标签jpa:repositories和spring进行整合
 
提示:该文件应该在java/main/resource目录下
注意修改数据库密码
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 <?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" >         <context:component-scan  base-package ="cn.itcast"  > </context:component-scan >           <bean  id ="dataSource"  class ="com.mchange.v2.c3p0.ComboPooledDataSource" >          <property  name ="user"  value ="root" > </property >          <property  name ="password"  value ="root" > </property >          <property  name ="jdbcUrl"  value ="jdbc:mysql:///jpa"  > </property >          <property  name ="driverClass"  value ="com.mysql.jdbc.Driver" > </property >      </bean >           <bean  id ="transactionManager"  class ="org.springframework.orm.jpa.JpaTransactionManager" >                   <property  name ="entityManagerFactory"  ref ="entityManagerFactoty" > </property >      </bean >      <tx:advice  id ="txAdvice"  transaction-manager ="transactionManager" >          <tx:attributes >              <tx:method  name ="save*"  propagation ="REQUIRED" />              <tx:method  name ="insert*"  propagation ="REQUIRED" />              <tx:method  name ="update*"  propagation ="REQUIRED" />              <tx:method  name ="delete*"  propagation ="REQUIRED" />              <tx:method  name ="get*"  read-only ="true" />              <tx:method  name ="find*"  read-only ="true" />              <tx:method  name ="*"  propagation ="REQUIRED" />          </tx:attributes >      </tx:advice >      <aop:config >          <aop:pointcut  id ="pointcut"  expression ="execution(* cn.itcast.service.*.*(..))"  />          <aop:advisor  advice-ref ="txAdvice"  pointcut-ref ="pointcut"  />      </aop:config >           <bean  id ="entityManagerFactoty"  class ="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" >          <property  name ="dataSource"  ref ="dataSource"  />                   <property  name ="packagesToScan"  value ="cn.itcast.domain"  />                   <property  name ="persistenceProvider" >              <bean  class ="org.hibernate.jpa.HibernatePersistenceProvider" />          </property >                   <property  name ="jpaVendorAdapter" >              <bean  class ="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" >                                   <property  name ="generateDdl"  value ="false"  />                                   <property  name ="database"  value ="MYSQL"  />                                   <property  name ="databasePlatform"  value ="org.hibernate.dialect.MySQLDialect"  />                                   <property  name ="showSql"  value ="true"  />              </bean >          </property >                   <property  name ="jpaDialect"  >              <bean  class ="org.springframework.orm.jpa.vendor.HibernateJpaDialect"  />          </property >          <property  name ="jpaProperties"  >              <props >                  <prop  key ="hibernate.hbm2ddl.auto" > update</prop >              </props >          </property >      </bean >           <jpa:repositories  base-package ="cn.itcast.dao"  transaction-manager-ref ="transactionManager"                         entity-manager-factory-ref ="entityManagerFactoty"  > </jpa:repositories > </beans > 
 
快速入门 创建表cst_customer 
提示:day01已经创建过了
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 USE  `jpa` ;DROP  TABLE  IF  EXISTS  `cst_customer` ;CREATE  TABLE  `cst_customer`  (  `cust_id`  bigint (32 ) NOT  NULL  AUTO_INCREMENT COMMENT  '客户编号(主键)' ,   `cust_name`  varchar (32 ) NOT  NULL  COMMENT  '客户名称(公司名称)' ,   `cust_source`  varchar (32 ) DEFAULT  NULL  COMMENT  '客户信息来源' ,   `cust_industry`  varchar (32 ) DEFAULT  NULL  COMMENT  '客户所属行业' ,   `cust_level`  varchar (32 ) DEFAULT  NULL  COMMENT  '客户级别' ,   `cust_address`  varchar (128 ) DEFAULT  NULL  COMMENT  '客户联系地址' ,   `cust_phone`  varchar (64 ) DEFAULT  NULL  COMMENT  '客户联系电话' ,   PRIMARY KEY  (`cust_id` ) ) ENGINE =InnoDB  DEFAULT  CHARSET =utf8; insert   into  `cst_customer` (`cust_id` ,`cust_name` ,`cust_source` ,`cust_industry` ,`cust_level` ,`cust_address` ,`cust_phone` ) values  (1 ,'黑马程序员' ,NULL ,'教育' ,NULL ,NULL ,NULL ),(2 ,'传智播客' ,NULL ,'教育' ,NULL ,NULL ,NULL ),(3 ,'酷丁鱼' ,NULL ,'教育' ,NULL ,NULL ,NULL ),(4 ,'传智汇' ,NULL ,'教育' ,NULL ,NULL ,NULL ),(5 ,'传智专修学院' ,NULL ,'教育' ,NULL ,NULL ,NULL ),(6 ,'谷歌' ,NULL ,'教育' ,NULL ,NULL ,NULL );
 
创建实体类Customer 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 package  cn.itcast.domain;import  javax.persistence.*;public  class  Customer   {    private  Long custId;      private  String custName;     private  String custSource;     private  String custLevel;     private  String custIndustry;     private  String custPhone;     private  String custAddress;     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 getCustLevel ()   {         return  custLevel;     }     public  void  setCustLevel (String custLevel)   {         this .custLevel = custLevel;     }     public  String getCustIndustry ()   {         return  custIndustry;     }     public  void  setCustIndustry (String custIndustry)   {         this .custIndustry = custIndustry;     }     public  String getCustPhone ()   {         return  custPhone;     }     public  void  setCustPhone (String custPhone)   {         this .custPhone = custPhone;     }     public  String getCustAddress ()   {         return  custAddress;     }     public  void  setCustAddress (String custAddress)   {         this .custAddress = custAddress;     }     @Override      public  String toString ()   {         return  "Customer{"  +                 "custId="  + custId +                 ", custName='"  + custName + '\''  +                 ", custSource='"  + custSource + '\''  +                 ", custLevel='"  + custLevel + '\''  +                 ", custIndustry='"  + custIndustry + '\''  +                 ", custPhone='"  + custPhone + '\''  +                 ", custAddress='"  + custAddress + '\''  +                 '}' ;     } } 
 
通过注解配置映射关系 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 package  cn.itcast.domain;import  javax.persistence.*;@Entity @Table (name = "cst_customer" )public  class  Customer   {    @Id      @GeneratedValue (strategy = GenerationType.IDENTITY)     @Column (name = "cust_id" )     private  Long custId;      @Column (name = "cust_name" )     private  String custName;     @Column (name="cust_source" )     private  String custSource;     @Column (name="cust_level" )     private  String custLevel;     @Column (name="cust_industry" )     private  String custIndustry;     @Column (name="cust_phone" )     private  String custPhone;     @Column (name="cust_address" )     private  String custAddress;     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 getCustLevel ()   {         return  custLevel;     }     public  void  setCustLevel (String custLevel)   {         this .custLevel = custLevel;     }     public  String getCustIndustry ()   {         return  custIndustry;     }     public  void  setCustIndustry (String custIndustry)   {         this .custIndustry = custIndustry;     }     public  String getCustPhone ()   {         return  custPhone;     }     public  void  setCustPhone (String custPhone)   {         this .custPhone = custPhone;     }     public  String getCustAddress ()   {         return  custAddress;     }     public  void  setCustAddress (String custAddress)   {         this .custAddress = custAddress;     }     @Override      public  String toString ()   {         return  "Customer{"  +                 "custId="  + custId +                 ", custName='"  + custName + '\''  +                 ", custSource='"  + custSource + '\''  +                 ", custLevel='"  + custLevel + '\''  +                 ", custIndustry='"  + custIndustry + '\''  +                 ", custPhone='"  + custPhone + '\''  +                 ", custAddress='"  + custAddress + '\''  +                 '}' ;     } } 
 
创建CustomerDao接口 1 2 3 4 5 6 7 8 9 10 11 12 13 package  cn.itcast.dao;import  cn.itcast.domain.Customer;import  org.springframework.data.jpa.repository.JpaRepository;import  org.springframework.data.jpa.repository.JpaSpecificationExecutor;public  interface  CustomerDao  extends  JpaRepository <Customer ,Long >,													JpaSpecificationExecutor <Customer > {} 
 
编写测试类 
需求:查询姓名=李四的用户
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 package  cn.itcast.dao;import  cn.itcast.domain.Customer;import  org.junit.Test;import  org.junit.runner.RunWith;import  org.springframework.beans.factory.annotation.Autowired;import  org.springframework.data.jpa.domain.Specification;import  org.springframework.test.context.ContextConfiguration;import  org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import  javax.persistence.criteria.*;import  java.util.List;@RunWith (SpringJUnit4ClassRunner.class ) @ContextConfiguration (locations   = "classpath:applicationContext.xml" )public  class  CustomerDaoSpecificationTest   {    @Autowired      private  CustomerDao customerDao;          @Test      public  void  findByCustNameQueryTest ()  {                  Customer customer = customerDao.findOne(new  Specification<Customer>() {             @Override                           public  Predicate toPredicate (Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder)   {                                  Path<Object> custName = root.get("custName" );                                  Predicate predicate = criteriaBuilder.equal(custName, "李四" );                 return  predicate;             }         });         System.out.println(customer);     } } 
 
运行结果
 
单条件查询 请查看1.4内容
多条件查询 
需求:查询姓名=李四,电话=1390000000的客户
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 @Test public  void  manyConditionsQueryTest ()  {    Customer customer = customerDao.findOne(new  Specification<Customer>() {         @Override                   public  Predicate toPredicate (Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder)   {                          Predicate p1 = criteriaBuilder.equal(root.get("custName" ), "李四" );                          Predicate p2 = criteriaBuilder.equal(root.get("custPhone" ), "1390000000" );                                                                              Predicate p3 = criteriaBuilder.and(p1, p2);                                       return  p3;         }     });     System.out.println(customer); } 
 
运行结果
 
模糊匹配 种类 模糊匹配有like,>, < ,>=,<=
对应的方法就是like , gt,lt,ge,le
使用步骤 1.从root中获取要操作的属性
2.调用模糊匹配方法,传入两个参数,第一个是path.as(属性的类型.class),第二个是属性值
测试代码 
查询客户名包含传智播客,并且ID>=2的用户
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Test public  void  dimQuery ()  {    Customer cus = customerDao.findOne(new  Specification<Customer>() {         @Override          public  Predicate toPredicate (Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder)   {                          Predicate p1 = criteriaBuilder.like(root.get("custName").as(String.class), "%传智播客%");                          Predicate p2 = criteriaBuilder.ge(root.get("custId" ).as(Long.class ), 2L ) ;                          return  criteriaBuilder.and(p1, p2);         }     });     System.out.println(cus); } 
 
运行结果
 
排序 一个排序条件 
需求:按照ID降序查询
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Test public  void  orderByTest1 ()  {         Sort sort = new  Sort(Sort.Direction.DESC,"custId" );          List<Customer> all = customerDao.findAll(null , sort);     for  (Customer customer : all) {         System.out.println(customer);     } } 
 
运行结果
 
多个排序条件 
按照电话降序排序,如果电话相同按照ID升序排序
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @Test public  void  orderByTest2 ()  {         Sort.Order o1 = new  Sort.Order(Sort.Direction.DESC, "custPhone" );     Sort.Order o2 = new  Sort.Order(Sort.Direction.ASC, "custId" );     ArrayList orders = new  ArrayList();          orders.add(o1);     orders.add(o2);     Sort sort = new  Sort(orders);               List<Customer> all = customerDao.findAll(null , sort);     for  (Customer customer : all) {         System.out.println(customer);     } } 
 
使用CriteriaQuery完成排序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Test public  void  orderTest3 ()  {    List<Customer> all = customerDao.findAll(new  Specification<Customer>() {         @Override          public  Predicate toPredicate (Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb)   {                          query.where(cb.like(root.get("custName").as(String.class),"%传%"));             query.orderBy(cb.desc(root.get("custPhone" )), cb.asc(root.get("custId" )));                          return  query.getRestriction();         }     });     for  (Customer customer : all) {         System.out.println(customer);     } } 
 
运行结果
 
分页 
需求 查询ID=4,5,6的数据
 
代码
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Test public  void  pageTest ()  {              PageRequest pageRequest = new  PageRequest(1 , 3 );     Page<Customer> all = customerDao.findAll(null , pageRequest);     for  (Customer customer : all) {         System.out.println(customer);     } } 
 
运行结果
 
案例 
需求,网页需要一个搜索功能,如果用输入客户名,则可以根据客户名搜索,如果输入电话,则可以根据电话搜索,如果都输入了就根据用户名和电话搜索,问,service层中的方法应该如何实现
 
代码
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 public  List<Customer> search (String custName, String custPhone)  {    List<Customer> customers = customerDao.findAll(new  Specification<Customer>() {         @Override          public  Predicate toPredicate (Root<Customer> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder)   {             List<Predicate> list = new  ArrayList<>();                                       if (custName!=null  && !custName.trim().equals("" )){                 Predicate p = criteriaBuilder.like(root.get("custName").as(String.class), "%" + custName + "%");                 list.add(p);             }                          if (custPhone!=null  && !custPhone.trim().equals("" )){                 Predicate p = criteriaBuilder.like(root.get("custPhone").as(String.class), "%" + custPhone + "%");                 list.add(p);             }                          Predicate p = criteriaBuilder.and(list.toArray(new  Predicate[0 ]));             return  p;         }     });     return  customers; } @Test public  void  searchTest ()  {    List<Customer> customers = search("传" , "1" );     for  (Customer customer : customers) {         System.out.println(customer);     } } 
 
运行结果
 
多表查询 一对多和多对一 需求 一个Customer[这里用户表示公司]对应多个联系人
创建表 
为了避免和之前的数据产生冲突,在讲多表查询的时候表名和实体类名后面都会加数字进行区分
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 DROP  TABLE  IF  EXISTS  `cst_customer2` ;CREATE  TABLE  `cst_customer2`  (  `cust_id`  bigint (32 ) NOT  NULL  AUTO_INCREMENT COMMENT  '客户编号(主键)' ,   `cust_name`  varchar (32 ) NOT  NULL  COMMENT  '客户名称(公司名称)' ,   `cust_source`  varchar (32 ) DEFAULT  NULL  COMMENT  '客户信息来源' ,   `cust_industry`  varchar (32 ) DEFAULT  NULL  COMMENT  '客户所属行业' ,   `cust_level`  varchar (32 ) DEFAULT  NULL  COMMENT  '客户级别' ,   `cust_address`  varchar (128 ) DEFAULT  NULL  COMMENT  '客户联系地址' ,   `cust_phone`  varchar (64 ) DEFAULT  NULL  COMMENT  '客户联系电话' ,   PRIMARY KEY  (`cust_id` ) ) ENGINE =InnoDB  AUTO_INCREMENT=117  DEFAULT  CHARSET =utf8; DROP  TABLE  IF  EXISTS  `cst_linkman2` ;CREATE  TABLE  `cst_linkman2`  (  `lkm_id`  bigint (32 ) NOT  NULL  AUTO_INCREMENT COMMENT  '联系人编号(主键)' ,   `lkm_name`  varchar (16 ) DEFAULT  NULL  COMMENT  '联系人姓名' ,   `lkm_gender`  char (1 ) DEFAULT  NULL  COMMENT  '联系人性别' ,   `lkm_phone`  varchar (16 ) DEFAULT  NULL  COMMENT  '联系人办公电话' ,   `lkm_mobile`  varchar (16 ) DEFAULT  NULL  COMMENT  '联系人手机' ,   `lkm_email`  varchar (64 ) DEFAULT  NULL  COMMENT  '联系人邮箱' ,   `lkm_position`  varchar (16 ) DEFAULT  NULL  COMMENT  '联系人职位' ,   `lkm_memo`  varchar (512 ) DEFAULT  NULL  COMMENT  '联系人备注' ,   `lkm_cust_id`  bigint (32 ) DEFAULT  NULL  COMMENT  '客户id(外键)' ,   PRIMARY KEY  (`lkm_id` ),   KEY  `FK_cst_linkman_lkm_cust_id`  (`lkm_cust_id` ) ) ENGINE =InnoDB  AUTO_INCREMENT=23  DEFAULT  CHARSET =utf8; 
 
创建实体类及映射关系 
客户
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 package  cn.itcast.domain;import  javax.persistence.*;import  java.util.HashSet;import  java.util.Set;@Entity @Table (name="cst_customer2" )public  class  Customer2   {    @Id      @GeneratedValue (strategy = GenerationType.IDENTITY)     @Column (name="cust_id" )     private  Long custId;     @Column (name="cust_address" )     private  String custAddress;     @Column (name="cust_industry" )     private  String custIndustry;     @Column (name="cust_level" )     private  String custLevel;     @Column (name="cust_name" )     private  String custName;     @Column (name="cust_phone" )     private  String custPhone;     @Column (name="cust_source" )     private  String custSource;     public  Long getCustId ()   {         return  custId;     }     public  void  setCustId (Long custId)   {         this .custId = custId;     }     public  String getCustAddress ()   {         return  custAddress;     }     public  void  setCustAddress (String custAddress)   {         this .custAddress = custAddress;     }     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 getCustName ()   {         return  custName;     }     public  void  setCustName (String custName)   {         this .custName = custName;     }     public  String getCustPhone ()   {         return  custPhone;     }     public  void  setCustPhone (String custPhone)   {         this .custPhone = custPhone;     }     public  String getCustSource ()   {         return  custSource;     }     public  void  setCustSource (String custSource)   {         this .custSource = custSource;     }          @Override      public  String toString ()   {         return  "Customer{"  +                 "custId="  + custId +                 ", custAddress='"  + custAddress + '\''  +                 ", custIndustry='"  + custIndustry + '\''  +                 ", custLevel='"  + custLevel + '\''  +                 ", custName='"  + custName + '\''  +                 ", custPhone='"  + custPhone + '\''  +                 ", custSource='"  + custSource + '\''  +                 '}' ;     } } 
 
联系人
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 package  cn.itcast.domain;import  javax.persistence.*;@Entity @Table (name = "cst_linkman2" )public  class  LinkMan2   {    @Id      @GeneratedValue (strategy = GenerationType.IDENTITY)     @Column (name = "lkm_id" )     private  Long lkmId;      @Column (name = "lkm_name" )     private  String lkmName;     @Column (name = "lkm_gender" )     private  String lkmGender;     @Column (name = "lkm_phone" )     private  String lkmPhone;     @Column (name = "lkm_mobile" )     private  String lkmMobile;     @Column (name = "lkm_email" )     private  String lkmEmail;     @Column (name = "lkm_position" )     private  String lkmPosition;     @Column (name = "lkm_memo" )     private  String lkmMemo;     public  Long getLkmId ()   {         return  lkmId;     }     public  void  setLkmId (Long lkmId)   {         this .lkmId = lkmId;     }     public  String getLkmName ()   {         return  lkmName;     }     public  void  setLkmName (String lkmName)   {         this .lkmName = lkmName;     }     public  String getLkmGender ()   {         return  lkmGender;     }     public  void  setLkmGender (String lkmGender)   {         this .lkmGender = lkmGender;     }     public  String getLkmPhone ()   {         return  lkmPhone;     }     public  void  setLkmPhone (String lkmPhone)   {         this .lkmPhone = lkmPhone;     }     public  String getLkmMobile ()   {         return  lkmMobile;     }     public  void  setLkmMobile (String lkmMobile)   {         this .lkmMobile = lkmMobile;     }     public  String getLkmEmail ()   {         return  lkmEmail;     }     public  void  setLkmEmail (String lkmEmail)   {         this .lkmEmail = lkmEmail;     }     public  String getLkmPosition ()   {         return  lkmPosition;     }     public  void  setLkmPosition (String lkmPosition)   {         this .lkmPosition = lkmPosition;     }     public  String getLkmMemo ()   {         return  lkmMemo;     }     public  void  setLkmMemo (String lkmMemo)   {         this .lkmMemo = lkmMemo;     }     @Override      public  String toString ()   {         return  "LinkMan{"  +                 "lkmId="  + lkmId +                 ", lkmName='"  + lkmName + '\''  +                 ", lkmGender='"  + lkmGender + '\''  +                 ", lkmPhone='"  + lkmPhone + '\''  +                 ", lkmMobile='"  + lkmMobile + '\''  +                 ", lkmEmail='"  + lkmEmail + '\''  +                 ", lkmPosition='"  + lkmPosition + '\''  +                 ", lkmMemo='"  + lkmMemo + '\''  +                 '}' ;     } } 
 
一对多关系配置及测试 
使用一对多的好处:
    通过一的一方可以直接获取多的一方
    保存一的一方的时候多的一方也会被顺便保存
具体使用方式请查看测试类
 
1、说明
 
客户是一的一方
联系人是多的一方
 2.在客户实体类(Customer2)中添加集合属性,存储所有的联系人
 
1 2 3 4 5 6 7 8 9 private  Set<LinkMan2> linkMan2s = new  HashSet<>();public  Set<LinkMan2> getLinkMan2s ()   {    return  linkMan2s; } public  void  setLinkMan2s (Set<LinkMan2> linkMan2s)   {    this .linkMan2s = linkMan2s; } 
 
3.配置映射关系·
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 @OneToMany (targetEntity = LinkMan2.class ) @JoinColumn (name  ="lkm_cust_id" ,referencedColumnName = "cust_id" )private  Set<LinkMan2> linkMan2s = new  HashSet<>();public  Set<LinkMan2> getLinkMan2s ()   {    return  linkMan2s; } public  void  setLinkMan2s (Set<LinkMan2> linkMan2s)   {    this .linkMan2s = linkMan2s; } 
 
4.创建Dao接口
 
1 2 3 4 5 6 7 8 9 package  cn.itcast.dao;import  cn.itcast.domain.Customer;import  cn.itcast.domain.Customer2;import  org.springframework.data.jpa.repository.JpaRepository;import  org.springframework.data.jpa.repository.JpaSpecificationExecutor;public  interface  CustomerDao2  extends  JpaRepository <Customer2 ,Long >,JpaSpecificationExecutor <Customer2 >  {} 
 
1 2 public  interface  LinkManDao2  extends  JpaRepository <LinkMan2 ,Long >,JpaSpecificationExecutor <LinkMan2 >  {} 
 
5.测试
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 package  cn.itcast.dao;import  cn.itcast.domain.Customer2;import  cn.itcast.domain.LinkMan2;import  org.junit.Test;import  org.junit.runner.RunWith;import  org.springframework.beans.factory.annotation.Autowired;import  org.springframework.test.annotation.Rollback;import  org.springframework.test.context.ContextConfiguration;import  org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import  org.springframework.transaction.annotation.Transactional;import  java.util.ArrayList;import  java.util.HashSet;import  java.util.List;import  java.util.Set;@RunWith (SpringJUnit4ClassRunner.class ) @ContextConfiguration (locations   = "classpath:applicationContext.xml" )public  class  One2ManyTest   {    @Autowired      private  CustomerDao2 customerDao2 ;     @Autowired      private  LinkManDao2 linkManDao2;     @Test      @Transactional      @Rollback (false )          public  void  add ()  {         LinkMan2 lm1 = new  LinkMan2();         lm1.setLkmEmail("kefuA@foxmail.com" );         lm1.setLkmGender("男" );         lm1.setLkmMobile("110" );         lm1.setLkmName("客服A" );         LinkMan2 lm2 = new  LinkMan2();         lm2.setLkmEmail("kefuB@foxmail.com" );         lm2.setLkmGender("女" );         lm2.setLkmMobile("119" );         lm2.setLkmName("客服B" );         Customer2 customer2 = new  Customer2();         customer2.setCustName("JACK" );         customer2.getLinkMan2s().add(lm1);         customer2.getLinkMan2s().add(lm2);         customerDao2.save(customer2);                           linkManDao2.save(lm1);         linkManDao2.save(lm2);     } } 
 
运行结果
 
多对一关系配置及测试 
1.说明
 
客户(Customer2)[主表]是一的一方
联系人(LinkMan2)[副表]是多的一方
我们需要在多的一方中配置关系
2.在LinkMan2中添加属性CUstomer2
 
1 2 3 4 5 6 7 8 9 private  Customer2 customer2;public  Customer2 getCustomer2 ()   {	return  customer2; } public  void  setCustomer2 (Customer2 customer2)   {	this .customer2 = customer2; } 
 
3.添加映射关系
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @ManyToOne (targetEntity = Customer2.class ) @JoinColumn (name  ="lkm_cust_id" ,referencedColumnName = "cust_id" )private  Customer2 customer2;public  Customer2 getCustomer2 ()   {	return  customer2; } public  void  setCustomer2 (Customer2 customer2)   {	this .customer2 = customer2; } 
 
4.测试
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 package  cn.itcast.dao;import  cn.itcast.domain.Customer2;import  cn.itcast.domain.LinkMan2;import  org.junit.Test;import  org.junit.runner.RunWith;import  org.springframework.beans.factory.annotation.Autowired;import  org.springframework.test.annotation.Rollback;import  org.springframework.test.context.ContextConfiguration;import  org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import  org.springframework.transaction.annotation.Transactional;import  java.util.List;@RunWith (SpringJUnit4ClassRunner.class ) @ContextConfiguration (locations   = "classpath:applicationContext.xml" )public  class  Many2OneTest   {    @Autowired      private  CustomerDao2 customerDao2;     @Autowired      private  LinkManDao2 linkManDao2;     @Test      public  void  findAllTest ()  {         List<LinkMan2> all = linkManDao2.findAll();         for  (LinkMan2 linkMan2 : all) {             Customer2 customer2 = linkMan2.getCustomer2();             System.out.println(customer2);         }     }     @Test      @Transactional      @Rollback (false )     public  void  addTest ()  {         LinkMan2 lm = new  LinkMan2();         lm.setLkmEmail("kefuB@foxmail.com" );         lm.setLkmGender("女" );         lm.setLkmMobile("119" );         lm.setLkmName("客服BBBB" );         Customer2 customer2 = new  Customer2();         customer2.setCustName("JACKBBB" );         lm.setCustomer2(customer2);         customerDao2.save(customer2);         linkManDao2.save(lm);     } } 
 
运行结果
 
放弃关系维护 
为什么要放弃关系维护
 
在多对一的情况下保存用户和客户只需要2条SQL,都是INSERT
在一对多的情况下保存用户和客户需要3条SQL语句,2条INSERT,1条UPDATE
如果双向一对多的情况下,可能会出现一下情况
问题代码
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 package  cn.itcast.dao;import  cn.itcast.domain.Customer2;import  cn.itcast.domain.LinkMan2;import  org.junit.Test;import  org.junit.runner.RunWith;import  org.springframework.beans.factory.annotation.Autowired;import  org.springframework.test.annotation.Rollback;import  org.springframework.test.context.ContextConfiguration;import  org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import  org.springframework.transaction.annotation.Transactional;@RunWith (SpringJUnit4ClassRunner.class ) @ContextConfiguration (locations   = "classpath:applicationContext.xml" )public  class  ManyToOne2   {    @Autowired      private  CustomerDao2 customerDao2 ;     @Autowired      private  LinkManDao2 linkManDao2;     @Test      @Transactional      @Rollback (false )     public  void  addTest ()  {         LinkMan2 linkMan = new  LinkMan2();         linkMan.setLkmEmail("郝美丽@foxmail.com" );         linkMan.setLkmGender("女" );         linkMan.setLkmMobile("10086" );         linkMan.setLkmName("郝美丽" );         Customer2 customer = new  Customer2();         customer.setCustName("客户" );                  linkMan.setCustomer2(customer);                  customer.getLinkMan2s().add(linkMan);         customerDao2.save(customer);         linkManDao2.save(linkMan);     } } 
 
执行结果
 
问题
 
上面代码两个实体类都在维护关系,如果由联系人维护只需要执行2条SQL,如果有客户联系只需要执行3条SQL。运行后发现执行了3条SQL,说明是有客户实体类维护关系的,如果可以由联系人实体类维护关系岂不是更好。
解决办法
 
其中一个实体类放弃关系的维护,最好客户实体类放弃,因为联系人维护关系可以少执行一条SQL语句
修改客户实体类的OneToMany注解,并删除@JoinColumn注解,代码如下
1 2 3 @OneToMany (mappedBy = "customer2" )private  Set<LinkMan2> linkMan2s = new  HashSet<>();
 
级联操作 
概念
 
操作一个实体类对象的同时会操作另一个实体类。
注意事项
 
1.级联操作一定明确操作主体
2.明确了操作主体后,需要在操作主体上指明允许级联操作
    操作方式:在@OnetToMany、@ManyToOne、@ManyToMany注解中添加属性cascade = CascadeType.ALL
    cascade 属性说明
        定义源实体 和关联的目标实体 间的级联关系。当对源实体 进行操作时,是否对关联的目标实体 也做相同的操作。默认没有级联操作。该参数的可选值有:CascadeType.PERSIST(级联新建)CascadeType.REMOVE(级联删除)CascadeType.REFRESH(级联刷新)CascadeType.MERGE(级联更新)CascadeType.ALL(包含以上四项)
级联保存 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 @Test    @Transactional     @Rollback (false )        public  void  add ()  {       LinkMan2 lm1 = new  LinkMan2();        lm1.setLkmEmail("kefuA@foxmail.com" );        lm1.setLkmGender("男" );        lm1.setLkmMobile("110" );        lm1.setLkmName("客服A" );        LinkMan2 lm2 = new  LinkMan2();        lm2.setLkmEmail("kefuB@foxmail.com" );        lm2.setLkmGender("女" );        lm2.setLkmMobile("119" );        lm2.setLkmName("客服B" );        Customer2 customer2 = new  Customer2();        customer2.setCustName("JACK" );                customer2.getLinkMan2s().add(lm1);        customer2.getLinkMan2s().add(lm2);                lm1.setCustomer2(customer2);        lm2.setCustomer2(customer2);                        customer2Dao.save(customer2);    } 
 
级联删除 1 2 3 4 5 6 7 8 9 @Test @Transactional @Rollback (false )public  void  delete ()  {    Customer2 c = customerDao2.findOne(13L );          customerDao2.delete(c); } 
 
多对多 需求 一个用户(User)对应多个角色(Role)
一个角色(Role)可以对应多个用户(User)
创建表 这里不手动创建了,直接由框架自己生成表
编写实体类及映射关系 
用户
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 package  cn.itcast.domain;import  javax.persistence.*;import  java.util.HashSet;import  java.util.Set;@Entity @Table (name = "sys_role" )public  class  Role   {    @Id      @GeneratedValue (strategy = GenerationType.IDENTITY)     @Column (name = "role_id" )     private  Long roleId;     @Column (name = "role_name" )     private  String roleName;     public  Long getRoleId ()   {         return  roleId;     }     public  void  setRoleId (Long roleId)   {         this .roleId = roleId;     }     public  String getRoleName ()   {         return  roleName;     }     public  void  setRoleName (String roleName)   {         this .roleName = roleName;     }      } 
 
角色
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 package  cn.itcast.domain;import  javax.persistence.*;import  java.util.HashSet;import  java.util.Set;@Entity @Table (name = "sys_user" )public  class  User   {    @Id      @GeneratedValue (strategy = GenerationType.IDENTITY)     @Column (name="user_id" )     private  Long userId;     @Column (name="user_name" )     private  String userName;     @Column (name="age" )     private  Integer age;     public  Long getUserId ()   {         return  userId;     }     public  void  setUserId (Long userId)   {         this .userId = userId;     }     public  String getUserName ()   {         return  userName;     }     public  void  setUserName (String userName)   {         this .userName = userName;     }     public  Integer getAge ()   {         return  age;     }     public  void  setAge (Integer age)   {         this .age = age;     } } 
 
多对多关系配置
 
1.给用户实体类(User)添加属性及映射关系
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 @ManyToMany (targetEntity = Role.class ,cascade   = CascadeType.ALL)@JoinTable (    	name = "sys_user_role" ,                  joinColumns = {             @JoinColumn (name = "sys_user_id" ,referencedColumnName = "user_id" )         },                  inverseJoinColumns = {             @JoinColumn (name = "sys_role_id" ,referencedColumnName = "role_id" )         } ) private  Set<Role> roles = new  HashSet<>();public  Set<Role> getRoles ()   {    return  roles; } public  void  setRoles (Set<Role> roles)   {    this .roles = roles; } 
 
2.角色(Role)实体类添加属性及映射关系
关系由用户维护就好了,所以在角色实体类中用mapppedBy
 
1 2 3 4 5 6 7 8 9 10 @ManyToMany (mappedBy = "roles" )  private  Set<User> users = new  HashSet<>();public  Set<User> getUsers ()   {    return  users; } public  void  setUsers (Set<User> users)   {    this .users = users; } 
 
编写接口 
UserDao
 
1 2 3 4 5 6 7 8 package  cn.itcast.dao;import  cn.itcast.domain.User;import  org.springframework.data.jpa.repository.JpaRepository;import  org.springframework.data.jpa.repository.JpaSpecificationExecutor;public  interface  UserDao  extends  JpaRepository <User ,Long >,JpaSpecificationExecutor <User >  {} 
 
RoleDao
 
1 2 3 4 5 6 7 8 9 package  cn.itcast.dao;import  cn.itcast.domain.Role;import  cn.itcast.domain.User;import  org.springframework.data.jpa.repository.JpaRepository;import  org.springframework.data.jpa.repository.JpaSpecificationExecutor;public  interface  RoleDao  extends  JpaRepository <Role ,Long > ,JpaSpecificationExecutor <Role >  {} 
 
级联保存 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 package  cn.itcast.dao;import  cn.itcast.domain.Role;import  cn.itcast.domain.User;import  org.junit.Test;import  org.junit.runner.RunWith;import  org.springframework.beans.factory.annotation.Autowired;import  org.springframework.test.context.ContextConfiguration;import  org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith (SpringJUnit4ClassRunner.class ) @ContextConfiguration (locations   = "classpath:applicationContext.xml" )public  class  Many2ManyTest   {    @Autowired      private  UserDao userDao;     @Autowired      private  RoleDao roleDao;     @Test      public  void  addTest ()  {         Role role = new  Role();         role.setRoleName("管理员" );         User user = new  User();         user.setAge(13 );         user.setUserName("老王" );                  user.getRoles().add(role);         userDao.save(user);     } } 
 
运行结果
 
级联删除 1 2 3 4 5 6 @Test public  void  deleteTest ()  {    User user = userDao.findOne(1L );     userDao.delete(user); } 
 
运行结果
 
级联查询(对象导航查询) 1 2 3 4 5 6 7 8 @Test    public  void  findTest ()  {        User user = userDao.findOne(2L );        Set<Role> roles = user.getRoles();        for  (Role role : roles) {            System.out.println(role.getRoleName());        }    } 
 
报错
 
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role:
解决方案1:在User实体类的@ManyToMany注解中添加值fetch
 
1 @ManyToMany(targetEntity = Role.class,cascade = CascadeType.ALL,fetch = FetchType.EAGER) 
 
解决方案2:在junit测试方法findTest()上加@Transactional
 
一对多关系对象查询总结 通过一的一方查询多的一方默认是延迟查询,因为多的一方可能数据非常多,浪费时间,浪费内存
通过多的一方查询一的一方默认是立即查询,因为一的一方就一条数据,性能可以忽略不计
推荐:使用默认设置,如果使用默认设置,在进行对象查询的时候可能会报org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role:,原因是事务关闭了,我们需要加@Transactional