JPA使用.pdf
Spring 数据扩展

@Query 取值方式

https://spring.io/blog/2014/07/15/spel-support-in-spring-data-jpa-query-definitions

  1. @Query("select u from User u where u.age = ?#{[0]}")
  2. List<User> findUsersByAge(int age);
  3. # 实体取值
  4. @Query("select u from User u where u.firstname = :#{#customer.firstname}")
  5. List<User> findUsersByCustomersFirstname(@Param("customer") Customer customer);

@Query 使用方式

https://docs.spring.io/spring-data/jpa/docs/2.5.6/reference/html/#jpa.query-methods.at-query

  1. public interface UserRepository extends JpaRepository<User, Long> {
  2. @Query("select u from User u where u.emailAddress = ?1")
  3. User findByEmailAddress(String emailAddress);
  4. @Query("select u from User u where u.emailAddress = :emailAddress")
  5. User findByEmailAddress2(@Param("nickname") String emailAddress);
  6. # 实体取值
  7. @Query("select u from User u where u.firstname = :#{#customer.firstname}")
  8. List<User> findUsersByCustomersFirstname(@Param("customer") Customer customer);
  9. }

Repository 的使用

https://docs.spring.io/spring-data/jpa/docs/2.5.6/reference/html/#jpa.query-methods.query-creation

Keyword Sample JPQL snippet
Distinct findDistinctByLastnameAndFirstname select distinct … where x.lastname = ?1 and x.firstname = ?2
And findByLastnameAndFirstname … where x.lastname = ?1 and x.firstname = ?2
Or findByLastnameOrFirstname … where x.lastname = ?1 or x.firstname = ?2
Is
, Equals
findByFirstname
,findByFirstnameIs
,findByFirstnameEquals
… where x.firstname = ?1
Between findByStartDateBetween … where x.startDate between ?1 and ?2
LessThan findByAgeLessThan … where x.age < ?1
LessThanEqual findByAgeLessThanEqual … where x.age <= ?1
GreaterThan findByAgeGreaterThan … where x.age > ?1
GreaterThanEqual findByAgeGreaterThanEqual … where x.age >= ?1
After findByStartDateAfter … where x.startDate > ?1
Before findByStartDateBefore … where x.startDate < ?1
IsNull
, Null
findByAge(Is)Null … where x.age is null
IsNotNull
, NotNull
findByAge(Is)NotNull … where x.age not null
Like findByFirstnameLike … where x.firstname like ?1
NotLike findByFirstnameNotLike … where x.firstname not like ?1
StartingWith findByFirstnameStartingWith … where x.firstname like ?1
(parameter bound with appended %
)
EndingWith findByFirstnameEndingWith … where x.firstname like ?1
(parameter bound with prepended %
)
Containing findByFirstnameContaining … where x.firstname like ?1
(parameter bound wrapped in %
)
OrderBy findByAgeOrderByLastnameDesc … where x.age = ?1 order by x.lastname desc
Not findByLastnameNot … where x.lastname <> ?1
In findByAgeIn(Collection<Age> ages) … where x.age in ?1
NotIn findByAgeNotIn(Collection<Age> ages) … where x.age not in ?1
True findByActiveTrue() … where x.active = true
False findByActiveFalse() … where x.active = false
IgnoreCase findByFirstnameIgnoreCase … where UPPER(x.firstname) = UPPER(?1)

返回自定义实体

推荐第一种:定义返回实体接口

定义返回实体接口

  1. // 只需要有get方法即可,注意命名要规范
  2. public interface UserOrRole2 {
  3. String getId();
  4. String getUserId();
  5. String getNickname();
  6. String getSex();
  7. String getRoleName();
  8. }
  9. /**
  10. * jpql 返回自定义 实体
  11. * @param nickname
  12. * @return
  13. */
  14. @Query(value = " SELECT u.userId,u.id,u.nickname,u.sex,u.roleName FROM UserBean u where u.nickname = :nickname ")
  15. public List<UserOrRole2> test(@Param("nickname") String nickname);

定义返回实体

  1. public class UserOrRole2 {
  2. String id;
  3. String userId;
  4. String nickname;
  5. String sex;
  6. String roleName;
  7. // 省略get set
  8. }
  9. /**
  10. * jpql 返回自定义 实体
  11. * @param nickname
  12. * @return
  13. */
  14. @Query(value = " SELECT new com.tn.jpahi.bean.UserOrRole2(r.userId,r.id,u.nickname,u.sex,r.roleName) FROM UserBean u where u.nickname =:nickname ")
  15. public List<UserOrRole2> test(@Param("nickname") String nickname);

常用注解

设置索引 @Table @Index @UniqueConstraint

