前言
使用spring jpa作为orm工具,有一个单向一对多关系,进行查询的问题,不加额外处理会有n+1问题
spring jpa version:1.10.1
底层hibernate: 5.1.0
步骤一, 定义自定义的repository
@NoRepositoryBean
public interface CustomRepository<T, ID extends Serializable> extends JpaRepository<T, ID>, JpaSpecificationExecutor<T> {
Page<T> findAll(Specification<T> spec, Pageable pageable, EntityGraph.EntityGraphType entityGraphType, String entityGraphName);
Page<T> findAll(Specification<T> spec, Pageable pageable, String entityGraphName);
}
主要是使用EntityGraph
步骤二, 实现上面的repository
public class CustomRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements CustomRepository<T, ID> {
private EntityManager em;
public CustomRepositoryImpl(JpaEntityInformation entityInformation,
EntityManager entityManager) {
super(entityInformation, entityManager);
this.em = entityManager;
}
@Override
public Page<T> findAll(Specification<T> spec, Pageable pageable, EntityGraph.EntityGraphType entityGraphType, String entityGraphName) {
TypedQuery<T> query = getQuery(spec, pageable.getSort());
query.setHint(entityGraphType.getKey(), em.getEntityGraph(entityGraphName));
return readPage(query, pageable, spec);
}
@Override
public Page<T> findAll(Specification<T> spec, Pageable pageable, String entityGraphName) {
return findAll(spec, pageable, EntityGraph.EntityGraphType.FETCH, entityGraphName);
}
}
上面的实现类和其他正常的repository放在不同的package
entity的代码,添加EntityGraph
@Table(name = "XX_YY")
@NamedEntityGraphs({
@NamedEntityGraph(
name = "xxyyWithZZ",
attributeNodes = {
//跟下面的属性同名
@NamedAttributeNode("imgList")
}
)
})
public class XXYYEntity implements Serializable {
private static final long serialVersionUID = -3476018376851461504L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private long id;
@Column(name = "name", length = 45)
private String name;
@Column(name = "desc", length = 45)
private String desc;
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinColumn(name = "zz_id")
@Where(clause = "is_valid=1") //这个条件是加在XXYYZZ表的where条件里面的
private List<XXYYZZ> imgList;
}
XXYY表的id和XXYYZZ的zz_id进行join关联
步骤三, 配置
<jpa:repositories base-package="xxx.yyy.repository"
base-class="xxx.zzz.CustomRepositoryImpl"
transaction-manager-ref="transactionManager"
entity-manager-factory-ref="entityManagerFactory" />
如何使用
定义一个repository,继续最开始的自定义repository接口,然后在service里面组装好Specification,Pageable,并指定entigyGraph名称 进行调用
Page<XXYYEntity> content = xxyyRepository.findAll(spec, pageable, "xxyyWithZZ");
问题
1.若一个entity包括多个一对多关系,则需要把list换成set,否则报错,或者显示指定@IndexColumn 2.不使用上面的方式,直接定义一个repository,然后使用@EntityGraph注解
XXYYRepository extends JpaRepository<XXYYEntity, Long>,
JpaSpecificationExecutor<XXYYEntity> {
@EntityGraph("xxyyWithZZ")
List<XXYYEntity> getByIsValid(int valid);
}
假设xxyy有4条记录,前两条记录分别有2条XXYYZZ,则上述查询会返回6条记录,如下
1-{2条xxyyzz}
1-{2条xxyyzz}
2-{2条xxyyzz}
2-{2条xxyyzz}
3-
4-
后期可以看看为什么这么返回以及如何处理
参考
http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.at-query
http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.single-repository-behaviour