К сожалению, MySQL пока не поддерживает операторы в стиле DELETE .. RETURNING
(см. Ниже).
Решение, которое работает на всех СУБД с несколькими циклами обработки
Полное решение, которое будет Работа для всех видов сложных операторов DELETE
и UPDATE
будет использовать VisitListener
для преобразования операторов в эквивалентные операторы SELECT
. Я могу вспомнить тонну крайних случаев, которые необходимо учитывать, если вы хотите, чтобы это всегда работало.
Если решение "80/20" достаточно хорошо, тогда Вы можете использовать это простое регулярное выражение ExecuteListener
. Вот пример:
create table t (i int primary key, j int);
insert into t values (1, 1), (2, 2), (3, 3);
А затем:
try (Connection c = getConnection()) {
DSLContext ctx = DSL.using(c);
ctx.configuration().set(new DefaultExecuteListener() {
@Override
public void executeStart(ExecuteContext c) {
if (c.query() instanceof Delete)
System.out.println(ctx.fetch(c.sql().replace("delete from", "select * from")));
}
});
System.out.println(ctx.delete(table("t")).where("i > 1").execute());
}
Вывод вышеуказанной программы:
+----+----+
| i| j|
+----+----+
| 2| 2|
| 3| 3|
+----+----+
2
Этот подход имеет недостатки, которые могут или могут не имеет значения для вас:
- Не работает с простыми SQL запросами. Если это проблема, замените чек
instanceof Delete
более дорогим чеком c.sql().startsWith("delete")
. - Он не учитывает чувствительность к регистру (например, простые операторы SQL
DELETE
) или отформатирован SQL , Конечно, это поправимо. - Он не работает с некоторыми MySQL спецификациями c
DELETE
, такими как PARTITION
или IGNORE
, которые вы также можете исправить. - Подход предполагает, что можно выполнить второй оператор на том же
Connection
. Это может быть не так в зависимости от вашей DataSource
/ модели транзакции.
Решение, которое работает для некоторых не MySQL СУБД
Для полноты информации и будущих читателей В этом ответе я также предложу решение, которое будет работать на DB2, Firebird, Oracle, PostgreSQL и SQL Server, которые имеют форму DELETE .. RETURNING
или эквивалентный оператор. В этих СУБД вы можете написать:
dslContext.deleteFrom(Tables.USERS)
.where(Tables.USERS.NAME.eq("xy"))
.returning()
.fetch();
Это удалит записи и вернет все затронутые записи в одном операторе, вместо создания двух циклов.