当使用getOne和findOne方法时,Spring数据JPA
我有一个用例,它调用以下内容:当使用getOne和findOne方法时,Spring数据JPA,jpa,spring-data,spring-data-jpa,Jpa,Spring Data,Spring Data Jpa,我有一个用例,它调用以下内容: @Override @Transactional(propagation=Propagation.REQUIRES_NEW) public UserControl getUserControlById(Integer id){ return this.userControlRepository.getOne(id); } 观察@Transactional具有传播。需要\u NEW,存储库使用getOne。运行应用程序时,我收到以下错误消息: Except
@Override
@Transactional(propagation=Propagation.REQUIRES_NEW)
public UserControl getUserControlById(Integer id){
return this.userControlRepository.getOne(id);
}
观察@Transactional
具有传播。需要\u NEW,存储库使用getOne。运行应用程序时,我收到以下错误消息:
Exception in thread "main" org.hibernate.LazyInitializationException:
could not initialize proxy - no Session
...
但是,如果我通过findOne(id)
更改getOne(id)
,所有操作都可以正常进行
顺便说一句,在用例调用getUserControlById方法之前,它已经调用了insertUserControl方法
@Override
@Transactional(propagation=Propagation.REQUIRES_NEW)
public UserControl insertUserControl(UserControl userControl) {
return this.userControlRepository.save(userControl);
}
这两种方法都是传播。需要新的,因为我正在执行一个简单的审核控制
我使用getOne
方法,因为它是在接口中定义的,并且我的存储库接口从那里扩展而来,我当然在使用JPA
JpaRepository接口扩展自。
findOne(id)
方法在crudepository
中定义
我的问题是:
getOne(id)
方法失败getOne(id)
方法getOne(id)
方法,只有在我使用传播时,所有存储库都可以正常工作。需要\u NEW它失败
根据getOneAPI:
返回对具有给定标识符的实体的引用
根据findOneAPI:
按实体的id检索实体
findOne(id)
方法
1。为什么getOne(id)方法失败? 见本节。您重写已就位的事务可能是导致问题的原因。然而,如果没有更多的信息,这个问题很难回答 2。何时应该使用getOne(id)方法? 没有深入研究Spring数据JPA的内部,区别似乎在于用于检索实体的机制 如果查看下的for
getOne(ID)
,请参见:
这个方法似乎只是委托给JPA实体管理器的实现
但是,对于findOne(ID)
来说,没有提到这一点
线索也在存储库的名称中。
JpaRepository
是特定于JPA的,因此如果需要,可以将调用委托给实体管理器。
crudepository
不知道所使用的持久化技术。它被用作JPA等多种持久性技术的标记接口
因此,对于您的用例,这两种方法并没有真正的“区别”,只是
findOne(ID)
比更专业的getOne(ID)
更通用。您使用哪种方法取决于您和您的项目,但我个人会坚持使用findOne(ID)
,因为它使您的代码不那么具体,并为您打开了通向MongoDB等东西的大门。在未来,无需太多重构:)getOne
方法只返回来自DB的引用(延迟加载).
因此,基本上您在事务之外(不考虑您在服务类中声明的
Transactional
),并且会发生错误。基本区别在于getOne
是延迟加载的,而findOne
不是
考虑以下示例:
public static String NON_EXISTING_ID = -1;
...
MyEntity getEnt = myEntityRepository.getOne(NON_EXISTING_ID);
MyEntity findEnt = myEntityRepository.findOne(NON_EXISTING_ID);
if(findEnt != null) {
findEnt.getText(); // findEnt is null - this code is not executed
}
if(getEnt != null) {
getEnt.getText(); // Throws exception - no data found, BUT getEnt is not null!!!
}
TL;博士
T findOne(ID ID)
(旧API中的名称)/可选findById(ID)
(新API中的名称)依赖于执行实体快速加载的EntityManager.find()
T getOne(ID)
依赖于执行实体延迟加载的EntityManager.getReference()
。因此,为了确保实体的有效加载,需要对其调用方法
findOne()
因此,在大多数情况下,支持findOne()/findById()
而不是getOne()
API变更
至少从2.0
版本开始,Spring数据Jpa
已修改findOne()
以前,它在crudepository
界面中定义为:
T findOne(ID primaryKey);
<S extends T> Optional<S> findOne(Example<S> example);
现在,您将在crudepository
中找到的单个findOne()
方法是QueryByExampleExecutor
接口中定义的方法:
T findOne(ID primaryKey);
<S extends T> Optional<S> findOne(Example<S> example);
现在它返回一个可选的。这对于防止NullPointerException
来说并不坏
因此,现在实际的选择是在可选的findById(ID)
和T getOne(ID)
之间
依赖于两种不同JPA EntityManager检索方法的两种不同方法
1) 缔约国表示:
按实体的id检索实体
当我们查看实现时,可以看到它依赖于EntityManager.find()
进行检索:
public Optional<T> findById(ID id) {
Assert.notNull(id, ID_MUST_NOT_BE_NULL);
Class<T> domainType = getDomainClass();
if (metadata == null) {
return Optional.ofNullable(em.find(domainType, id));
}
LockModeType type = metadata.getLockModeType();
Map<String, Object> hints = getQueryHints().withFetchGraphs(em).asMap();
return Optional.ofNullable(type == null ? em.find(domainType, id, hints) : em.find(domainType, id, type, hints));
}
其javadoc声明:
使用指定的属性按主键查找
因此,检索加载的实体似乎是意料之中的事
2) 而各州(重点是我):
返回对具有给定标识符的实体的引用
事实上,参考术语实际上是board,jpaapi没有指定任何getOne()
方法。
因此,要理解Spring包装器的作用,最好的办法是研究实现:
@Override
public T getOne(ID id) {
Assert.notNull(id, ID_MUST_NOT_BE_NULL);
return em.getReference(getDomainClass(), id);
}
下面是一个EntityManager
方法,声明为:
public <T> T find(Class<T> entityClass, Object primaryKey,
Map<String, Object> properties);
public <T> T getReference(Class<T> entityClass,
Object primaryKey);
public T getReference(类entityClass,
对象主密钥);
幸运的是,EntityManager
javadoc更好地定义了它的意图(重点是我的):
获取一个实例,该实例的状态可能是延迟获取的。如有要求,
实例在中不存在
public UserDTO getById(int userId) throws Exception {
final User user = userDao.getOne(userId);
if (user == null) {
throw new ServiceException("User not found", HttpStatus.NOT_FOUND);
}
userDto = mapEntityToDto.transformBO(user, UserDTO.class);
return userDto;
}
{
"collection": {
"version": "1.0",
"data": {
"id": 1,
"name": "TEST_ME",
"bookList": null
},
"error": null,
"statusCode": 200
},
"booleanStatus": null
{
"collection": {
"version": "1.0",
"data": {
"id": 0,
"name": "Annama",
"bookList": [
{
"id": 2,
"book_no": "The karma of searching",
}
]
},
"error": null,
"statusCode": 200
},
"booleanStatus": null