【问题标题】:Lazy initialization of OnetoOne mapping when update fired for second time第二次触发更新时延迟初始化 OnetoOne 映射
【发布时间】:2019-09-14 13:17:28
【问题描述】:

我试图理解为什么当我第二次点击控制器时,我的 OnetoOne 映射正在初始化。下面是我的代码: 控制器:

@RequestMapping(value="/updateOrderbyOrderid", method=RequestMethod.PUT,produces=MediaType.APPLICATION_JSON_VALUE)
public Order updateOrderbyOrderid (@RequestBody Order orderVO ) {

System.out.println(orderVO.getOrderId());
Order s1 = orderRepository.findByOrderId(orderVO.getOrderId());
if (orderVO.getCustomerId()!=null) {
    orderVO.setCustomer(customerRepository.findByCustomerId(orderVO.getCustomerId()));
}

s1 = orderRepository.saveAndFlush(orderVO);

return s1;
}

订单实体:

@Entity
@Table(name="Ordertable", schema="cf_2583f365_c3c6_499a_a60d_138e7e7023eb")
public class Order {
@Id
@Column(name = "ORDER_ID")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int orderId;



@OneToOne(fetch=FetchType.LAZY,cascade=CascadeType.ALL)
@JoinColumn(name = "ORDER_CUSTOMER_ID", referencedColumnName = "CUSTOMER_ID")
private Customer customer;

private transient Long customerId;


public int getOrderId() {
    return orderId;
}

public void setOrderId(int orderId) {
    this.orderId = orderId;
}

public Customer getCustomer() {
    return customer;
}

public void setCustomer(Customer customer) {
    this.customer = customer;
}


public Long getCustomerId() {
    return customerId;
}

public void setCustomerId(Long customerId) {
    this.customerId = customerId;
}

}

客户实体:

@Entity
@Table(name="Customer", schema="cf_2583f365_c3c6_499a_a60d_138e7e7023eb")
public class Customer {

@Id
@Column(name = "CUSTOMER_ID")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long customerId;

@Column(name = "CUSTOMER_NAME")
private String customer_name;


@Column(name = "CUSTOMER_address_id")
private int customer_address_id;


public Long getCustomerId() {
    return customerId;
}


public void setCustomerId(Long customerId) {
    this.customerId = customerId;
}


public String getCustomer_name() {
    return customer_name;
}


public void setCustomer_name(String customer_name) {
    this.customer_name = customer_name;
}


public int getCustomer_address_id() {
    return customer_address_id;
}


public void setCustomer_address_id(int customer_address_id) {
    this.customer_address_id = customer_address_id;
}


public Customer() {

}

}

Controller的Json结构:

{
    "orderId" :101,
    "customerId" : 2
}

首发订单表:

第一次点击的 OnetoOne 注释实体截图。 customerRepository.findByCustomerId(orderVO.getCustomerId()) 没有惰性初始化 bean:

第二次命中的订单表:

当我第二次点击时,我得到一个用于 customerRepository.findByCustomerId(orderVO.getCustomerId()) 的延迟加载 bean。为什么会这样:

我的期望是当我执行 orderVO.setCustomer(customerRepository.findByCustomerId(orderVO.getCustomerId()));而不是分配它从 Order s1 = orderRepository.findByOrderId(orderVO.getOrderId()); 获得的惰性初始化 bean;

一个重要的注意事项,如果我在控制器下面的行评论:

Order s1 = orderRepository.findByOrderId(orderVO.getOrderId()); :

并用 Order s1 = null 替换它,我不再懒惰初始化 bean。 hibernate 缓存同一个惰性初始化的bean之前在内部吗??

我没有评论时 s1 的屏幕截图:

注释 s1 并将其替换为 null 后的代码:

@RequestMapping(value="/updateOrderbyOrderid", method=RequestMethod.PUT,produces=MediaType.APPLICATION_JSON_VALUE)
public Order updateOrderbyOrderid (@RequestBody Order orderVO ) {
System.out.println(orderVO.getOrderId());
Order s1 = null;
//Order s1 = orderRepository.findByOrderId(orderVO.getOrderId());
if (orderVO.getCustomerId()!=null) {
    orderVO.setCustomer(customerRepository.findByCustomerId(orderVO.getCustomerId()));
}

s1 = orderRepository.saveAndFlush(orderVO);

return s1;
}

