У меня есть приложение, построенное на Spring + Hibernate. Я пытаюсь вставить данные в базу данных из списка записей в файле. Основная идея состоит в том, чтобы вставить все записи с действительными данными и зарегистрировать отчет об ошибках для всех записей, которые не были вставлены.
Класс обслуживания, которым является @Transactional, вызывает другой класс обслуживания для чтения файла и вставки в БД. Сейчас я вставляю записи одну за другой. Возможно, я изменю это на Пакетную обработку. Вставка выполняется в блоке try catch.
Псевдокод:
@Transactional
class MainService {
public void insertFromFile(File inputFile) {
subServuce(toIterator(inputFile)); // toIterator(..) is just for understanding.
}
}
class SubService {
public void insert(Iterator input) {
while (input.hasNext()) {
try {
DBService.save(input.next());
} catch (Exception e) {
// Log the error and continue with next records
}
}
}
}
@Transactional
class DBService {
public void save(Data input) {
generalDao.save(input);
}
}
Пытался:
class SubService {
public void insert(Iterator input) {
while (input.hasNext()) {
try {
save(input.next());
} catch (Exception e) {
// Log the error and continue with next records
}
}
}
// @Transactional(propagation = Propagation.REQUIRES_NEW, noRollbackFor = Exception.class)
@Transactional(propagation = Propagation.NOT_SUPPORTED, noRollbackFor = Exception.class)
public void save(Data input) {
DBService.save(input);
}
}
Несмотря на то, что исключение обработано, выполняется откат всей транзакции, и я получаю эту ошибку Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly
Я попытался указать @Transactional(noRollBack = Exception.class)
на SubService.insert(..)
, но это не сработало.
Следующие мои вопросы:
- Как мне сказать Spring не откатывать назад и продолжить с другими записями.
- Хорошая практика - не откатывать назад при вставке нескольких записей? Разве это не противоречит правилу атомарности?
Как это обрабатывается при пакетной обработке? Если возникает ошибка, вставляются все или нет?
Решение:
С помощью ответа @Madhusudana Reddy Sunnapu смог решить эту проблему.
Создал слой между SubService и DBService с помощью Propagation.REQUIRES_NEW. Проблема заключалась в том, что даже несмотря на то, что SubService.save (..) аннотируется @Transactional, поскольку он принадлежит одному и тому же Bean, прокси не будет рассматривать его как другой сеанс.
SubServiceDao {
// @Transactional(propagation = Propagation.REQUIRES_NEW)
public void save(Data input) {
DBService.save(input);
}
}
class SubService {
public void insert(Iterator input) {
while (input.hasNext()) {
try {
SubServiceDao.save(input.next());
} catch (Exception e) {
// Log the error and continue with next records
}
}
}
}