❤️ 基接口 Repository
使用基接口 Repository 可以复用方法名
- 定义基接口
java
@NoRepositoryBean
public interface BaseRepository<T> {
List<T> findAllByCustName(String name);
}- 继承
java
public interface CustomerRepository extends BaseRepository<Customer>, JpaRepository<Customer, Long> {
}❤️ 分页
静态方法 :
PageRequest of(第几页,一页的大小,Sort 排序对象)页码从 0 开始
java
public interface CustomerRepository extends BaseRepository<Customer>, JpaRepository<Customer, Long> {
Page<Customer> findAll(Pageable pageable);
}
@Test
public void test_findAll_pageable() {
// 定义分页参数
PageRequest pageRequest = PageRequest.of(
1,
5,
Sort.by("no").descending()
);
Page<Customer> all = customerRepository.findAll(pageRequest);
JsonNode jsonNode = objectMapper.valueToTree(all);
System.out.println(jsonNode.toString());
}❤️ 映射关系
如果是使用 Jpa Buddy 生成的 JPQL,则不支持映射关系,比如要执行一个 update,很麻烦,还是乖乖地手动维护吧
💛 多对多
- 多对多中一方为维护端,一方为被维护端。关系的绑定和解除都由维护端来完成,关系被维护端不能绑定关系
- 如果 A,B 表已经绑定了多对多的关系,那么不能直接删除从表,必须由主表解除关系后,才能删除从表;但是可以直接删除主表,删除时会先解除关系然后再删除
@ManyToMany
cascade[]该属性定义了级联操作的类型,即在执行操作时,是否将这些操作级联到关联的实体上CascadeType.ALL包括以下所有CascadeType.PERSIST当持久化操作发生时,级联保存关联的实体CascadeType.MERGE当合并操作发生时,级联更新关联的实体CascadeType.REMOVE当删除操作发生时,级联删除关联的实体CascadeType.REFRESH当刷新操作发生时,级联刷新关联的实体CascadeType.DETACH当分离操作发生时,级联分离关联的实体
fetch指定关联实体的加载策略FetchType.LAZY懒加载,表示只有在实际访问该关联时才会从数据库加载相关的实体FetchType.EAGER立即加载,表示在加载当前实体时会同时加载关联的实体
mappedBy映射关系的被维护方,需要添加 mappedBy 来指定维护方
java
@EqualsAndHashCode(exclude = {"authors"})
@Entity
public class Book implements Serializable {
@ManyToMany(fetch = FetchType.EAGER, cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
@JoinTable(name = "book_author",
joinColumns = {@JoinColumn(name = "book_id", referencedColumnName = "id")},
inverseJoinColumns = {@JoinColumn(name = "author_id", referencedColumnName = "id")})
private Set<Author> authors;
}
@ToString(exclude = {"books"})
@EqualsAndHashCode(exclude = {"books"})
@Entity
public class Author implements Serializable {
@ManyToMany(mappedBy = "authors")
private Set<Book> books;
}`@ManyTOMany` 时 Lombok 生成的 @ToString,@EqualsAndHashCode 会导致两个集合循环比较,造成内存溢出,要么手写 equals 和 hashcode,要么排除该属性
java
// 主表
@EqualsAndHashCode(exclude = {"authors"})
public class Book {
@ManyToMany(fetch = FetchType.EAGER, cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
@JoinTable(name = "book_author",
joinColumns = {@JoinColumn(name = "book_id", referencedColumnName = "id")},
inverseJoinColumns = {@JoinColumn(name = "author_id", referencedColumnName = "id")})
private Set\<Author> authors;
}
// 从表
@ToString(exclude = {"books"})
@EqualsAndHashCode(exclude = {"books"})
public class Author {
@ManyToMany(mappedBy = "authors")
private Set\<Book> books;
}触发器
#问题 jpa 怎么写触发器
存储引擎
查询时抓取
[!quote] 抓取 抓取 是从数据库中获取实体,及其关联属性的数据
实体类上 :
@NamedEntityGraph在实体类上定义实体图,指定要抓取的属性name指定实体图的名字attributeNodes指定抓取哪个属性
仓储接口的查询方法上 :
@EntityGraph在查询方法上应用实体图value指定实体图的名字type指定抓取策略- FETCH 仅抓取指定的属性,其他属性将使用默认的懒加载
- LOAD 不仅抓取指定的属性,还会抓取其他默认设置为立即加载的属性
复用实体图
如果有一个实体图需要复用,那么可以将其定义在 Entity 上
- 定义命名实体图
java
@Entity
@NamedEntityGraph(name = "GroupInfo.detail", attributeNodes = @NamedAttributeNode("members"))
public class GroupInfo {
@ManyToMany
List<GroupMember> members = new ArrayList<GroupMember>();
// 默认抓取模式是懒加载。
}- 在查询方法中引用命名实体图
java
public interface GroupRepository extends CrudRepository<GroupInfo, String> {
@EntityGraph(value = "GroupInfo.detail", type = EntityGraphType.LOAD)
GroupInfo getByGroupName(String name);
}临时实体图
如果某个实体图,只在当前查询方法上使用,那就直接在当前方法上定义
java
public interface GroupRepository extends CrudRepository<GroupInfo, String> {
@EntityGraph(attributePaths = { "members" })
GroupInfo getByGroupName(String name);
}不推荐 - OneToMany
@OneToManycascade- CascadeType.ALL - 对 Many 端的所有持久化实体的操作,都会自动应用到 One 端
orphanRemoval- true - One 端删除了集合中的 Many item,那在 Many 端,会删除 item 记录
java
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "awardId") // 指定Award表中的外键为awardId todo
private List<Award> awards; // 绑定的奖品集合推荐 - Convert 存 id 集合
java
@Entity
public class RafflePool {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(columnDefinition = "TEXT")
@Convert(converter = LongListToJsonConverter.class)
private List<Long> awardIds; // 绑定的奖品集合
}
@Converter
public class LongListToJsonConverter implements AttributeConverter<List<Long>, String> {
private final ObjectMapper objectMapper = new ObjectMapper();
/**
* 实体属性 --->>> 数据库列
*/
@Override
public String convertToDatabaseColumn(List<Long> longs) {
try {
return objectMapper.writeValueAsString(longs);
} catch (Exception e) {
throw new RuntimeException("Failed to convert list to JSON", e);
}
}
/**
* 数据库列 --->>> 实体属性
*/
@Override
public List<Long> convertToEntityAttribute(String dbData) {
try {
return objectMapper.readValue(dbData, new TypeReference<>() {
});
} catch (Exception e) {
throw new RuntimeException("Failed to convert JSON to list", e);
}
}
}