我有一個JPA實體與Lazy加載集合。我不需要收集每一次。OpenSessionInView與交易? (春季/休眠/ 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
一旦進入一個請求調用。
但是,我不希望processAllFoos
被封裝在單個數據庫事務中,因爲這會鎖定整個Foo表,直到爲所有Foos執行業務邏輯爲止。
如果我使processFoo
方法@Transactional
我得到LazyInitializationException
,它抱怨Hibernate會話不存在。爲了使這個工作,我需要在調用堆棧@Transactional
中的所有方法,以便嵌套的方法可以加入到調用方法的事務。但是,如上所述,這將鎖定整個Foo表。
添加爲dispatcher servlet
一個OpenSessionInViewFilter
解決我的問題,但我讀過,有與業績和實體分離/重新連接(這是我在應用程序的其他部分一樣)使用這種方法的問題。
有沒有一種方法可以在不使用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);
}
}
謝謝@SergeyBespalov這使整個過程快得令人難以置信。這種方法有什麼需要注意的嗎?你明確管理事務時不應該做的事情? – battle2048
我可以建議你基於這個例子的兩條簡單規則: 1.不要使用聲明式事務管理,如果它不適合你; 2.如果只需要一個屬性,請不要使用完全對象; –