是否可以在标记为Spring的 @Transactional 的方法中执行提交?
@PersistenceContext
private EntityManager em;
@Transactional(propagation = Propagation.REQUIRED)
public void saveMembersWithMultipleCommits(List<Member> members)
throws HibernateException
{
Iterator<Member> it = members.iterator();
while (it.hasNext())
{
while (it.hasNext())
{
Member wsBean = it.next();
em.persist(wsBean); // overall commit will be made after method exit
log.info("Webservices record " + wsBean + " saved. " + i++);
}
}
}
我想在说出每500个项目后提交DB。这可能与上述背景有关吗?
答案 0 :(得分:5)
您的问题表明您错放了交易边界。
您可以将持久调用移动到私有方法中,并使该方法为事务性而非外部方式。此方法一次可以接受500个成员,然后在退出时提交。
答案 1 :(得分:5)
不,您需要使用例如TransactionTemplate
API以编程方式执行此操作。阅读更多here。
看起来像
while (it.hasNext())
{
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus status) {
int counter = 0;
while (it.hasNext() && counter++ < 500) {
Member wsBean = it.next();
em.persist(wsBean);
log.info("Webservices record " + wsBean + " saved. " + i++);
}
}
);
}
答案 2 :(得分:1)
如果您期望在其他交易中进行交易,则可能需要使用@Transactional (propagation = Propagation.REQUIRES_NEW)
答案 3 :(得分:-1)
替代策略是您在DAO中创建一个方法并将其标记为@Transactional。此方法将进行批量更新(例如500个)。所以你可以有一个带代码的方法
@Transactional
public void mybatchUpdateMethod(){
StatelessSession session = this.hibernateTemplate.getSessionFactory()
.openStatelessSession();
Transaction transaction = null;
Long entryCounter = 0L;
PreparedStatement batchUpdate = null;
try {
transaction = session.beginTransaction();
batchUpdate = session.connection().prepareStatement(insertSql);
for (BatchSnapshotEntry entry : entries) {
entry.addEntry(batchUpdate);
batchUpdate.addBatch();
if (++entryCounter == 500) {
// Reached limit for uncommitted entries, so commit
batchUpdate.executeBatch();
}
}
batchUpdate.executeBatch();
batchUpdate.close();
batchUpdate = null;
}
catch (HibernateException ex) {
transaction.rollback();
transaction = null;
}
}
每次调用此方法时,它将在500次插入/更新后提交