Performance 为什么JPA/Eclipselink即使使用BatchFetchType.IN提示也会触发冗余数据库查询?
摘要: 我正在努力减少基于JPA的java应用程序对数据库的查询数量。我指定了<代码> @ BatchFetch(BotFutChyType in)<代码>优化提示,但我仍然看到一些额外的查询,我认为这是多余的和不必要的。 详细信息:Performance 为什么JPA/Eclipselink即使使用BatchFetchType.IN提示也会触发冗余数据库查询?,performance,jpa,optimization,eclipselink,Performance,Jpa,Optimization,Eclipselink,摘要: 我正在努力减少基于JPA的java应用程序对数据库的查询数量。我指定了 @ BatchFetch(BotFutChyType in)优化提示,但我仍然看到一些额外的查询,我认为这是多余的和不必要的。 详细信息: 考虑一个简单的领域模型:我们有发票管理系统。发票与订单具有一对一关系。我们还有客户,客户与订单有一对一的关系(Customer 1->M Order 1在EclipseLink中看起来像是一个错误/问题,因为对象模型中的急切关系允许在加载引用发票的订单之前在“in”中加载第二张发
考虑一个简单的领域模型:我们有发票管理系统。发票与订单具有一对一关系。我们还有客户,客户与订单有一对一的关系(Customer 1->M Order 1在EclipseLink中看起来像是一个错误/问题,因为对象模型中的急切关系允许在加载引用发票的订单之前在“in”中加载第二张发票。这迫使发票在数据库中查询订单,而不是在缓存中查找订单 您可以通过在发票到订单关系上使用延迟抓取来解决此问题。此延迟将允许EclipseLink完全构建对象模型,以便在访问对象模型时将其放在缓存中。问题中的代码显示此关系标记为延迟,但这只是对无法在EclipseLink中使用O的JPA提供程序的提示ut使用代理或字节码编织,如下所述:
惰性集合不需要编织,只有1:1和其他优化才需要编织。尝试添加一些调试语句,以查看最后两个查询何时执行(即是在构建订单列表时,还是在调用order.getInvoice()时)。还要检查orders、Customer或Invoice中是否有任何方法可以访问对象不完整的关系,例如在toString方法中。所有查询都在order.getInvoice()语句中执行。所有字段(包括关系)都在每个对象的toString方法中使用;但由于(111222)已在第二个查询中加载,为什么在第四个查询中再次显式调用订单222?您的意思是最后3个是在第一个订单上执行的。getInvoice()调用?尝试更改toString方法以防止加载惰性属性,和/或添加调试以查看是否是触发查询的原因。您可能会将日志设置为finest,以便显示EclipseLink消息以及SQLI。源代码zip文件包含对OpenJPA的生成路径和persistence.xml引用,而不是E你到底为什么一直在谈论EclipseLink?你只是对不同的JPA实现感到困惑吗?当你说EclipseLink时,你是真的想说OpenJPA吗?还是你无意中提供了错误的源代码文件,因为你也用OpenJPA进行了测试,但在一次测试中发现了相同的问题d因此打算忽略它?是的,我将提供程序更改为EclipseLink,而不是继续使用OpenJPA。共享代码是为了提供实际的数据模型,但我已将persistence.xml更改为EclipseLink,并将提供程序更新为EclipseLink。是的,使用lazy works。问题只出现在急切获取发票->订单关系时。如果它被标记为懒惰,并且使用了编织,在我使用您的类进行的测试中不会出现这种情况。有没有计划在EclipseLink中尽快解决此问题?即使在EclipseLink 2.6.3中,此错误仍然存在。
@Entity(name = "CUSTOMER")
public class Customer {
@Id //signifies the primary key
@Column(name = "CUST_ID", nullable = false)
@GeneratedValue(strategy = GenerationType.AUTO)
private long custId;
@Column(name = "FIRST_NAME", length = 50)
private String firstName;
@OneToMany(mappedBy="customer",targetEntity=Order.class,
fetch=FetchType.LAZY)
private Collection<Order> orders;
}
@Entity(name = "ORDERS")
public class Order {
@Id
@Column(name = "ORDER_ID", nullable = false)
@GeneratedValue(strategy = GenerationType.AUTO)
private long orderId;
@Column(name = "TOTAL_PRICE", precision = 2)
private double totPrice;
@OneToOne(fetch = FetchType.LAZY, optional = false, cascade = CascadeType.ALL, mappedBy = "order")
private Invoice invoice;
@ManyToOne(optional = false)
@JoinColumn(name = "CUST_ID", referencedColumnName = "CUST_ID")
private Customer customer;
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "ORDER_DETAIL", joinColumns = @JoinColumn(name = "ORDER_ID", referencedColumnName = "ORDER_ID"), inverseJoinColumns = @JoinColumn(name = "PROD_ID", referencedColumnName = "PROD_ID"))
private List<Product> productList;
}
@Entity(name = "ORDER_INVOICE")
public class Invoice {
@Id
// signifies the primary key
@Column(name = "INVOICE_ID", nullable = false)
@GeneratedValue(strategy = GenerationType.AUTO)
private long invoiceId;
@Column(name = "AMOUNT_DUE", precision = 2)
private double amountDue;
@OneToOne(optional = false, fetch = FetchType.LAZY)
@JoinColumn(name = "ORDER_ID")
private Order order;
}
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("testjpa");
EntityManager em = entityManagerFactory.createEntityManager();
Customer customer = em.find(Customer.class, 100L);
Collection<Order> orders = customer.getOrders();
for(Order order: orders){
System.out.println(order.getInvoice().getInvoiceId());
}
em.close();
1398882535950|1|1|statement|SELECT CUST_ID, APPT, CITY, EMAIL, FIRST_NAME, LAST_NAME, STREET, LAST_UPDATED_TIME, ZIP_CODE FROM CUSTOMER WHERE (CUST_ID = ?)|SELECT CUST_ID, APPT, CITY, EMAIL, FIRST_NAME, LAST_NAME, STREET, LAST_UPDATED_TIME, ZIP_CODE FROM CUSTOMER WHERE (CUST_ID = 100)
1398882535981|0|1|statement|SELECT ORDER_ID, OREDER_DESC, ORDER_DATE, TOTAL_PRICE, LAST_UPDATED_TIME, CUST_ID FROM ORDERS WHERE (CUST_ID = ?)|SELECT ORDER_ID, OREDER_DESC, ORDER_DATE, TOTAL_PRICE, LAST_UPDATED_TIME, CUST_ID FROM ORDERS WHERE (CUST_ID = 100)
1398882535995|1|1|statement|SELECT INVOICE_ID, AMOUNT_DUE, DATE_CANCELLED, DATE_RAISED, DATE_SETTLED, LAST_UPDATED_TIME, ORDER_ID FROM ORDER_INVOICE WHERE (ORDER_ID = ?)|SELECT INVOICE_ID, AMOUNT_DUE, DATE_CANCELLED, DATE_RAISED, DATE_SETTLED, LAST_UPDATED_TIME, ORDER_ID FROM ORDER_INVOICE WHERE (ORDER_ID = 111)
1398882536004|0|1|statement|SELECT INVOICE_ID, AMOUNT_DUE, DATE_CANCELLED, DATE_RAISED, DATE_SETTLED, LAST_UPDATED_TIME, ORDER_ID FROM ORDER_INVOICE WHERE (ORDER_ID = ?)|SELECT INVOICE_ID, AMOUNT_DUE, DATE_CANCELLED, DATE_RAISED, DATE_SETTLED, LAST_UPDATED_TIME, ORDER_ID FROM ORDER_INVOICE WHERE (ORDER_ID = 222)
@Entity(name = "ORDERS")
public class Order {
@Id
@Column(name = "ORDER_ID", nullable = false)
@GeneratedValue(strategy = GenerationType.AUTO)
private long orderId;
@Column(name = "TOTAL_PRICE", precision = 2)
private double totPrice;
@BatchFetch(BatchFetchType.IN)
@OneToOne(fetch = FetchType.LAZY, optional = false, cascade = CascadeType.ALL, mappedBy = "order")
private Invoice invoice;
@ManyToOne(optional = false)
@JoinColumn(name = "CUST_ID", referencedColumnName = "CUST_ID")
private Customer customer;
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "ORDER_DETAIL", joinColumns = @JoinColumn(name = "ORDER_ID", referencedColumnName = "ORDER_ID"), inverseJoinColumns = @JoinColumn(name = "PROD_ID", referencedColumnName = "PROD_ID"))
private List<Product> productList;
}
1398883197009|1|1|statement|SELECT CUST_ID, APPT, CITY, EMAIL, FIRST_NAME, LAST_NAME, STREET, LAST_UPDATED_TIME, ZIP_CODE FROM CUSTOMER WHERE (CUST_ID = ?)|SELECT CUST_ID, APPT, CITY, EMAIL, FIRST_NAME, LAST_NAME, STREET, LAST_UPDATED_TIME, ZIP_CODE FROM CUSTOMER WHERE (CUST_ID = 100)
1398883197030|0|1|statement|SELECT ORDER_ID, OREDER_DESC, ORDER_DATE, TOTAL_PRICE, LAST_UPDATED_TIME, CUST_ID FROM ORDERS WHERE (CUST_ID = ?)|SELECT ORDER_ID, OREDER_DESC, ORDER_DATE, TOTAL_PRICE, LAST_UPDATED_TIME, CUST_ID FROM ORDERS WHERE (CUST_ID = 100)
1398883197037|1|1|statement|SELECT INVOICE_ID, AMOUNT_DUE, DATE_CANCELLED, DATE_RAISED, DATE_SETTLED, LAST_UPDATED_TIME, ORDER_ID FROM ORDER_INVOICE WHERE (ORDER_ID IN (?,?))|SELECT INVOICE_ID, AMOUNT_DUE, DATE_CANCELLED, DATE_RAISED, DATE_SETTLED, LAST_UPDATED_TIME, ORDER_ID FROM ORDER_INVOICE WHERE (ORDER_ID IN (111,222))
1398883197042|1|1|statement|SELECT ORDER_ID, OREDER_DESC, ORDER_DATE, TOTAL_PRICE, LAST_UPDATED_TIME, CUST_ID FROM ORDERS WHERE (ORDER_ID = ?)|SELECT ORDER_ID, OREDER_DESC, ORDER_DATE, TOTAL_PRICE, LAST_UPDATED_TIME, CUST_ID FROM ORDERS WHERE (ORDER_ID = 222)
1398883197045|0|1|statement|SELECT INVOICE_ID, AMOUNT_DUE, DATE_CANCELLED, DATE_RAISED, DATE_SETTLED, LAST_UPDATED_TIME, ORDER_ID FROM ORDER_INVOICE WHERE (ORDER_ID = ?)|SELECT INVOICE_ID, AMOUNT_DUE, DATE_CANCELLED, DATE_RAISED, DATE_SETTLED, LAST_UPDATED_TIME, ORDER_ID FROM ORDER_INVOICE WHERE (ORDER_ID = 222)