unique = true 唯一索引

  1. // 复合注解
  2. @Table(name = "数据表名称", schema = "数据库名称",
  3. indexes = {
  4. @Index(name = "索引名称", columnList = "字段1", unique = true),
  5. @Index(name = "索引名称", columnList = "字段1,字段2", unique = true),
  6. })
  7. @Table(name="数据表名称",indexes={@Index(name="索引名称",columnList="字段1",unique=true})
  8. // 单个注解
  9. @Index(name="索引名称",columnList="字段1",unique=false)})
  10. // 单个注解 - 唯一索引
  11. @UniqueConstraint(name = "索引名称", columnNames = {"字段1","字段2"})})

标识实体类中属性与数据表中字段的对应关系 @Column

  1. columnDefinition我常用

    1. @Column(columnDefinition = " int(4) not null default 1 comment ' 停启用状态(0、停用 ,1、启用,默认1)' ")
    2. private Integer status;
  2. 根据属性设置

    1. @Target({ElementType.METHOD, ElementType.FIELD})
    2. @Retention(RetentionPolicy.RUNTIME)
    3. public @interface Column {
    4. String name() default ""; // 定义了该属性字段在数据库表中所对应字段的名称
    5. boolean unique() default false; //表示该字段是否为唯一标识,默认为false
    6. boolean nullable() default true; //表示该字段是否可以为null值,默认为true
    7. boolean insertable() default true; //表示在使用“INSERT”脚本插入数据时,是否允许插入该字段的值
    8. boolean updatable() default true; //表示在使用“UPDATE”脚本插入数据时,是否允许更新该字段的值.
    9. String columnDefinition() default ""; //表示创建表时,该字段创建的SQL语句,一般用于通过Entity生成表定义时使用。
    10. String table() default ""; //定义了包含当前字段的表名,缺省值时默认该字段存在于主表下
    11. int length() default 255; // 表示字段的长度,当字段的类型为varchar时,该属性才有效,默认为255个字符
    12. int precision() default 0; //表示数值的总长度
    13. int scale() default 0; //表示小数点所占的位数
    14. }

实体中嵌入对象

https://www.codeleading.com/article/81262695760/ @Embeddable
@Access @embedded

默认使用方式

公共字段,需要被嵌入到其他地方使用

@Embeddable @Access

  1. package com.detabes.gzyanalysis.entity.door;
  2. import lombok.Getter;
  3. import lombok.Setter;
  4. import org.hibernate.annotations.DynamicInsert;
  5. import org.hibernate.annotations.DynamicUpdate;
  6. import org.hibernate.annotations.SelectBeforeUpdate;
  7. import javax.persistence.Access;
  8. import javax.persistence.AccessType;
  9. import javax.persistence.Column;
  10. import javax.persistence.Embeddable;
  11. /**
  12. * 门禁实体公共字段
  13. *
  14. * @author tn
  15. * @date 2022-03-03 11:02
  16. */
  17. @Embeddable
  18. @DynamicInsert
  19. @DynamicUpdate
  20. @SelectBeforeUpdate
  21. @Access(AccessType.FIELD)
  22. @Getter
  23. @Setter
  24. public class DoorEntity {
  25. /**
  26. * 用户编码;用户编码
  27. **/
  28. @Column(columnDefinition = "varchar(60) comment '用户编码'")
  29. private String userNo;
  30. /**
  31. * 闸机号;闸机号
  32. **/
  33. @Column(columnDefinition = "varchar(60) not null comment '闸机号'")
  34. private String gateNo;
  35. }

实体类使用嵌入字段

@Embedded

  1. package com.detabes.gzyanalysis.entity.door;
  2. import com.detabes.gzyanalysis.entity.CommonBean;
  3. import lombok.Data;
  4. import lombok.EqualsAndHashCode;
  5. import org.hibernate.annotations.DynamicInsert;
  6. import org.hibernate.annotations.DynamicUpdate;
  7. import javax.persistence.Column;
  8. import javax.persistence.Embedded;
  9. import javax.persistence.Entity;
  10. import javax.persistence.Table;
  11. /**
  12. * 入馆数据实体类
  13. *
  14. * @author tn
  15. * @date 2022-03-03
  16. **/
  17. @Entity
  18. @Table(name = "door_input")
  19. @org.hibernate.annotations.Table(appliesTo = "door_input", comment = "入馆数据")
  20. @Data
  21. @EqualsAndHashCode(callSuper = true)
  22. @DynamicUpdate
  23. @DynamicInsert
  24. public class DoorInputEntity extends CommonBean<DoorInputEntity> {
  25. /**
  26. * 入馆时间;入馆时间
  27. **/
  28. @Column(columnDefinition = "varchar(60) comment '入馆时间'")
  29. private String inTime;
  30. /**
  31. * 入馆方式;0.不明 1. 扫码 2. 刷卡 3. 远程开门(保安开的 4. 等等
  32. **/
  33. @Column(columnDefinition = "int not null default 0 comment '入馆方式;0.不明 1. 扫码 2. 刷卡 3. 远程开门(保安开的 '")
  34. private Integer inType;
  35. /**
  36. * 嵌入公共字段对象
  37. */
  38. @Embedded
  39. private DoorEntity doorEntity;
  40. }

