ID为字符串时为N + 1(JpaRepository)

Fee*_*eco 3 java hibernate jpa spring-data spring-data-jpa

我有一个字符串ID为的实体:

@Table
@Entity
public class Stock {

    @Id
    @Column(nullable = false, length = 64)
    private String index;

    @Column(nullable = false)
    private Integer price;

}
Run Code Online (Sandbox Code Playgroud)

和JpaRepository:

public interface StockRepository extends JpaRepository<Stock, String> {
}
Run Code Online (Sandbox Code Playgroud)

当我打电话时stockRepository::findAll,我有N + 1问题:

日志简化了

选择s.index,s.price from stock s
select s.index,s.price from stock s where s.index =?

报价的最后一行调用约5K次(表的大小).另外,当我更新价格时,我会做下一步:

stockRepository.save(listOfStocksWithUpdatedPrices);
Run Code Online (Sandbox Code Playgroud)

在日志中我有N插入.
当id是数字时,我没有看到类似的行为.
在我的情况下,PS将id的类型设置为数字不是最佳解决方案.

更新1:
我忘了提到还有Trade与多对多关系的类Stock:

@Table
@Entity
public class Trade {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    @Column
    @Enumerated(EnumType.STRING)
    private TradeType type;

    @Column
    @Enumerated(EnumType.STRING)
    private TradeState state;

    @MapKey(name = "index")
    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "trade_stock",
        joinColumns = { @JoinColumn(name = "id", referencedColumnName = "id") },
        inverseJoinColumns = { @JoinColumn(name = "stock_index", referencedColumnName = "index") })
    private Map<String, Stock> stocks = new HashMap<>();

}
Run Code Online (Sandbox Code Playgroud)

UPDATE2:
我为这一Stock方添加了多对多的关系:

@ManyToMany(cascade = CascadeType.ALL, mappedBy = "stocks") //lazy by default
Set<Trade> trades = new HashSet<>();
Run Code Online (Sandbox Code Playgroud)

但现在它离开了加入交易(但它们很懒),以及所有交易的收藏品(它们也很懒).但是,生成的Stock::toString方法抛出LazyInitializationException异常.

mal*_*ouk 5

相关回答:JPA eager fetch不加入

你基本上需要设置@Fetch(FetchMode.JOIN),因为fetch = FetchType.EAGER只是指定将加载关系,而不是如何加载.

另外,对于您的问题可能有帮助的是 @BatchSize注释,它指定在请求第一个时,将加载多少个延迟集合.例如,如果您在内存中有100 交易(股票未初始化)@BatchSize(size = 50)将确保仅使用2个查询.有效地将n + 1改为(n + 1)/ 50. https://docs.jboss.org/hibernate/orm/4.3/javadocs/org/hibernate/annotations/BatchSize.html

关于插入,您可能需要设置 hibernate.jdbc.batch_size属性并将order_inserts和order_updates设置为true. https://vladmihalcea.com/how-to-batch-insert-and-update-statements-with-hibernate/