@Query 取值方式
https://spring.io/blog/2014/07/15/spel-support-in-spring-data-jpa-query-definitions
@Query("select u from User u where u.age = ?#{[0]}")
List<User> findUsersByAge(int age);
# 实体取值
@Query("select u from User u where u.firstname = :#{#customer.firstname}")
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
public interface UserRepository extends JpaRepository<User, Long> {
@Query("select u from User u where u.emailAddress = ?1")
User findByEmailAddress(String emailAddress);
@Query("select u from User u where u.emailAddress = :emailAddress")
User findByEmailAddress2(@Param("nickname") String emailAddress);
# 实体取值
@Query("select u from User u where u.firstname = :#{#customer.firstname}")
List<User> findUsersByCustomersFirstname(@Param("customer") Customer customer);
}
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) |
返回自定义实体
推荐第一种:定义返回实体接口
定义返回实体接口
// 只需要有get方法即可,注意命名要规范
public interface UserOrRole2 {
String getId();
String getUserId();
String getNickname();
String getSex();
String getRoleName();
}
/**
* jpql 返回自定义 实体
* @param nickname
* @return
*/
@Query(value = " SELECT u.userId,u.id,u.nickname,u.sex,u.roleName FROM UserBean u where u.nickname = :nickname ")
public List<UserOrRole2> test(@Param("nickname") String nickname);
定义返回实体
public class UserOrRole2 {
String id;
String userId;
String nickname;
String sex;
String roleName;
// 省略get set
}
/**
* jpql 返回自定义 实体
* @param nickname
* @return
*/
@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 ")
public List<UserOrRole2> test(@Param("nickname") String nickname);
常用注解
设置索引 @Table
@Index
@UniqueConstraint
unique = true 唯一索引
// 复合注解
@Table(name = "数据表名称", schema = "数据库名称",
indexes = {
@Index(name = "索引名称", columnList = "字段1", unique = true),
@Index(name = "索引名称", columnList = "字段1,字段2", unique = true),
})
@Table(name="数据表名称",indexes={@Index(name="索引名称",columnList="字段1",unique=true})
// 单个注解
@Index(name="索引名称",columnList="字段1",unique=false)})
// 单个注解 - 唯一索引
@UniqueConstraint(name = "索引名称", columnNames = {"字段1","字段2"})})
标识实体类中属性与数据表中字段的对应关系 @Column
columnDefinition
我常用@Column(columnDefinition = " int(4) not null default 1 comment ' 停启用状态(0、停用 ,1、启用,默认1)' ")
private Integer status;
根据属性设置
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
String name() default ""; // 定义了该属性字段在数据库表中所对应字段的名称
boolean unique() default false; //表示该字段是否为唯一标识,默认为false
boolean nullable() default true; //表示该字段是否可以为null值,默认为true
boolean insertable() default true; //表示在使用“INSERT”脚本插入数据时,是否允许插入该字段的值
boolean updatable() default true; //表示在使用“UPDATE”脚本插入数据时,是否允许更新该字段的值.
String columnDefinition() default ""; //表示创建表时,该字段创建的SQL语句,一般用于通过Entity生成表定义时使用。
String table() default ""; //定义了包含当前字段的表名,缺省值时默认该字段存在于主表下
int length() default 255; // 表示字段的长度,当字段的类型为varchar时,该属性才有效,默认为255个字符
int precision() default 0; //表示数值的总长度
int scale() default 0; //表示小数点所占的位数
}
实体中嵌入对象
https://www.codeleading.com/article/81262695760/ @Embeddable
@Access @embedded
默认使用方式
公共字段,需要被嵌入到其他地方使用
package com.detabes.gzyanalysis.entity.door;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.SelectBeforeUpdate;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Column;
import javax.persistence.Embeddable;
/**
* 门禁实体公共字段
*
* @author tn
* @date 2022-03-03 11:02
*/
@Embeddable
@DynamicInsert
@DynamicUpdate
@SelectBeforeUpdate
@Access(AccessType.FIELD)
@Getter
@Setter
public class DoorEntity {
/**
* 用户编码;用户编码
**/
@Column(columnDefinition = "varchar(60) comment '用户编码'")
private String userNo;
/**
* 闸机号;闸机号
**/
@Column(columnDefinition = "varchar(60) not null comment '闸机号'")
private String gateNo;
}
实体类使用嵌入字段
package com.detabes.gzyanalysis.entity.door;
import com.detabes.gzyanalysis.entity.CommonBean;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.Table;
/**
* 入馆数据实体类
*
* @author tn
* @date 2022-03-03
**/
@Entity
@Table(name = "door_input")
@org.hibernate.annotations.Table(appliesTo = "door_input", comment = "入馆数据")
@Data
@EqualsAndHashCode(callSuper = true)
@DynamicUpdate
@DynamicInsert
public class DoorInputEntity extends CommonBean<DoorInputEntity> {
/**
* 入馆时间;入馆时间
**/
@Column(columnDefinition = "varchar(60) comment '入馆时间'")
private String inTime;
/**
* 入馆方式;0.不明 1. 扫码 2. 刷卡 3. 远程开门(保安开的 4. 等等
**/
@Column(columnDefinition = "int not null default 0 comment '入馆方式;0.不明 1. 扫码 2. 刷卡 3. 远程开门(保安开的 '")
private Integer inType;
/**
* 嵌入公共字段对象
*/
@Embedded
private DoorEntity doorEntity;
}
使用二 修改公共字段的column名称后在使用
公共字段
package com.detabes.gzyanalysis.entity.door;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.SelectBeforeUpdate;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Column;
import javax.persistence.Embeddable;
/**
* 门禁实体公共字段
*
* @author tn
* @date 2022-03-03 11:02
*/
@Embeddable
@DynamicInsert
@DynamicUpdate
@SelectBeforeUpdate
@Access(AccessType.FIELD)
@Getter
@Setter
public class DoorEntity {
/**
* 出入馆时间
**/
@Column(columnDefinition = "varchar(60) comment '出入馆时间'")
private String times;
/**
* 出入馆方式;0.不明 1. 扫码 2. 刷卡 3. 远程开门(保安开的 4. 等等
**/
@Column(columnDefinition = "int not null default 0 comment '出入馆方式;0.不明 1. 扫码 2. 刷卡 3. 远程开门(保安开的 '")
private Integer type;
/**
* 用户编码;用户编码
**/
@Column(columnDefinition = "varchar(60) comment '用户编码'")
private String userNo;
/**
* 闸机号;闸机号
**/
@Column(columnDefinition = "varchar(60) not null comment '闸机号'")
private String gateNo;
}
实体类使用嵌入类时修改表字段名
这种方式如果要使用 索引方法如下:
// 嵌入类时修改表字段时, 不能写 DoorEntity 里面的原本实体字段名,会报错
@Table(name = "door_input",
indexes = {
@Index(name = "in_type_index", columnList = "in_type", unique = true),
})
import com.detabes.gzyanalysis.entity.CommonBean;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import javax.persistence.*;
/**
* 入馆数据实体类
*
* @author tn
* @date 2022-03-03
**/
@Entity
@Table(name = "door_input")
@org.hibernate.annotations.Table(appliesTo = "door_input", comment = "入馆数据")
@Data
@EqualsAndHashCode(callSuper = true)
@DynamicUpdate
@DynamicInsert
public class DoorInputEntity extends CommonBean<DoorInputEntity> {
/**
* 嵌入公共字段对象
*/
@Embedded
@AttributeOverrides({
@AttributeOverride(name="type",column=@Column(name="in_type",columnDefinition = "int not null default 0 comment '入馆方式;0.不明 1. 扫码 2. 刷卡 3. 远程开门(保安开的 '")),
@AttributeOverride(name="times",column=@Column(name="in_time",columnDefinition = "varchar(60) comment '入馆时间'"))
})
private DoorEntity doorEntity;
}
效果
CREATE TABLE `door_input` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键,自动生成',
`update_user_name` varchar(100) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '更新人',
`create_user_name` varchar(100) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '创建人',
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新日期',
`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建日期',
`in_time` varchar(60) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '入馆时间',
`in_type` int(11) NOT NULL DEFAULT '0' COMMENT '入馆方式;0.不明 1. 扫码 2. 刷卡 3. 远程开门(保安开的 ',
`user_no` varchar(60) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '用户编码',
`gate_no` varchar(60) COLLATE utf8mb4_general_ci NOT NULL COMMENT '闸机号',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='入馆数据';
枚举参数
https://blog.csdn.net/weixin_42994251/article/details/110147426
枚举类
package com.detabes.gzyanalysis.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Objects;
/**
* 存量类型
*
* @author tn
* @date 2022-01-19 16:31
*/
@AllArgsConstructor
@Getter
public enum StockTypeEnum {
/* 总藏 = 在馆的所有书籍(包括外借的) */
TOTAL(1,"总藏(在馆的所有书籍(包括外借的))"),
/* 入藏 = 买的所有书籍*/
INTO(2,"入藏(买的所有书籍)"),
/* 在馆 = 在馆的所有书籍(不包括外借的) */
AT_HOME(3,"在馆(在馆的所有书籍(不包括外借的))"),
/* 总资源 =书+刊+古籍+多媒体+电子资源(这次不包括) */
TOTAL_RESOURCE(4,"总资源(书+刊+古籍+多媒体+电子资源)"),
;
private final int stockType;
private final String stockName;
//获取枚举实例
public static StockTypeEnum fromValue(Integer value) {
for (StockTypeEnum stockTypeEnum : StockTypeEnum.values()) {
if (Objects.equals(value, stockTypeEnum.getStockType())) {
return stockTypeEnum;
}
}
throw new IllegalArgumentException();
}
}
自定义Convert
package com.detabes.gzyanalysis.enums.convert;
import com.detabes.gzyanalysis.enums.StockTypeEnum;
import javax.persistence.AttributeConverter;
/**
* @author tn
*/
public class StockEnumConvert implements AttributeConverter<StockTypeEnum, Integer> {
@Override
public Integer convertToDatabaseColumn(StockTypeEnum attribute) {
return attribute.getStockType();
}
@Override
public StockTypeEnum convertToEntityAttribute(Integer dbData) {
return StockTypeEnum.fromValue(dbData);
}
}
实体类中使用
import com.detabes.entity.basics.vo.SerializableVO;
import com.detabes.gzyanalysis.enums.StockTypeEnum;
import com.detabes.gzyanalysis.enums.convert.StockEnumConvert;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import javax.persistence.*;
/**
* 藏书存量(全馆全时间段统计)实体类
*
* @author tn
* @date 2022-01-19
**/
@Entity
@Table(name = "library_stock", indexes = {
@Index(name = "stockType_index", columnList = "stockType", unique = true)
})
@org.hibernate.annotations.Table(appliesTo = "library_stock", comment = "藏书存量(全馆全时间段统计)")
@Data
@EqualsAndHashCode(callSuper = true)
@DynamicUpdate
@DynamicInsert
public class LibraryStockEntity extends SerializableVO<LibraryStockEntity> {
/**
* 主键;自增长
**/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(columnDefinition = "int comment '主键;自增长'")
private Integer id;
/**
* 存量类型
* 存储的是 int
**/
@Column(columnDefinition = "int comment '存量类型(具体信息:StockTypeEnum)'")
@Convert(converter = StockEnumConvert.class)
private StockTypeEnum stockType;
/**
* 统计时间
**/
@Column(columnDefinition = "varchar(100) not null comment '统计时间'")
private String countTime;
/**
* 存量
**/
@Column(columnDefinition = "bigint default 0 comment '存量'")
private Long stock;
}
实体构建索引
// unique true: 唯一索引 false:单值索引
@Table(name="sys_user_msg_collect",
indexes={
@Index(name="uuid_index",columnList="uuid",unique=true),
@Index(name="loginName_index",columnList="loginName",unique=false)
}
)