私は方法があります:
@Transactional
public void importChargesRequest() {
...
for (Charge charge : charges) {
try {
Charge savedCharge = saveCharge(charge);
} catch (Exception e) {
log.error(e.getMessage());
}
}
}
各存続のためにCharge
私は内部メソッドを呼び出します。
@Transactional(propagation = Propagation.REQUIRES_NEW)
public Charge saveCharge(Charge charge) {
return chargesRepository.saveAndFlush(charge);
}
場合saveCharge
methosは、私が書き込みログが欲しい(私の場合の制約例外では)例外をスローし、引き続き別のエンティティを永続化します。しかし、私は例外をキャッチする場合-エラーと私の外部トランザクション・rolback:
Transaction was marked for rollback only; cannot commit; nested exception is org.hibernate.TransactionException: Transaction was marked for rollback only; cannot commit
私は開いているトランザクションを必要とする各エンティティの保存を開始します。いくつかのエンティティが例外を除いて保存することができない場合 - 私はこの例外をログに記録し、別のエンティティの保存を続行する必要が。すべてのエンティティは、保存された(または記録さ)になるとき、私は外部のトランザクションをコミットする必要が。しかし、今ではロールバックします。どのように私はそれを修正することができますか?
EDIT:
私は、コメントを受け入れ、別のBeanにREQUIRES_NEWトランザクションを移動します。
@Service
public class TestService {
private final TestDao testDao;
public TestService(TestDao testDao) {
this.testDao = testDao;
}
@Transactional
public void saveTest() {
for (int i = 0; i < 100; i++) {
Test test = new Test();
if (i == 10 || i == 20) {
test.setName("123");
} else {
test.setName(UUID.randomUUID().toString());
}
testDao.save(test);
}
}
}
それぞれの内部取引のための別のBean:
@Slf4j
@Component
@Repository
public class TestDao {
@PersistenceContext
private EntityManager entityManager;
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void save(Test test) {
entityManager.persist(test);
}
}
私が初めてで保存しようとすると、私は、DB内で20行を持っています。そして、私は10行を取得保存し、次の各。名前には制約があります。私はエラーを取得した場合 - トランザクションがコミットし続けるではありません。それぞれが保存した後、私は98行を待ちます。
場合は、saveCharge
同じBean内のメソッドでimportChargesRequest
、@Transactional
注釈は無視されますとsaveAndFlushは同じ(外側)のトランザクションで動作します。(私はあなたがトランザクションを管理するためのプロキシ/インターセプタを使用するときに必ずこのような場合はね。AspectJのベースのトランザクション傍受を使用しているとき、私はかなり確かにその場合も同様です)。
例外は、外法(@Transactionマーク1)にすべての方法をバブルアップが、私はリポジトリまたはトランザクションマネージャ自体が(セッションを休止状態)を直接ロールバック起因するため、トランザクションをマーキングされた疑いがある場合は通常、トランザクションはロールバック専用としてマークされます制約違反。
この溶液を別のBeanにsaveChargeを移動しimportChargesRequest法でBeanにそのBeanを注入することです。
@Service
public class ChargesDataService{
@Autowire
private ChargesRepository chargesRepository;
@Transactional(propagation = Propagation.REQUIRES_NEW)
public Charge saveCharge(Charge charge) {
return chargesRepository.saveAndFlush(charge);
}
}
@RestController
public class ChargesController{
@Autowire
private ChargesDataService chargesDataService;
@Transactional
public void importChargesRequest() {
for (Charge charge : charges) {
try {
Charge savedCharge = chargesDataService.saveCharge(charge);
} catch (Exception e) {
log.error(e.getMessage());
}
}
}
}
補遺:あなたは、もはや新しいトランザクションを処理する場所がないことを意味し何のインターセプターが呼び出されることはありません飽き意味豆のインスタンスへのプロキシ、通過しないため、注釈は無視されます。これは中にブレークポイントを設定することにより、ケースであるかどうかをチェックできるsaveCharge
方法および^スタックトレースを見ています。方法invokeWithinTransactionのようなトランザクションインターセプターのようなものを探してください。
^また、そのスタックトレースを含む例外を印刷/にfillInStackTraceを呼び出した後、ログインし、新しい例外を作成することができます。