Java 在使用SpringDataJPA时,如何避免分离对象或未初始化的Hibernate代理?
我使用的是Java 在使用SpringDataJPA时,如何避免分离对象或未初始化的Hibernate代理?,java,spring-data-jpa,Java,Spring Data Jpa,我使用的是Spring数据JPA,分离的对象有问题。我想知道如何解决这个问题 我正在处理两个对象:请求和事件。 请求有一个生命周期,并且在其生命周期内被多次处理。 每次处理请求,都会生成一个事件,并将其存储在表中。因此,事件具有对请求的引用和基数多通 请求:-------------------------------------------------------------> 事件:-------------------------------------------------------
Spring数据JPA
,分离的对象有问题。我想知道如何解决这个问题
我正在处理两个对象:请求
和事件
。
请求有一个生命周期,并且在其生命周期内被多次处理。
每次处理请求
,都会生成一个事件
,并将其存储在表中。因此,事件
具有对请求的引用
和基数多通
请求:------------------------------------------------------------->
事件:---------------------------------------------------------------------------------------------------------------------------------------------------------->
下面是事件类的一部分
:
public class Event implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID")
@Getter @Setter
private long id;
@ManyToOne(cascade = {CascadeType.ALL})
@JoinColumn(name = "REQUESTID")
@Getter @Setter
private Request request;
...
请求
如下所示:
public class Request implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID")
@Getter @Setter
private long id;
@Column(name = "AMOUNT")
@Getter @Setter
private BigInteger amount;
}
以下是关系的SQL表示形式:
CREATE TABLE IF NOT EXISTS REACTIVEENGINE.EVENT (
id int AUTO_INCREMENT NOT NULL ,
requestId int NOT NULL ,
domain varchar(50) NOT NULL ,
step varchar(150) NOT NULL ,
result varchar(20) NOT NULL ,
timelog timestamp(3) NOT NULL ,
alertId int NULL ,
primary key (id),
CONSTRAINT FK_EVENT_REQUEST_ID foreign key (requestId) references REQUEST (id) ON DELETE CASCADE ,
CONSTRAINT FK_EVENT_ALERT_ID foreign key (alertId) references ALERT (id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=UTF8MB4;
当我想处理请求时,我遇到了这个问题。下面是一个方法:
executorService.scheduleAtFixedRate( () -> {
Flux<Event> eventFlux = getEventFlux();
eventFlux.subscribe( event -> {
Request request = requestDao.getOne(event.getRequest().getId());
Event fundingEvent = Event.builder()
.domain(Domain.FUNDING)
.step(FundingStep.FUNDABILITY_CHECK.name())
.request(request)
.result(Event.Status.SUCCESS)
.timelog(LocalDateTime.now())
.build();
eventDao.save(fundingEvent);
});
}, 0, 30, TimeUnit.SECONDS);
问题是请求现在已分离:
reactor.core.Exceptions$ErrorCallbackNotImplemented: org.springframework.dao.InvalidDataAccessApiUsageException: uninitialized proxy passed to persist(); nested exception is org.hibernate.PersistentObjectException: uninitialized proxy passed to persist()
Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: uninitialized proxy passed to persist(); nested exception is org.hibernate.PersistentObjectException: uninitialized proxy passed to persist()
我尝试了许多解决方案,将级联。所有添加到事件实体。
我还尝试将@PersistenceContext
添加到我的类中,以便在将请求对象注入事件对象之前刷新/合并请求对象(但它不起作用,因为持久性上下文仍然为null)
你能提出什么解决方案
提前感谢。您使用getOne
的目的是什么?是否将事件与请求
关联,而不从DB加载请求
如果是这样,没有事务,这将无法工作。之所以出现异常,是因为getOne
返回一个代理,并且由于没有周围的持久性上下文,代理会立即“分离”,无法初始化它(因为创建它的上下文不再存在)
解决方案是,只需使用原始的event.getRequest()
,或者,如果出于某种奇怪的原因坚持“刷新”Request
状态,则使用findById
而不是getOne
另一个解决方案(假设您使用的是JPA的默认提供程序,即Hibernate)是从Event.request中删除CascadeType.ALL
(因为它对@ManyToOne
没有任何意义-您可以将其替换为级联选项的某些子集,但排除合并
和删除
),只需使用新请求(event.getRequest().getId())
。对于此场景,原始事件.getRequest()
也同样有效。您使用getOne
的意图是什么?是否将事件与请求关联,而不从DB加载请求
如果是这样,那么如果没有事务,这将无法工作。您将获得异常,因为getOne
返回一个代理,并且由于没有周围的持久性上下文,代理将立即“分离”,无法初始化它(因为创建它的上下文不再存在)
解决方案是,只需使用原始的event.getRequest()
,或者,如果出于某种奇怪的原因坚持“刷新”Request
状态,则使用findById
而不是getOne
另一个解决方案(假设您使用的是JPA的默认提供程序,即Hibernate)是从Event.request中删除CascadeType.ALL
(因为它对@ManyToOne
没有任何意义-您可以将其替换为级联选项的某些子集,但排除合并
和删除
),只需使用新请求(event.getRequest().getId())
。对于此场景,原始事件.getRequest()
也同样有效。谢谢您的时间和帮助
“getOne(…)
”是Spring Data JPA命名“findById(id)
”方法的方式。开始时没有调用requestDao.getOne(event.getRequest().getId());
在上一个事件
对象中只有一个请求
对象,我只想将它从上一个传递到下一个。分离的对象问题出现了,当时我只想使用从事件a
中提取的相同请求
对象注入事件B
这就是为什么我测试从数据库中获取一个“新的”请求,但是“分离的
”问题已经被“代理
”问题所取代,没有更多的持久性上下文。我尝试的@Transactional
注释也没有解决问题
事实上,你对级联
的看法是正确的,这在我的情况下是完全无用和没有意义的。我认为它可以帮助我节省一些时间和代码行,以避免N次调用save
方法,每个对象一次。我想在同一个动作中完成这一切,这就是我使用级联
工具的原因
我不清楚Hibernate上下文中“Proxy
”的概念,但我知道“requestDao.getOne(…)
”方法不足以创建持久持久性上下文,后者将由事件的dao层使用
我还了解到,级联
原则的使用绝对不适合我的情况。当必须同时创建两个对象时,级联.PERSIST
是可以的。但在我的情况下,请求
对象已经创建,只是被一个新的事件
对象重复使用。但Hibernate不是能够持久化其中一个,只需合并/更新另一个
最后,我抑制了Cascade
关键字a
reactor.core.Exceptions$ErrorCallbackNotImplemented: org.springframework.dao.InvalidDataAccessApiUsageException: uninitialized proxy passed to persist(); nested exception is org.hibernate.PersistentObjectException: uninitialized proxy passed to persist()
Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: uninitialized proxy passed to persist(); nested exception is org.hibernate.PersistentObjectException: uninitialized proxy passed to persist()