Jimmy Lee Notes Take notes, Reading...

JPA join查询使用

2016-11-18
Jimmy Lee
ORM

前言

使用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



上一篇 spring aop笔记

下一篇 JPA 更新entity


Comments