Ниже мой класс под резьбовые пружинные исполнители.В зависимости от типа источника / услуги TAXP, TAXS, методы TAXT вызываются.Логика в том случае, если 'taxInfo.getGroupingId ()' уже присутствует в первичной налоговой таблице, не вставляйте, иначе вставьте первичную таблицу.Все записи вторичных и третичных таблиц вставляются.НАЛОГ, НАЛОГИ, НАЛОГ - темы, и они получают данные в любое время.может быть интервал в миллисекунды или в то же время данные будут отправлены, поэтому блоки синхронизируются.
Все 3 метода вызываются из 3 разных исполнителей потоков.
executor1.insertPrimaryTaxInfo(taxInfo);
executor2.insertSecTaxInfo(taxInfo);
executor3.insertTerTaxInfo(taxInfo);
@Service
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public class TaxServiceImpl implements TaxService {
private static final Logger LOG = LogManager.getLogger(ScanServiceImpl.class);
// TAXP
@Override
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = TaxServiceException.class)
public void insertPrimaryTaxInfo(TaxInfo taxInfo) throws TaxServiceException {
String taxId = null;
try {
synchronized (this) {
taxId = taxMapper.checkExists(taxInfo.getGroupingId());
if (taxId == null) {
taxMapper.insertTaxInfo(taxInfo); // primary tax table
}
}
LOG.info("tax id -- " + taxId);
} catch (Exception ex) {
LOG.error("Error inserting txId for " + taxInfo.getGroupingId()
+ ex);
throw new TaxServiceException(ex);
}
}
// TAXS
@Override
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = TaxServiceException.class)
public void insertSecTaxInfo(TaxInfo taxInfo) throws TaxServiceException {
String taxId = null;
try {
synchronized (this) {
taxId = taxMapper.checkExists(taxInfo.getGroupingId());
if (taxId == null) {
taxMapper.insertTaxInfo(taxInfo); // primary tax table
}
}
taxMapper.insertIntoSecTable(taxInfo); // secondary tax table
LOG.info("tax id -- " + taxId);
} catch (Exception ex) {
LOG.error("Error inserting txId for " + taxInfo.getGroupingId()
+ ex);
throw new TaxServiceException(ex);
}
}
// TAXT
@Override
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = TaxServiceException.class)
public void insertTerTaxInfo(TaxInfo taxInfo) throws TaxServiceException {
String taxId = null;
try {
synchronized (this) {
taxId = taxMapper.checkExists(taxInfo.getGroupingId());
if (taxId == null) {
taxMapper.insertTaxInfo(taxInfo); // primary tax table
}
}
taxMapper.insertIntoSecTable(taxInfo); // secondary tax table
taxMapper.insertIntoTerTable(taxInfo); // Tertiary tax table
LOG.info("tax id -- " + taxId);
} catch (Exception ex) {
LOG.error("Error inserting txId for " + taxInfo.getGroupingId()
+ ex);
throw new TaxServiceException(ex);
}
}
}
Проблема заключается в том, что TAXP, TAXS, TAXT получают данные одновременно, и 3 вышеуказанных метода вызываются одновременно.С разницей в миллисекунды один из потоков вставляет в основную таблицу, а другой поток пытается сделать то же самое, но находит запись, уже существующую в таблице, и выбрасывает исключение дубликата ключа.
Получаю следующее исключение:
"com.data.exception.TaxServiceException: org.springframework.dao.DuplicateKeyException:
### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: ORA-00001: unique constraint (TAXDB2.TAX_PK) violated
Причиной синхронизации блока является преодоление этого исключения.Что не так с приведенным выше кодом?