#java #spring #spring-mvc #spring-3 #spring-transactions
#java #весна #spring-mvc #весна-3 #spring-транзакции
Вопрос:
Я вставляю записи в пару таблиц, а именно Dept
и Emp
. Если Dept
таблица успешно создана, то только я хочу вставлять записи в Emp
таблицу. Кроме того, если какая-либо вставка завершается Emp
неудачно, я хочу откатить всю транзакцию, которая включает как откат Emp
, так и Dept
таблицы.
Я попробовал это, используя Propagation.REQUIRED
, как показано ниже:
Java-файл
public void saveEmployee(Employee empl){
try {
jdbcTemplate.update("INSERT INTO EMP VALUES(?,?,?,?,?)",empl.getEmpId(),empl.getEmpName(),
empl.getDeptId(),empl.getAge(),empl.getSex());
} catch (DataAccessException e) {
e.printStackTrace();
}
}
@Transactional(propagation=Propagation.REQUIRED)
public void saveRecords(){
saveDepartment(dept);
saveEmployee(empl);
}
context.xml
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
Проблема:
Даже если вставка в Emp
таблицу завершается неудачно, Dept
вставка сохраняется, чего я не хочу. Я хочу откатить все.
Пожалуйста, предложите.
Комментарии:
1. Вы перехватываете исключение…
Ответ №1:
Проблема в вашем блоке catch. Поскольку исключение перехвачено, tx не выполняет откат.
Вы должны создать исключение :
public void saveEmployee(Employee empl){
try {
jdbcTemplate.update("INSERT INTO EMP VALUES(?,?,?,?,?)",empl.getEmpId(),empl.getEmpName(),
empl.getDeptId(),empl.getAge(),empl.getSex());
} catch (DataAccessException e) {
e.printStackTrace();
throw e;
}
}
И, кстати, семантика продвижения.Требуется просто означает: создайте новый tx, если он не существует, ИЛИ используйте существующий, если запущен tx.
После вашего комментария здесь предлагается увидеть эффект НОВОГО tx :
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void saveEmployee(Employee empl){
try {
jdbcTemplate.update("INSERT INTO EMP VALUES(?,?,?,?,?)",empl.getEmpId(),empl.getEmpName(),
empl.getDeptId(),empl.getAge(),empl.getSex());
} catch (DataAccessException e) {
e.printStackTrace();
throw e;
}
}
@Transactional(propagation=Propagation.REQUIRED)
public void saveRecords(){
saveDepartment(dept);
try{
saveEmployee(empl);
}catch(Exception e){Logger.log("Fail to save emp !");}
}
Ключевым моментом, позволяющим увидеть эффект REQUIRE_NEW, является перехват исключения вокруг saveEmployee . Если вы его не поймаете: исключение будет распространяться в другом tx (тот, который начался при вводе saveRecords() ), и он тоже будет откатываться.
Комментарии:
1. Вышеупомянутое решение сработало. Просто для целей тестирования я добавил
@Transactional(propagation=Propagation.REQUIRES_NEW)
поверхsaveEmployee
метода, чтобы посмотреть, как он работает. Я ожидал:Dept
запись будет сохранена, аEmp
запись не будет сохранена, посколькуNEW
создаст новую транзакцию. Но я удивлен, увидев результат:Dept
ниEmp
одна запись не была сохранена. Я что-нибудь пропустил? Пожалуйста, объясните.2. Почему в этом случае не генерируется исключение? Это потому, что нам нечего откатывать? Кроме того, почему мой фрагмент кода не сработал? Какое значение имеет блок try при вызове
saveEmployee
метода? Пожалуйста, посоветуйте3. @user182944 смотрите мою отредактированную правку 😉 С помощью этого примера кода, я думаю, вы увидите, что dept будет сохранен даже при сбое вставки empl
4. да, теперь это работает … но я не могу понять, почему этот блок try имеет такое значение… не могли бы вы объяснить?
5. Спасибо за объяснение, это помогло 🙂