【问题讨论】:

  • 您的期望是什么?
  • 我的期望是当我做 orderVO.setCustomer(customerRepository.findByCustomerId(orderVO.getCustomerId()));而不是分配从 Order s1 = orderRepository.findByOrderId(orderVO.getOrderId()); 获得的惰性初始化 bean;
  • 尝试创建一个 OrderVO 类作为一个简单的 POJO(没有 Hibernate 注释),只包含 customerIdorderId 字段,并使用它来收集 JSON 值。然后使用此值从存储库中获取 OrderCustomer。我认为使用托管实体来收集 JSON 值不是一个好主意,托管实体必须仅用于持久性。
  • @JMSilla 我也试过这个,但得到了相同的结果。你也可以在你的电脑上试试这个。

标签: java spring hibernate spring-boot spring-data-jpa


【解决方案1】:

Spring Data JPA - findBy() 方法在内部由 EntityManager.find() 实现。 EntityManager.find()首先检查缓存中的数据,如果在缓存中没有找到数据,则点击数据库加载数据并放入缓存中进行管理。

如果我们再次执行EntityManager.find()(同样的主键),它会再次检查缓存。现在这一次是从缓存中加载数据而不是访问数据库。

我认为 Hibernate 正在缓存对象,当我第二次点击它时,它会返回缓存项的代理对象。

以下是我为了解findBy() 工作而阅读的链接。

When use getOne and findOne methods Spring Data JPA

similar load and get hibernate method on spring data

What is the difference between EntityManager.find() and EntityManger.getReference()?

现在为了测试我是否正确,我在下面的代码中使用了em.detach()detach() 将使托管实体 --> 非托管,并将其从缓存中删除。现在,当我执行代码时,我得到了新初始化的 bean。

@RequestMapping(value="/updateOrderbyOrderid", method=RequestMethod.PUT,produces=MediaType.APPLICATION_JSON_VALUE)
public Order updateOrderbyOrderid (@Valid @RequestBody Order orderVO ) {
    
    System.out.println(orderVO.getOrderId());
    Order s1 = orderRepository.findByOrderId(orderVO.getOrderId());
    em.detach(s1.getCustomer());
    s1= null;
    if (orderVO.getCustomerId()!=null) { 
        Customer findByCustomerId = customerRepository.findByCustomerId(orderVO.getCustomerId());
        orderVO.setCustomer(customerRepository.findByCustomerId(orderVO.getCustomerId()));
    }

    s1 = orderRepository.saveAndFlush(orderVO);
    
    return s1;
}

【讨论】:

    【解决方案2】:

    我认为您必须使用 fetch=FetchType.EAGER 进行 OneToOne 映射

    @OneToOne(fetch=FetchType.EAGER,cascade=CascadeType.ALL)
    @JoinColumn(name = "ORDER_CUSTOMER_ID", referencedColumnName = "CUSTOMER_ID")
    private Customer customer;
    

    希望它会有所帮助。

    【讨论】:

    • 我是使用spring data jpa来获取数据,而不是直接使用hibernate实体管理器。所以急切不会对它产生影响。请参阅此网址:stackoverflow.com/q/56248867/4860775。也可以在您的 PC 上试用。
    • 1:1 默认为 EAGER。
    【解决方案3】:

    您的映射看起来很像多对多。试试这个:

    // OrderTable
    @OneToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "CUSTOMER_ID", nullable = false)
    private Customer customer;
    // constructors
    public OrderTable() {}
    public OrderTable(Customer customer) { this.customer = customer; }
    
    
    // Customer
    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "customer")
    private OrderTable orderTable;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-10
      • 2016-06-16
      • 1970-01-01
      • 2011-11-17
      • 1970-01-01
      • 2014-07-11
      相关资源
      最近更新 更多