-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
郑家骜[ào]
committed
Sep 27, 2024
1 parent
58060b5
commit 29ee327
Showing
15 changed files
with
969 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,291 @@ | ||
# jpa 懒加载实现 | ||
|
||
## jpa 懒加载配置 | ||
|
||
注意,实现方式一 与 实现方式二 会存在冲突,所以需要选择一种实现方式,推荐使用实现方式二。 | ||
|
||
### 实现方式一(不推荐):实体类实现懒加载接口 PersistentAttributeInterceptable 来自定义懒加载行为。 | ||
|
||
要分别设置 @Lob 字段的懒加载,需手动添加 getXXX() 和 setXXX()方法,否则无法生效。 | ||
|
||
```java | ||
@Getter | ||
@Setter | ||
@Entity | ||
@Table(name = "t_project") | ||
@EntityListeners(value = AuditingEntityListener.class) | ||
public class Project implements PersistentAttributeInterceptable { | ||
|
||
@Id | ||
private String id = String.valueOf(System.currentTimeMillis()); | ||
|
||
/** | ||
* 名称 | ||
*/ | ||
@Column(nullable = false, length = 100) | ||
private String name; | ||
|
||
/** | ||
* json 字符串存储字段 | ||
*/ | ||
@Lob | ||
// @Lazy | ||
@Basic(fetch = FetchType.LAZY) // FetchType.LAZY 似乎未生效 | ||
@Column(name = "config_json") | ||
private JSONObject configJson; // jpa默认生成字段类型为错误的oid,正确应是text | ||
|
||
/** | ||
* 文本 or json字符串存储字段 | ||
*/ | ||
@Lob | ||
@Basic(fetch = FetchType.LAZY) | ||
@Column(name = "config_text") | ||
private String configText; // jpa默认生成正确的字段类型为text | ||
|
||
/** | ||
* 创建时间 | ||
*/ | ||
@Column(name = "create_time", nullable = false) | ||
@CreatedDate | ||
private LocalDateTime createTime; | ||
|
||
/** | ||
* 最后一次修改时间 | ||
*/ | ||
@Column(name = "last_modified_date") | ||
@LastModifiedDate | ||
private LocalDateTime lastModifiedDate; | ||
|
||
|
||
// 以下是实现懒加载 | ||
|
||
@Transient | ||
private PersistentAttributeInterceptor interceptor; | ||
|
||
@Override | ||
public PersistentAttributeInterceptor $$_hibernate_getInterceptor() { | ||
return interceptor; | ||
} | ||
|
||
@Override | ||
public void $$_hibernate_setInterceptor(PersistentAttributeInterceptor interceptor) { | ||
this.interceptor = interceptor; | ||
} | ||
|
||
// 需手动添加懒加载字段的 getXXX()方法 | ||
public Object getConfigJson() { | ||
if (this.configJson != null) { | ||
return this.configJson; | ||
} | ||
return interceptor.readObject(this, "configJson", this.configJson); | ||
} | ||
|
||
public Object getConfigText() { | ||
// 避免二次读取数据库 | ||
if (this.configText != null) { | ||
return this.configText; | ||
} | ||
return interceptor.readObject(this, "configText", this.configText); | ||
} | ||
|
||
public void setConfigJson(JSONObject configJson) { | ||
if (configJson != null) { | ||
interceptor.writeObject(this, "configJson", this.configJson, configJson); | ||
} | ||
this.configJson = configJson; | ||
} | ||
|
||
public void setConfigText(String configText) { | ||
if (configText != null) { | ||
interceptor.writeObject(this, "configText", this.configText, configText); | ||
} | ||
this.configText = configText; | ||
} | ||
} | ||
|
||
``` | ||
|
||
测试 | ||
|
||
```java | ||
@Transactional | ||
public Project queryById() { | ||
String id = "1719883977407"; | ||
Optional<Project> optional = repo.findById(id); | ||
Project entity = optional.get(); | ||
System.out.println(entity.getName()); | ||
//懒加载字段 | ||
System.out.println(entity.getConfigJson()); | ||
System.out.println(entity.getConfigText()); | ||
return entity; | ||
} | ||
``` | ||
|
||
### 实现方式二(推荐):采用 hibernate-enhance-maven-plugin 不推荐,偶尔遇到不生效 | ||
|
||
可能需要频繁编译maven项目,才会生效 | ||
|
||
pom.xml文件 | ||
|
||
```xml | ||
|
||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>org.hibernate.orm.tooling</groupId> | ||
<artifactId>hibernate-enhance-maven-plugin</artifactId> | ||
<version>${hibernate.version}</version> | ||
<executions> | ||
<execution> | ||
<configuration> | ||
<!--启用简单字段的延迟加载--> | ||
<enableLazyInitialization>true</enableLazyInitialization> | ||
</configuration> | ||
<goals> | ||
<goal>enhance</goal> | ||
</goals> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
``` | ||
|
||
配置文件(可选地,有些版本不需要配置): | ||
|
||
```yaml | ||
spring: | ||
jpa: | ||
properties: | ||
hibernate: | ||
enable_lazy_load_no_trans: true # 可选地 | ||
# open-in-view: true # 默认false,可选地,若出现懒加载异常可打开 | ||
``` | ||
|
||
实体字段: | ||
|
||
```java | ||
|
||
@Getter | ||
@Setter | ||
@Entity | ||
@Table(name = "t_project") | ||
@EntityListeners(value = AuditingEntityListener.class) | ||
public class Project { | ||
|
||
@Id | ||
private String id = String.valueOf(System.currentTimeMillis()); | ||
|
||
/** | ||
* 名称 | ||
*/ | ||
@Column(nullable = false, length = 100) | ||
private String name; | ||
|
||
/** | ||
* json 字符串存储字段 | ||
*/ | ||
@Lob | ||
// @Lazy // 未生效 | ||
@Basic(fetch = FetchType.LAZY) | ||
@Column(name = "config_json") | ||
private JSONObject configJson; // jpa默认生成字段类型为错误的oid,正确应是text | ||
|
||
/** | ||
* 文本 or json字符串存储字段 | ||
*/ | ||
@Lob | ||
@Basic(fetch = FetchType.LAZY) | ||
@Column(name = "config_text") | ||
private String configText; // jpa默认生成正确的字段类型为text | ||
|
||
/** | ||
* 创建时间 | ||
*/ | ||
@Column(name = "create_time", nullable = false) | ||
@CreatedDate | ||
private LocalDateTime createTime; | ||
} | ||
|
||
``` | ||
|
||
测试 | ||
|
||
```java | ||
|
||
@Test | ||
public void findAllPage_test() { | ||
int page = 0; | ||
int size = 2; | ||
Sort sort = Sort.by(Sort.Direction.DESC, "createTime"); | ||
|
||
// 查询条件 | ||
Project request = new Project(); | ||
request.setName("名称-1"); | ||
Specification<Project> spec = buildQuery(request); | ||
|
||
Page<Project> pageEntity = repo.findAll(spec, PageRequest.of(page, size, sort)); // 支持懒加载 | ||
List<Project> projectList = pageEntity.getContent(); | ||
projectList.forEach(project -> { | ||
System.out.println(project.getId()); | ||
System.out.println(project.getName()); | ||
System.out.println(project.getCreateTime()); | ||
System.out.println(project.getLastModifiedDate()); | ||
System.out.println("-------------特殊字段-------------"); | ||
System.out.println(project.getConfigJson()); | ||
System.out.println(project.getConfigText()); | ||
System.out.println("--------------------------"); | ||
}); | ||
} | ||
|
||
private Specification<Project> buildQuery(Project request) { | ||
// 构建查询条件 | ||
return (root, query, cb) -> { | ||
List<Predicate> predicates = new ArrayList<>(); | ||
// 关键词 | ||
if (!StringUtils.isEmpty(request.getName())) { | ||
predicates.add(cb.like(root.get("name"), request.getName() + "%")); | ||
} | ||
// 将条件连接在一起 | ||
return query.where(predicates.toArray(new Predicate[0])).getRestriction(); | ||
}; | ||
} | ||
``` | ||
|
||
测试结果: | ||
|
||
```text | ||
Hibernate: select project0_.id as id1_0_, project0_.create_time as create_t4_0_, project0_.cycle as cycle5_0_, project0_.internal as internal6_0_, project0_.last_modified_date as last_mod7_0_, project0_.name as name8_0_, project0_.remarks as remarks9_0_, project0_.sort as sort10_0_, project0_.state as state11_0_ from t_project project0_ where project0_.name like ? order by project0_.create_time desc limit ? | ||
1719883977407 | ||
名称-1 | ||
2024-07-02T09:32:57.781 | ||
2024-07-02T09:32:57.781 | ||
-------------特殊字段------------- | ||
Hibernate: select project_.config_json as config_j2_0_, project_.config_text as config_t3_0_ from t_project project_ where project_.id=? | ||
{"key":"value"} | ||
大文本字段 | ||
-------------------------- | ||
``` | ||
|
||
会再次查询懒加载字段。 | ||
|
||
测试: | ||
|
||
```text | ||
System.out.println("-------------特殊字段-------------"); | ||
// System.out.println(project.getConfigJson()); | ||
// System.out.println(project.getConfigText()); | ||
System.out.println("--------------------------"); | ||
``` | ||
|
||
测试结果: | ||
|
||
```text | ||
Hibernate: select project0_.id as id1_0_, project0_.create_time as create_t4_0_, project0_.cycle as cycle5_0_, project0_.internal as internal6_0_, project0_.last_modified_date as last_mod7_0_, project0_.name as name8_0_, project0_.remarks as remarks9_0_, project0_.sort as sort10_0_, project0_.state as state11_0_ from t_project project0_ where project0_.name like ? order by project0_.create_time desc limit ? | ||
1719883977407 | ||
名称-1 | ||
2024-07-02T09:32:57.781 | ||
2024-07-02T09:32:57.781 | ||
-------------特殊字段------------- | ||
-------------------------- | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 changes: 75 additions & 0 deletions
75
starter-data/starter-data-jpa/src/main/java/com/zja/controller/ProjectController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package com.zja.controller; | ||
import com.zja.model.dto.PageData; | ||
import com.zja.model.dto.ProjectDTO; | ||
import com.zja.model.dto.ProjectPageDTO; | ||
import com.zja.model.request.ProjectPageRequest; | ||
import com.zja.model.request.ProjectRequest; | ||
import com.zja.model.request.ProjectUpdateRequest; | ||
import com.zja.service.project.ProjectService; | ||
import io.swagger.annotations.Api; | ||
import io.swagger.annotations.ApiOperation; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.validation.annotation.Validated; | ||
import org.springframework.web.bind.annotation.*; | ||
|
||
import javax.validation.Valid; | ||
import javax.validation.constraints.NotBlank; | ||
import java.util.List; | ||
|
||
/** | ||
* 项目 接口层(一般与页面、功能对应) | ||
* @author: zhengja | ||
* @since: 2024/09/27 9:27 | ||
*/ | ||
@Validated | ||
@RestController | ||
@RequestMapping("/rest/project") | ||
@Api(tags = {"项目管理页面"}) | ||
public class ProjectController { | ||
|
||
@Autowired | ||
ProjectService service; | ||
|
||
@GetMapping("/query/{id}") | ||
@ApiOperation("查询单个项目详情") | ||
public ProjectDTO queryById(@NotBlank @PathVariable("id") String id) { | ||
return service.queryById(id); | ||
} | ||
|
||
@GetMapping("/page/list") | ||
@ApiOperation("分页查询项目列表") | ||
public PageData<ProjectPageDTO> pageList(@Valid ProjectPageRequest pageRequest) { | ||
return service.pageList(pageRequest); | ||
} | ||
|
||
@PostMapping("/add") | ||
@ApiOperation("添加项目") | ||
public ProjectDTO add(@Valid @RequestBody ProjectRequest request) { | ||
return service.add(request); | ||
} | ||
|
||
@PostMapping("/add/batch") | ||
@ApiOperation("批量添加项目") | ||
public List<ProjectDTO> add(@Valid @RequestBody List<ProjectRequest> orgRequests) { | ||
return service.addBatch(orgRequests); | ||
} | ||
|
||
@PutMapping("/update/{id}") | ||
@ApiOperation("更新项目") | ||
public ProjectDTO update(@NotBlank @PathVariable("id") String id, | ||
@Valid @RequestBody ProjectUpdateRequest updateRequest) { | ||
return service.update(id, updateRequest); | ||
} | ||
|
||
@DeleteMapping("/delete/{id}") | ||
@ApiOperation("删除项目") | ||
public boolean deleteById(@NotBlank @PathVariable("id") String id) { | ||
return service.deleteById(id); | ||
} | ||
|
||
@DeleteMapping("/delete/batch") | ||
@ApiOperation("批量删除项目") | ||
public void deleteBatch(@RequestBody List<String> ids) { | ||
service.deleteBatch(ids); | ||
} | ||
} |
Oops, something went wrong.