使用二 修改公共字段的column名称后在使用

公共字段

  1. package com.detabes.gzyanalysis.entity.door;
  2. import lombok.Getter;
  3. import lombok.Setter;
  4. import org.hibernate.annotations.DynamicInsert;
  5. import org.hibernate.annotations.DynamicUpdate;
  6. import org.hibernate.annotations.SelectBeforeUpdate;
  7. import javax.persistence.Access;
  8. import javax.persistence.AccessType;
  9. import javax.persistence.Column;
  10. import javax.persistence.Embeddable;
  11. /**
  12. * 门禁实体公共字段
  13. *
  14. * @author tn
  15. * @date 2022-03-03 11:02
  16. */
  17. @Embeddable
  18. @DynamicInsert
  19. @DynamicUpdate
  20. @SelectBeforeUpdate
  21. @Access(AccessType.FIELD)
  22. @Getter
  23. @Setter
  24. public class DoorEntity {
  25. /**
  26. * 出入馆时间
  27. **/
  28. @Column(columnDefinition = "varchar(60) comment '出入馆时间'")
  29. private String times;
  30. /**
  31. * 出入馆方式;0.不明 1. 扫码 2. 刷卡 3. 远程开门(保安开的 4. 等等
  32. **/
  33. @Column(columnDefinition = "int not null default 0 comment '出入馆方式;0.不明 1. 扫码 2. 刷卡 3. 远程开门(保安开的 '")
  34. private Integer type;
  35. /**
  36. * 用户编码;用户编码
  37. **/
  38. @Column(columnDefinition = "varchar(60) comment '用户编码'")
  39. private String userNo;
  40. /**
  41. * 闸机号;闸机号
  42. **/
  43. @Column(columnDefinition = "varchar(60) not null comment '闸机号'")
  44. private String gateNo;
  45. }

实体类使用嵌入类时修改表字段名

这种方式如果要使用 索引方法如下:

  1. // 嵌入类时修改表字段时, 不能写 DoorEntity 里面的原本实体字段名,会报错
  2. @Table(name = "door_input",
  3. indexes = {
  4. @Index(name = "in_type_index", columnList = "in_type", unique = true),
  5. })
  1. import com.detabes.gzyanalysis.entity.CommonBean;
  2. import lombok.Data;
  3. import lombok.EqualsAndHashCode;
  4. import org.hibernate.annotations.DynamicInsert;
  5. import org.hibernate.annotations.DynamicUpdate;
  6. import javax.persistence.*;
  7. /**
  8. * 入馆数据实体类
  9. *
  10. * @author tn
  11. * @date 2022-03-03
  12. **/
  13. @Entity
  14. @Table(name = "door_input")
  15. @org.hibernate.annotations.Table(appliesTo = "door_input", comment = "入馆数据")
  16. @Data
  17. @EqualsAndHashCode(callSuper = true)
  18. @DynamicUpdate
  19. @DynamicInsert
  20. public class DoorInputEntity extends CommonBean<DoorInputEntity> {
  21. /**
  22. * 嵌入公共字段对象
  23. */
  24. @Embedded
  25. @AttributeOverrides({
  26. @AttributeOverride(name="type",column=@Column(name="in_type",columnDefinition = "int not null default 0 comment '入馆方式;0.不明 1. 扫码 2. 刷卡 3. 远程开门(保安开的 '")),
  27. @AttributeOverride(name="times",column=@Column(name="in_time",columnDefinition = "varchar(60) comment '入馆时间'"))
  28. })
  29. private DoorEntity doorEntity;
  30. }

