我有一个带有延迟加载集合的 JPA 实体。我不需要每次都收集。
@Entity(name = "Foo")
@Access(AccessType.FIELD)
@Table(name = "TEST", schema = "TEST")
public class Foo implements Serializable {
private static final long serialVersionUID = 1L;
@OneToMany(mappedBy="foo", targetEntity=Bar.class, fetch=FetchType.LAZY, cascade=CascadeType.ALL)
private List<Bar> bars;
}
@Entity(name = "Bar")
@Access(AccessType.FIELD)
@Table(name = "TEST", schema = "TEST")
public class Bar implements Serializable {
private static final long serialVersionUID = 1L;
@ManyToOne(targetEntity = Foo.class)
@JoinColumn(name = "FOO_ID", referencedColumnName = "ID")
private Foo foo;
}
我在服务类上有一些方法,它们执行大量数据库交互,最后将 Foo 实体保存到数据库中。我需要为集合中的大约 100 个项目发生这种情况。
@Service
public class FooService {
@Autowired
private FooRepository fooRepository;
public void processAllFoos() {
fooRepository.findAll().forEach(foo -> {
processFoo(foo);
});
}
private void processFoo(Foo foo) {
foo.getBars().forEach(bar -> {
// Do a lot of time consuming stuff here that involves
// entities of other types and modify each bar object
});
fooRepository.save(foo);
}
}
processAllFoos
@RESTController
每当收到请求时都会从 a 调用。
但是,我不想processAllFoos
被包装在单个数据库事务中,因为这会锁定整个 Foo 表,直到为所有 Foo 执行业务逻辑。
如果我使用该processFoo
方法@Transactional
,我会得到LazyInitializationException
抱怨 Hibernate 会话不存在的方法。为了完成这项工作,我需要在调用堆栈中创建所有方法,@Transactional
以便嵌套方法可以加入调用方法的事务。但这会锁定整个 Foo 表,如上所述。
添加一个OpenSessionInViewFilter
for thedispatcher servlet
解决了我的问题,但我读到使用这种方法存在性能和实体分离/重新连接(我在应用程序的其他部分执行)的问题。
有没有一种方法可以在不使用该方法的情况下做我想做的事OpenSessionInView
?通过使用这种方法,我还添加了哪些其他漏洞?
Spring/Hibernate 4.x
根据下面的答案,我能够做到以下几点:
@Service
public class FooService {
@Autowired
private FooRepository fooRepository;
@Autowired
private TransactionTemplate transactionTemplate;
public void processAllFoos() {
fooRepository.findAll().forEach(foo -> {
transactionTemplate.execute(new TransactionCallback<Object>() {
public Object doInTransaction(TransactionStatus status) {
try {
processFoo(foo);
status.flush();
} catch(Exception e) {
status.setRollbackOnly();
}
return null;
}
});
});
}
private void processBar(Foo foo) {
foo.getBars().foreEach(bar -> {
// Do a lot of time consuming stuff here that involves
// entities of other types and modify each bar object
});
fooRepository.save(foo);
}
}