JavaSpringBoot2.0.4+Hibernate5在不调用getter的情况下获取控制器范围外的惰性集合
我有一个SpringBootWeb应用程序,它使用SpringJPA的hibernate实现。我使用连接列注释处理实体之间的一对多关系。为了实现这一点,技术实体有一个成员列表。我已将此列表标记为已初始化。一切都很好,但一旦控件移到控制器外部,hibernate就会触发对惰性集合(列表)的调用,而不调用它。这会导致加载网页的巨大延迟。不确定为什么hibernate在控制器范围外触发惰性集合。我试过使用Hibernate。初始化和Maven字节码增强插件,但似乎什么都不起作用。请帮忙
实体
@Entity
@Table(name="EmergentTechnologies")
public class EmergentTechnology implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="ID")
private int id;
@OneToMany
@JoinColumn(name="ETID")
@Basic(fetch = FetchType.LAZY)
private List<Artifact> artifacts;
@Entity
@Table(name="Artifacts")
public class Artifact implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="ID")
private int id;
@Column(name="Analyst")
private String analyst;
@Column(name="ArtifactType")
private String artifactType;
应用程序属性
spring.mvc.favicon.enabled=false
logging.level.com.boeing.etl=INFO
spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.jpa.generate-ddl=false
spring.jpa.show-sql=true
spring.jpa.hibernate.dialect=org.hibernate.dialect.SQLServer2012Dialect
波姆。xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cloud-connectors</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>sqljdbc4</artifactId>
<version>4.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.hibernate.orm.tooling</groupId>
<artifactId>hibernate-enhance-maven-plugin</artifactId>
<version>${hibernate.version}</version>
<executions>
<execution>
<configuration>
<failOnError>true</failOnError>
<enableLazyInitialization>true</enableLazyInitialization>
</configuration>
<goals>
<goal>enhance</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
控制器
@RequestMapping(value = "/artifacts", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity<List<EmergentTechnology>> getAllArtifactsByEmergentTech(@RequestParam("id") String id) {
logger.info("Enter getAllArtifactsByEmergentTech");
int emergentTechId=Integer.parseInt(id);
List<EmergentTechnology> emergentTechnology = emergingTechLibService.getAllArtifactsByEmergentTech(emergentTechId);
logger.info("Exit getAllArtifactsByEmergentTech");
return ResponseEntity.status(HttpStatus.OK).body(emergentTechnology);
}
服务
@Override
public List<EmergentTechnology> getAllArtifactsByEmergentTech(int emergentTechId) {
logger.info("Enter getAllArtifactsByEmergentTech");
List<EmergentTechnology> emergentTechnologies=emergentTechnologyRepository.getAllArtifactsById(emergentTechId);
//Optional<EmergentTechnology> emergentTechnology=emergentTechnologyRepository.findById(emergentTechId);
//emergentTechnologies.add(emergentTechnology.get());
logger.info("After calling findAllArtifactsById()");
return emergentTechnologies;
}
存储库
@Override
public List<EmergentTechnology> getAllArtifactsById(int emergentTechId) {
logger.info("Enter getEmergentTechnologies");
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<EmergentTechnology> criteriaQuery = criteriaBuilder.createQuery(EmergentTechnology.class);
Root<EmergentTechnology> root = criteriaQuery.from(EmergentTechnology.class);
criteriaQuery.select(root);
criteriaQuery.where(criteriaBuilder.equal(root.<Integer>get("id"), emergentTechId));
List<EmergentTechnology> emergingTechnologies = entityManager.createQuery(criteriaQuery).getResultList();
logger.info("Exit getEmergentTechnologies");
return emergingTechnologies;
}
当控件移出控制器时加载所有工件(根据应用程序日志)
# 1 楼答案
你似乎有1+N问题。您可以让hibernate在一个查询中加载所有数据。要做到这一点,您可以使用fetch join和您的条件
另一个让hibernate通过一个查询获取所有数据的选项是使用named entity graph
虽然我不确定这会解决你所有的问题,但你仍然应该看到性能的提高
此外,根据数据的性质(在我看来,这是一组不会太大、也不会经常改变的信息),您可以充分利用spring caching,它非常适合您的用例
还有一个选项是使用hibernate query cache
# 2 楼答案
回答之前有一件事:不要将实体作为rest服务的响应返回,因为您正在将服务的使用者耦合到数据库,因此这是一种不好的做法
现在答案是:当你的控制器返回一个包含在ResponseEntity中的列表时@ResponseBody注释意味着方法的返回值将构成HTTP响应的主体。由于响应中不允许使用Java对象,因此必须将它们序列化为适合REST应用程序的格式,即JSON或XML(这将取决于RequestMapping注释的products属性的值,以及客户端接受的内容类型)。由于这个系列化过程,将调用EmergentTechnology对象(由Hibernate管理,因此它们是代理的)中的getter方法。此调用将导致获取工件列表
因此,您需要做的是将实体映射到服务EmergingTechLibService(我建议MapStruct)中的VO(避免耦合)中,避免调用工件的获取者