• SpringDataJpa基础知识


    一、Spring Data JPA 为此提供了一些表达条件查询的关键字

     1 And --- 等价于 SQL 中的 and 关键字,比如 findByUsernameAndPassword(String user, Striang pwd);
     2 Or --- 等价于 SQL 中的 or 关键字,比如 findByUsernameOrAddress(String user, String addr);
     3 Between --- 等价于 SQL 中的 between 关键字,比如 findBySalaryBetween(int max, int min);
     4 LessThan --- 等价于 SQL 中的 "<",比如 findBySalaryLessThan(int max);
     5 GreaterThan --- 等价于 SQL 中的">",比如 findBySalaryGreaterThan(int min);
     6 IsNull --- 等价于 SQL 中的 "is null",比如 findByUsernameIsNull();
     7 IsNotNull --- 等价于 SQL 中的 "is not null",比如 findByUsernameIsNotNull();
     8 NotNull --- 与 IsNotNull 等价;
     9 Like --- 等价于 SQL 中的 "like",比如 findByUsernameLike(String user);
    10 NotLike --- 等价于 SQL 中的 "not like",比如 findByUsernameNotLike(String user);
    11 OrderBy --- 等价于 SQL 中的 "order by",比如 findByUsernameOrderBySalaryAsc(String user);
    12 Not --- 等价于 SQL 中的 "! =",比如 findByUsernameNot(String user);
    13 In --- 等价于 SQL 中的 "in",比如 findByUsernameIn(Collection<String> userList) ,方法的参数可以是 Collection 类型,也可以是数组或者不定长参数;
    14 NotIn --- 等价于 SQL 中的 "not in",比如 findByUsernameNotIn(Collection<String> userList) ,方法的参数可以是 Collection 类型,也可以是数组或者不定长参数;

    二、使用 @Query 创建查询

    @Query 注解的使用非常简单,只需在声明的方法上面标注该注解,同时提供一个 JP QL 查询语句即可,如下所示:

    1 public interface UserDao extends Repository<AccountInfo, Long> { 
    2  
    3 @Query("select a from AccountInfo a where a.accountId = ?1") 
    4 public AccountInfo findByAccountId(Long accountId); 
    5  
    6    @Query("select a from AccountInfo a where a.balance > ?1") 
    7 public Page<AccountInfo> findByBalanceGreaterThan( 
    8 Integer balance,Pageable pageable); 
    9 }

    很多开发者在创建 JP QL 时喜欢使用命名参数来代替位置编号,@Query 也对此提供了支持。JP QL 语句中通过": 变量"的格式来指定参数,同时在方法的参数前面使用 @Param 将方法参数与 JP QL 中的命名参数对应,示例如下:

     1 public interface UserDao extends Repository<AccountInfo, Long> { 
     2  
     3 public AccountInfo save(AccountInfo accountInfo); 
     4  
     5 @Query("from AccountInfo a where a.accountId = :id") 
     6 public AccountInfo findByAccountId(@Param("id")Long accountId); 
     7  
     8   @Query("from AccountInfo a where a.balance > :balance") 
     9   public Page<AccountInfo> findByBalanceGreaterThan( 
    10 @Param("balance")Integer balance,Pageable pageable); 
    11 }

    此外,开发者也可以通过使用 @Query 来执行一个更新操作,为此,我们需要在使用 @Query 的同时,用 @Modifying 来将该操作标识为修改查询,这样框架最终会生成一个更新的操作,而非查询。如下所示:

    1 @Modifying 
    2 @Query("update AccountInfo a set a.salary = ?1 where a.salary < ?2") 
    3 public int increaseSalary(int after, int before);

    三、SpringData-懒加载的作用和应用场景

    预期:
         启用懒加载后,对Student表取数,不会自动带出Course集合
         当student1.getCourse()使用集合时,再执行Student取数
    作用:
         当不需要使用Course集合引用时,不会执行多余的查询,提升效率
    

    四、springdataJpa复杂查询

    package bidding.model.specification;
    
    
    import bidding.model.dto.BiddingSupplierOrderManagerModelDto;
    import bidding.model.po.JcbdBdProvider;
    import bidding.model.po.JcbdBidding;
    import bidding.model.po.JcbdBiddingOrderItem;
    import bidding.model.po.JcbdMallOrder;
    import lombok.Data;
    import org.springframework.data.jpa.domain.Specification;
    import utils.Lang;
    import utils.string.StringUtils;
    
    import javax.persistence.criteria.*;
    import java.util.ArrayList;
    import java.util.List;
    /**
    * @date 2018/4/14
    */
    @Data
    public class BiddingSupplierOrderManagerSpecification<T> implements Specification<T>{
    
        private BiddingSupplierOrderManagerModelDto biddingSupplierOrderManagerModelDto;
    
        public BiddingSupplierOrderManagerSpecification() {
        }
    
        public BiddingSupplierOrderManagerSpecification(BiddingSupplierOrderManagerModelDto biddingSupplierOrderManagerModelDto) {
            this.biddingSupplierOrderManagerModelDto = biddingSupplierOrderManagerModelDto;
        }
    
        @Override
        public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) {
            List<Predicate> predicates = new ArrayList<>();
            predicates.add(cb.equal(root.get("isDelete"), false));
            predicates.add(cb.isNotNull(root.get("supplierOrderStatus")));
            if (!StringUtils.isEmpty(biddingSupplierOrderManagerModelDto.getProviderId()) && !biddingSupplierOrderManagerModelDto.getProviderId().isEmpty()) {
                predicates.add(cb.equal(root.get("providerId"), biddingSupplierOrderManagerModelDto.getProviderId()));
            }
            if (!StringUtils.isEmpty(biddingSupplierOrderManagerModelDto.getBiddingCode()) && !biddingSupplierOrderManagerModelDto.getBiddingCode().isEmpty()) {
                predicates.add(cb.equal(root.get("jcbdOrder").get("jcbdBidding").get("biddingCode"), biddingSupplierOrderManagerModelDto.getBiddingCode()));
            }
            if (!StringUtils.isEmpty(biddingSupplierOrderManagerModelDto.getGoodsCode()) && !biddingSupplierOrderManagerModelDto.getGoodsCode().isEmpty()) {
                Join<JcbdMallOrder, JcbdBiddingOrderItem> biddingJoin = root.join("jcbdBiddingOrderItems",JoinType.INNER);
                predicates.add(cb.equal(biddingJoin.get("sku"), biddingSupplierOrderManagerModelDto.getGoodsCode()));
            }
            if (!Lang.isEmpty(biddingSupplierOrderManagerModelDto.getStatus())) {
                predicates.add(cb.equal(root.get("supplierOrderStatus"), biddingSupplierOrderManagerModelDto.getStatus()));
            }
            if (biddingSupplierOrderManagerModelDto.getOrderStartTime() != null) {
                predicates.add(cb.greaterThanOrEqualTo(root.get("dateCreated"), biddingSupplierOrderManagerModelDto.getOrderStartTime()));
            }
            if (biddingSupplierOrderManagerModelDto.getOrderEndTime() != null) {
                predicates.add(cb.lessThanOrEqualTo(root.get("dateCreated"), biddingSupplierOrderManagerModelDto.getOrderEndTime()));
            }
    
            return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
        }
    }
    package bidding.model.po;
    
    import bidding.model.po.base.BaseDomain;
    import com.alibaba.fastjson.annotation.JSONField;
    import org.hibernate.annotations.GenericGenerator;
    import javax.persistence.*;
    import java.io.Serializable;
    import java.util.Date;
    import java.util.List;
    
    /**
     * @version 0.9 竞价采购实物商城订单表 2018-3-7 14:31:21.
     */
    
    @Entity
    public class JcbdMallOrder extends BaseDomain implements Serializable {
    
        /**
         * 主键.
         */
        @Id
        @GenericGenerator(name = "PKUUID", strategy = "uuid2")
        @GeneratedValue(generator = "PKUUID")
        private String id;
    
        /**
         * 竞价id.
         */
        @ManyToOne
        @JoinColumn(name = "JCBD_ORDER_ID", foreignKey = @ForeignKey(name = "FK_BIDDING_MALL_ORDER"))
        private JcbdOrder jcbdOrder;
    
        @OneToMany(mappedBy = "jcbdMallOrder",fetch = FetchType.LAZY,cascade = CascadeType.ALL)
        List<JcbdBiddingOrderItem> jcbdBiddingOrderItems;   ..........
    }package bidding.model.po;import bidding.model.po.base.BaseDomain;
    import org.hibernate.annotations.GenericGenerator;
    
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Id;
    import javax.persistence.ManyToOne;
    
    /**
     * 竞价订单商品项表
     *
     * @author torvalds on 2018/4/24 21:36.
     * @version 1.0
     */
    @Entity
    public class JcbdBiddingOrderItem extends BaseDomain {
        /**
         * 主键.
         */
        @Id
        @GenericGenerator(name = "PKUUID", strategy = "uuid2")
        @GeneratedValue(generator = "PKUUID")
        private String id;
    @ManyToOne
    private JcbdMallOrder jcbdMallOrder;
    private String sku;
    .......... }

     五、JPA注解介绍

    JPA 注解的几个要点 

    1.设置Pojo为实体 

    1 @Entity //标识这个pojo是一个jpa实体     
    2 public class Users implements Serializable {     
    3 }    

    2.设置表名

    1 @Entity     
    2 @Table(name = "users") //指定表名为users     
    3 public class Users implements Serializable {     
    4 }    

    3.设置主键

    1 public class Users implements Serializable {     
    2 @Id     
    3 private String userCode;    

    4. 设置字段类型 

     1 通过@Column注解设置,包含的设置如下 
     2 name:字段名 
     3 unique:是否唯一 
     4 nullable:是否可以为空 
     5 inserttable:是否可以插入 
     6 updateable:是否可以更新 
     7 columnDefinition: 定义建表时创建此列的DDL 
     8 secondaryTable: 从表名。如果此列不建在主表上(默认建在主表),该属性定义该列所在从表的名字。 
     9 
    10 @Column(name = "user_code", nullable = false, length=32)//设置属性userCode对应的字段为user_code,长度为32,非空     
    11 private String userCode;     
    12 @Column(name = "user_wages", nullable = true, precision=12, scale=2)//设置属性wages对应的字段为user_wages,12位数字可保留两位小数,可以为空     
    13 private double wages;     
    14 @Temporal(TemporalType.DATE)//设置为时间类型     
    15 private Date joinDate;    

    5.字段排序

    在加载数据的时候可以为其指定顺序,使用@OrderBy注解实现 

    1 @Table(name = "USERS")     
    2 public class User {     
    3 @OrderBy(name = "group_name ASC, name DESC")     
    4 private List books = new ArrayList();     
    5 }    

    6.主键生成策略 

     1 public class Users implements Serializable {     
     2 @Id     
     3 @GeneratedValue(strategy=GenerationType.IDENTITY)//主键自增,注意,这种方式依赖于具体的数据库,如果数据库不支持自增主键,那么这个类型是没法用的     
     4 @Column(name = "user_id", nullable = false)     
     5 private int userId;     
     6    
     7    
     8 public class Users implements Serializable {     
     9 @Id     
    10 @GeneratedValue(strategy=GenerationType.TABLE)//通过一个表来实现主键id的自增,这种方式不依赖于具体的数据库,可以解决数据迁移的问题     
    11 @Column(name = "user_code", nullable = false)     
    12 private String userCode;     
    13    
    14    
    15 public class Users implements Serializable {     
    16 @Id     
    17 @GeneratedValue(strategy=GenerationType.SEQUENCE)//通过Sequence来实现表主键自增,这种方式依赖于数据库是否有SEQUENCE,如果没有就不能用     
    18 @SequenceGenerator(name="seq_user")     
    19 @Column(name = "user_id", nullable = false)     
    20 private int userId;    

    7.一对多映射关系 

    有T_One和T_Many两个表,他们是一对多的关系,注解范例如下 
    主Pojo 

     1 @Entity     
     2 @Table(name = "T_ONE")     
     3 public class One implements Serializable {     
     4 private static final long serialVersionUID = 1L;     
     5 @Id     
     6 @Column(name = "ONE_ID", nullable = false)     
     7 private String oneId;     
     8 @Column(name = "DESCRIPTION")     
     9 private String description;     
    10 @OneToMany(cascade = CascadeType.ALL, mappedBy = "oneId")//指向多的那方的pojo的关联外键字段     
    11 private Collection<Many> manyCollection;     

    子Pojo 

     1 @Entity     
     2 @Table(name = "T_MANY")     
     3 public class Many implements Serializable {     
     4 private static final long serialVersionUID = 1L;     
     5 @Id     
     6 @Column(name = "MANY_ID", nullable = false)     
     7 private String manyId;     
     8 @Column(name = "DESCRIPTION")     
     9 private String description;     
    10    
    11 @JoinColumn(name = "ONE_ID", referencedColumnName = "ONE_ID")//设置对应数据表的列名和引用的数据表的列名     
    12 @ManyToOne//设置在“一方”pojo的外键字段上     
    13 private One oneId;     

    8.多对多映射关系 

    貌似多对多关系不需要设置级联,以前用hibernate的时候着实为多对多的级联头疼了一阵子,JPA的多对多还需要实际的尝试一下才能有所体会。 
    估计JPA的多对多也是可以转换成两个一对多的。 
    第一个Pojo 

     1 @Entity     
     2 @Table(name = "T_MANYA")     
     3 public class ManyA implements Serializable {     
     4 private static final long serialVersionUID = 1L;     
     5 @Id     
     6 @Column(name = "MANYA_ID", nullable = false)     
     7 private String manyaId;     
     8 @Column(name = "DESCRIPTION")     
     9 private String description;     
    10 @ManyToMany     
    11 @JoinTable(name = "TMANY1_TMANY2", joinColumns = {@JoinColumn(name = "MANYA_ID", referencedColumnName = "MANYA_ID")}, inverseJoinColumns = {@JoinColumn(name = "MANYB_ID", referencedColumnName = "MANYB_ID")})     
    12 private Collection<ManyB> manybIdCollection;     

    第二个Pojo 

     1 @Entity     
     2 @Table(name = "T_MANYB")     
     3 public class ManyB implements Serializable {     
     4 private static final long serialVersionUID = 1L;     
     5 @Id     
     6 @Column(name = "MANYB_ID", nullable = false)     
     7 private String manybId;     
     8 @Column(name = "DESCRIPTION")     
     9 private String description;     
    10 @ManyToMany(mappedBy = "manybIdCollection")     
    11 private Collection<ManyA> manyaIdCollection;     

    9.一对一映射关系 

    主Pojo

     1 @Entity     
     2 @Table(name = "T_ONEA")     
     3 public class OneA implements Serializable {     
     4 private static final long serialVersionUID = 1L;     
     5 @Id     
     6 @Column(name = "ONEA_ID", nullable = false)     
     7 private String oneaId;     
     8 @Column(name = "DESCRIPTION")     
     9 private String description;     
    10 @OneToOne(cascade = CascadeType.ALL, mappedBy = "oneA")//主Pojo这方的设置比较简单,只要设置好级联和映射到从Pojo的外键就可以了。     
    11 private OneB oneB;   

    从Pojo 

     1 @Entity     
     2 @Table(name = "T_ONEB")     
     3 public class OneB implements Serializable {     
     4 private static final long serialVersionUID = 1L;     
     5 @Id     
     6 @Column(name = "ONEA_ID", nullable = false)     
     7 private String oneaId;     
     8 @Column(name = "DESCRIPTION")     
     9 private String description;     
    10 @JoinColumn(name = "ONEA_ID", referencedColumnName = "ONEA_ID", insertable = false, updatable = false)//设置从方指向主方的关联外键,这个ONEA_ID其实是表T_ONEA的主键     
    11 @OneToOne     
    12 private OneA oneA;     

    10 .大字段 

    1 @Lob //对应Blob字段类型     
    2 @Column(name = "PHOTO")     
    3 private Serializable photo;     
    4 @Lob //对应Clob字段类型     
    5 @Column(name = "DESCRIPTION")     
    6 private String description;    

    11.瞬时字段 

    不需要与数据库映射的字段,在保存的时候不需要保存倒数据库 

     1 @Transient     
     2 private int tempValue;     
     3    
     4 public int getTempValue(){     
     5 get tempValue;     
     6 }     
     7    
     8 public void setTempValue(int value){     
     9 this.tempValue = value;     
    10 } 

    12.总结示例

     1 @Entity                           --声明为一个实体bean    
     2 @Table (name= "promotion_info" )    --为实体bean映射指定表(表名="promotion_info)    
     3 @Id                               --声明了该实体bean的标识属性    
     4 @GeneratedValue                   --可以定义标识字段的生成策略.    
     5 @Transient                        --将忽略这些字段和属性,不用持久化到数据库    
     6 @Column (name= "promotion_remark" )--声明列(字段名= "promotion_total" ) 属性还包括(length= 200 等)    
     7 @Temporal (TemporalType.TIMESTAMP)--声明时间格式    
     8 @Enumerated                       --声明枚举    
     9 @Version                          --声明添加对乐观锁定的支持    
    10 @OneToOne                         --可以建立实体bean之间的一对一的关联    
    11 @OneToMany                        --可以建立实体bean之间的一对多的关联    
    12 @ManyToOne                        --可以建立实体bean之间的多对一的关联    
    13 @ManyToMany                       --可以建立实体bean之间的多对多的关联    
    14 @Formula                          --一个SQL表达式,这种属性是只读的,不在数据库生成属性(可以使用sum、average、max等)   
    15 @Entity    
    16 @Table (name= "promotion_info" )    
    17 public class Promotion implements Serializable {    
    18    
    19      //AUTO--可以是identity类型的字段,或者sequence类型或者table类型,取决于不同的底层数据库    
    20      @Id    
    21      @GeneratedValue (strategy = GenerationType.AUTO)    
    22      private Long id;    
    23    
    24      @Column (name= "group_start_amount" )    
    25      private Integer groupStartAmount= 0 ;    
    26         
    27      @Column (name= "promotion_remark" ,length= 200 )    
    28      //@Lob 如果是文章内容可以使用 只需要把length=200去掉就可以了    
    29      private String remark;    
    30      //DATE       - java.sql.Date    
    31      //TIME       - java.sql.Time    
    32      //TIMESTAMP - java.sql.Timestamp    
    33      @Temporal (TemporalType.TIMESTAMP)    
    34      @Column (name= "start_time" )    
    35      private Date startTime;    
    36    
    37      //显示0 隐藏1    
    38      public static enum DisplayType {    
    39          显示,隐藏    
    40      }    
    41      @Enumerated (value = EnumType.ORDINAL) //ORDINAL序数    
    42      private DisplayType displayType = DisplayType.显示;    
    43    
    44      @Version    
    45      private Integer version;    
    46    
    47      //CascadeType.PERSIST    -- 触发级联创建(create)    
    48      //CascadeType.MERGE      -- 触发级联合并(update)    
    49      //FetchType.LAZY         -- 延迟加载    
    50      @ManyToOne (cascade = {CascadeType.PERSIST,CascadeType.MERGE},fetch = FetchType.LAZY)    
    51      private PromotionGroup promotionGroup;    
    52    
    53      //单向ManyToMany    
    54      //@JoinTable(关联的表名)    
    55      //joinColumns -- promotion关联的列的外键    
    56      //inverseJoinColumns -- largess 关联列的外键    
    57      @ManyToMany (cascade = {CascadeType.PERSIST,CascadeType.MERGE})    
    58      @JoinTable (name= "promotion_largess" ,joinColumns={ @JoinColumn (name= "promotion_id" )},inverseJoinColumns={ @JoinColumn (name= "largess_id" )})    
    59      private Set<Largess> largess;    
    60    
    61      //get set 省略....    
    62    
    63 }    
    64 @Entity    
    65 @Table (name= "promotion_group" )    
    66 public class PromotionGroup implements Serializable {    
    67      @Id    
    68      @GeneratedValue (strategy = GenerationType.AUTO)    
    69      private Long id;    
    70         
    71      //mappedBy的值"promotionGroup"指向owner(Promotion)端的关联属性,并且是双向关系    
    72      @OneToMany (mappedBy= "promotionGroup" ,cascade=CascadeType.ALL)    
    73      private List<Promotion> promotion;    
    74    
    75      //get set 省略....    
    76 }    
    77 @Entity    
    78 @Table (name= "largess" )    
    79 public class Largess implements Serializable {    
    80      @Id    
    81      @GeneratedValue (strategy = GenerationType.AUTO)    
    82      private Long id;    
    83    
    84      //1.sql语句中的字段和表名都应该和数据库相应,而不是类中的字段,    
    85      //若带有参数如la.id= id,这个=id才是类中属性    
    86      //2.操作字段一定要用别名    
    87      @Formula (select max(la.id) from largess as la)    
    88      private int maxId;    
    89    
    90      @Formula (select COUNT(la.id) from largess la)    
    91      private int count;    
    92    
    93      @Transient    
    94      private String img    
    95    
    96      //get set 省略....    
    97 }  
  • 相关阅读:
    工作实战之项目常用技术
    Thymeleaf的错误解决方式
    实用小demo
    idea常用的几个插件
    idea2019+Plugins中搜索不到任何插件解决办法
    git的初体验
    springboot2.+的整合log4j2错误解决浅谈
    MobaXterm百度网盘下载
    阿里云RDS云数据库连接步骤
    读源码学编程之——死循环妙用
  • 原文地址:https://www.cnblogs.com/jcjssl/p/9391277.html
Copyright © 2020-2023  润新知