效果

  1. CREATE TABLE `door_input` (
  2. `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键,自动生成',
  3. `update_user_name` varchar(100) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '更新人',
  4. `create_user_name` varchar(100) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人',
  5. `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新日期',
  6. `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建日期',
  7. `in_time` varchar(60) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '入馆时间',
  8. `in_type` int(11) NOT NULL DEFAULT '0' COMMENT '入馆方式;0.不明 1. 扫码 2. 刷卡 3. 远程开门(保安开的 ',
  9. `user_no` varchar(60) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '用户编码',
  10. `gate_no` varchar(60) COLLATE utf8mb4_general_ci NOT NULL COMMENT '闸机号',
  11. PRIMARY KEY (`id`)
  12. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='入馆数据';

枚举参数

https://blog.csdn.net/weixin_42994251/article/details/110147426

枚举类

  1. package com.detabes.gzyanalysis.enums;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Getter;
  4. import java.util.Objects;
  5. /**
  6. * 存量类型
  7. *
  8. * @author tn
  9. * @date 2022-01-19 16:31
  10. */
  11. @AllArgsConstructor
  12. @Getter
  13. public enum StockTypeEnum {
  14. /* 总藏 = 在馆的所有书籍(包括外借的) */
  15. TOTAL(1,"总藏(在馆的所有书籍(包括外借的))"),
  16. /* 入藏 = 买的所有书籍*/
  17. INTO(2,"入藏(买的所有书籍)"),
  18. /* 在馆 = 在馆的所有书籍(不包括外借的) */
  19. AT_HOME(3,"在馆(在馆的所有书籍(不包括外借的))"),
  20. /* 总资源 =书+刊+古籍+多媒体+电子资源(这次不包括) */
  21. TOTAL_RESOURCE(4,"总资源(书+刊+古籍+多媒体+电子资源)"),
  22. ;
  23. private final int stockType;
  24. private final String stockName;
  25. //获取枚举实例
  26. public static StockTypeEnum fromValue(Integer value) {
  27. for (StockTypeEnum stockTypeEnum : StockTypeEnum.values()) {
  28. if (Objects.equals(value, stockTypeEnum.getStockType())) {
  29. return stockTypeEnum;
  30. }
  31. }
  32. throw new IllegalArgumentException();
  33. }
  34. }

自定义Convert

  1. package com.detabes.gzyanalysis.enums.convert;
  2. import com.detabes.gzyanalysis.enums.StockTypeEnum;
  3. import javax.persistence.AttributeConverter;
  4. /**
  5. * @author tn
  6. */
  7. public class StockEnumConvert implements AttributeConverter<StockTypeEnum, Integer> {
  8. @Override
  9. public Integer convertToDatabaseColumn(StockTypeEnum attribute) {
  10. return attribute.getStockType();
  11. }
  12. @Override
  13. public StockTypeEnum convertToEntityAttribute(Integer dbData) {
  14. return StockTypeEnum.fromValue(dbData);
  15. }
  16. }

实体类中使用

  1. import com.detabes.entity.basics.vo.SerializableVO;
  2. import com.detabes.gzyanalysis.enums.StockTypeEnum;
  3. import com.detabes.gzyanalysis.enums.convert.StockEnumConvert;
  4. import lombok.Data;
  5. import lombok.EqualsAndHashCode;
  6. import org.hibernate.annotations.DynamicInsert;
  7. import org.hibernate.annotations.DynamicUpdate;
  8. import javax.persistence.*;
  9. /**
  10. * 藏书存量(全馆全时间段统计)实体类
  11. *
  12. * @author tn
  13. * @date 2022-01-19
  14. **/
  15. @Entity
  16. @Table(name = "library_stock", indexes = {
  17. @Index(name = "stockType_index", columnList = "stockType", unique = true)
  18. })
  19. @org.hibernate.annotations.Table(appliesTo = "library_stock", comment = "藏书存量(全馆全时间段统计)")
  20. @Data
  21. @EqualsAndHashCode(callSuper = true)
  22. @DynamicUpdate
  23. @DynamicInsert
  24. public class LibraryStockEntity extends SerializableVO<LibraryStockEntity> {
  25. /**
  26. * 主键;自增长
  27. **/
  28. @Id
  29. @GeneratedValue(strategy = GenerationType.IDENTITY)
  30. @Column(columnDefinition = "int comment '主键;自增长'")
  31. private Integer id;
  32. /**
  33. * 存量类型
  34. * 存储的是 int
  35. **/
  36. @Column(columnDefinition = "int comment '存量类型(具体信息:StockTypeEnum)'")
  37. @Convert(converter = StockEnumConvert.class)
  38. private StockTypeEnum stockType;
  39. /**
  40. * 统计时间
  41. **/
  42. @Column(columnDefinition = "varchar(100) not null comment '统计时间'")
  43. private String countTime;
  44. /**
  45. * 存量
  46. **/
  47. @Column(columnDefinition = "bigint default 0 comment '存量'")
  48. private Long stock;
  49. }

实体构建索引

@UniqueConstraint @Index

  1. // unique true: 唯一索引 false:单值索引
  2. @Table(name="sys_user_msg_collect",
  3. indexes={
  4. @Index(name="uuid_index",columnList="uuid",unique=true),
  5. @Index(name="loginName_index",columnList="loginName",unique=false)
  6. }
  7. )