当前位置: 首页 > 知识库问答 >
问题:

为什么“findbyid()”在调用相同实体的getOne()后返回proxy?

楚苏燕
2023-03-14

在我的Web应用中,在服务布局中,我对“餐厅”实体使用代理(在“餐厅”字段上使用fetchtype.lazy)。

  User user = userRepository.get(userId);
  /*
     Getting proxy here, not restaurant object
  */
  Restaurant userRestaurantRef = user.getRestaurant();

  if (userRestaurantRef != null){
     restaurantRepository.decreaseRating(userRestaurantRef.getId());
  }

  restaurantRepository.increaseRating(restaurantId);
  /*
    "getReference" invokes "getOne()"
  */
  user.setRestaurant(restaurantRepository.getReference(restaurantId));
  userRepository.save(user);
mockMvc.perform(put(REST_URL + RESTAURANT1_ID)
                .param("time", "10:30")
                .with(userHttpBasic(USER)))
                .andExpect(status().isNoContent());

Restaurant restaurant = restaurantRepository.get(RESTAURANT1_ID);
Restaurant restaurantBefore = restaurantRepository.get(RESTAURANT1_ID);

mockMvc.perform(put(REST_URL + RESTAURANT1_ID)
                .param("time", "10:30")
                .with(userHttpBasic(USER)))
                .andExpect(status().isNoContent());

Restaurant restaurantAfter = restaurantRepository.get(RESTAURANT1_ID);

“get()”进入存储库:

    @Override
    public Restaurant get(int id) {
        return repository.findById(id).orElse(null);
    }

共有1个答案

蒋泰
2023-03-14

方法或服务类本身有@transaction注释吗?

这可以解释观察到的行为。

当在事务中执行方法时,从数据库获取或合并/保存到数据库的实体将被缓存,直到事务结束(通常是方法结束)。这意味着对具有相同ID的实体的任何调用都将直接从缓存返回,而不会命中数据库。

    null

回到您的示例

  • 首先调用findbyid(id),然后调用getone(id)为两者返回相同的实体对象
  • 首先调用getone(id),然后调用findbyid(id)为这两个调用返回相同的代理

这是因为它们共享相同的ID,并且在相同的事务中执行。

根据JPA持久化提供程序的实现方式,这很可能总是在第一次访问时返回一个实例并抛出一个EntityNotFoundException。其中一些会立即拒绝无效的标识符。

参数:id-不能为空。

返回:对具有给定标识符的实体的引用。

返回:具有给定id的实体,如果没有找到,则返回可选的#empty()

我花了一些时间寻找更好的解释,但没有找到,所以我不确定这是findbyid()实现中的一个bug,还是一个没有(很好地)记录的特性。

作为解决这个问题的变通办法,我可以建议:

    null
java prettyprint-override">import javax.persistence.EntityManager;
import org.springframework.transaction.annotation.Transactional;

@Transactional
@Service
public class SomeServiceImpl implements SomeService {

    private final SomeRepository repository;
    private final EntityManager entityManager;

    // constructor, autowiring

    @Override
    public void someMethod(long id) {
        SomeEntity getOne = repository.getOne(id); // Proxy -> added to cache

        entityManager.detach(getOne); // removes getOne from the cache

        SomeEntity findById = repository.findById(id).get(); // Entity from the DB
    }
import javax.persistence.EntityManager;
import org.springframework.transaction.annotation.Transactional;

@Transactional
@Service
public class SomeServiceImpl implements SomeService {

    private final SomeRepository repository;
    private final EntityManager entityManager;

    // constructor, autowiring

    @Override
    public void someMethod(long id) {
        SomeEntity getOne = repository.getOne(id); // Proxy -> added to cache

        entityManager.clear(); // clears the cache

        SomeEntity findById = repository.findById(id).get(); // Entity from the DB
    }
    null

编辑:

下面是一个简单的项目,演示了问题或特性(取决于观点)。

 类似资料:
  • > -返回类型是实体和 -返回类型为实体 过程1需要一个额外的步骤,使用optional.get()从optional中获取实体。有什么不同吗?你推荐哪一种?

  • } 我得到了下面的结果。但是在这个结果中,高亮显示的行具有相同的列名,但是别名不同。为什么hibernate会得到相同的Cloumn? 冬眠:删除表,如果存在hibernate_sequence hibernate:删除表(如果存在)UserDetails Hibernate:如果存在,则删除表车辆Hibernate:创建表hibernate_sequence(next_val bigint)En

  • 问题内容: 我在某处读到,函数应始终仅返回一种类型,因此以下代码被视为错误代码: 我想更好的解决方案是 返回None然后创建一个新的空元组不是更便宜的内存明智的选择吗?或者即使在较大的项目中,这种时差也太小而无法引起注意? 问题答案: 为什么函数应该返回一致类型的值?满足以下两个规则。 规则1-函数具有“类型”-输入映射到输出。它必须返回一致的结果类型,否则它不是函数。一团糟。 从数学上讲,我们说

  • 问题内容: 今天,我了解并决定将其使用和测试。我知道整数是不可变的,因此id应该是(?)相同。但是,当我在提示中进行测试时,我注意到了一些细微的差异,并想找出其背后的原因。 凉!到目前为止,所有签出。但是之后… 好的,所以测试一下,我注意到此行为一直持续到256年。id最多可以是8位数字,然后257将返回更大的id,可以是15位数字。因此类型必须是8个字节。 所以我发现它与8个字节长有关,但是任何

  • 当我执行普通Select时,返回正确的结果,但当我执行Select for DB uptime时,它始终返回相同的第一个结果。我确实检查了Postgres日志,我看到select被执行了。

  • 我有这些实体 标准化ChannelStock。Java语言 NormalizedChannelStockId。Java语言 Channel.java 我面临的问题是 如图所示,savedentialities中返回的实体将其通道内部对象设置为null,以及其created\u at和updated\u at 这是正常的行为吗?当我在存储库上运行时,实体中的被正确地延迟加载,因此我相信实体在代码中被