Iva*_*van 5 java hibernate spring-data-jpa
在我的网络应用程序中,在服务布局中,我使用“餐厅”实体的代理(“餐厅”字段上的 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);
Run Code Online (Sandbox Code Playgroud)
在测试中通过控制器调用此方法后,所有其他 RestaurantRepository 的获取方法(例如 findById())也返回代理。
但是,如果我在服务的方法之前调用“findById()”方法,则一切正常。
例如:
mockMvc.perform(put(REST_URL + RESTAURANT1_ID)
.param("time", "10:30")
.with(userHttpBasic(USER)))
.andExpect(status().isNoContent());
Restaurant restaurant = restaurantRepository.get(RESTAURANT1_ID);
Run Code Online (Sandbox Code Playgroud)
“餐厅”是代理
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);
Run Code Online (Sandbox Code Playgroud)
“restaurantAfter”是真正的对象
“get()”进入存储库:
@Override
public Restaurant get(int id) {
return repository.findById(id).orElse(null);
}
Run Code Online (Sandbox Code Playgroud)
您是否@Transactional对方法或服务类本身进行了注释?
这可以解释观察到的行为。
当在事务中执行方法时,从/向数据库获取或合并/保存的实体将被缓存,直到事务结束(通常是方法结束)。这意味着对具有相同 ID 的实体的任何调用都将直接从缓存中返回,并且不会访问数据库。
这里有一些关于 Hibernate 的缓存和代理的文章:
回到你的例子:
findById(id)首先调用,然后getOne(id)为两者返回相同的实体对象getOne(id)首先调用,然后findById(id)为两者返回相同的代理那是因为它们共享相同的内容id并在同一个事务中执行。
有关getOne()说明它可以返回an instance而不是引用(HibernateProxy)的文档,因此可以预期它返回一个实体:
T getOne(ID id)
返回对具有给定标识符的实体的引用。
根据 JPA 持久性提供程序的实现方式,这很可能总是返回一个实例并在第一次访问时抛出 EntityNotFoundException。其中一些会立即拒绝无效的标识符。
参数: id - 不能为空。
返回: 对具有给定标识符的实体的引用。
findById()另一方面,文档没有任何关于它可以返回除Optionalentity 或 empty 之外的任何内容的提示Optional:
可选的 findById(ID id)
通过其 id 检索实体。
参数: id - 不能为空。
返回: 具有给定 id 的实体或 Optional#empty() 如果没有找到
我花了一些时间寻找更好的解释,但没有找到,所以我不确定它是实现中的一个错误findById()还是一个没有(很好)记录的功能。
作为问题的解决方法,我可以建议:
@Transactional在不需要时使用。交易也可以手动管理。这里有一些关于这个主题的好文章:
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
}
Run Code Online (Sandbox Code Playgroud)
clear()方法一次删除所有对象: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
}
Run Code Online (Sandbox Code Playgroud)
相关文章:
编辑:
这是一个演示问题或功能的简单项目(取决于观点)。
| 归档时间: |
|
| 查看次数: |
2068 次 |
| 最近记录: |