Продолжить транзакцию Postgres с исключениями в Java - PullRequest
2 голосов
/ 10 мая 2011

Приведенный ниже метод insert вставляет ссылки на таблицу в базе данных (PostgreSQL), но если возникает ошибка, это влияет на остальную часть транзакции и не работает.Исключением является то, что поле URL уникально.

В PostgreSQL возможно продолжить транзакцию даже с исключениями?

for (int i = 0, n = page.getLinks().length; i < n; i++) {
     linkBD.insert(page.getLink(i), idPage);
}            

public boolean insert(Link link, int idPage) {
    try {
        String sql = "INSERT INTO link (id,idPage,url,linkText,"
        + "visited,broken) VALUES(nextval('idLinkSqc'),?,?,?,?,?)";

        PreparedStatement pstm = Conn.conn.prepareStatement(sql);

        pstm.setInt(1, idPage);
        pstm.setString(2, link.getUrl());
        pstm.setString(3, link.getLinkText());
        pstm.setBoolean(4, false);
        pstm.setBoolean(5, false);

        pstm.execute();            
        Conn.commit();
        pstm.close();            
        return true;
    } catch (Exception e) {
        System.out.println("Erro inserindo link no banco de dados: " + e.getMessage());
        System.out.println("Erro no link: "+link.getUrl());
        return false;
    }
}

Сообщение об ошибке на португальском языке: transaçãoatrom interrompida, comandos ignorados até o fim do bloo de transação

Перевод Google Translate, я считаю правильным: текущая транзакция отменена, команды игнорируются до конца блока транзакции

Ответы [ 7 ]

2 голосов
/ 11 мая 2011

Вы можете избежать нарушения ограничения (и, следовательно, проблемы исключений и транзакций), изменив свой INSERT

INSERT INTO link(id, idPage, url, linkText, visited, broken)
SELECT nextval('idLinkSqc'), ?, ?, ?, ?, ?
FROM link
WHERE NOT EXISTS (SELECT url FROM link WHERE url = ?)
LIMIT 1

И затем дополнительный заполнитель:

pstm.setString(6, link.getUrl());

Вы можететакже замените ваш необработанный INSERT на хранимую процедуру, которая проверит, что новый URL еще не существует, прежде чем пытаться выполнить INSERT.

UPDATE : улучшенная версия SQL вышебудь это:

INSERT INTO link (id, idPage, url, linkText, visited, broken)
SELECT nextval('idLinkSqc'), ?, ?, ?, ?, ?
FROM (
    SELECT 1
    WHERE NOT EXISTS (SELECT 1 FROM link WHERE url = ?)
) AS postgres_needs_this_alias

Конечный результат должен быть таким же, но эта версия не требует взлома LIMIT 1.Идея заключается в том, чтобы использовать внутренний SELECT для создания одной строки, если url не присутствует (отсюда дополнительный вложенный бизнес НЕ СУЩЕСТВУЕТ), и нет строк, если присутствует url;затем мы используем количество строк из внутреннего SELECT в качестве счетчика для того, сколько строк должно быть вставлено в link.Проверка EXISTS на индексированный столбец также должна быть достаточно быстрой.

2 голосов
/ 11 мая 2011

Можно продолжить, если сбой был внутри SAVEPOINT .Вот пример в psql:

# create temporary table foo (i int primary key);
CREATE TABLE

Начните транзакцию и вставьте строку:

# begin;
BEGIN
# insert into foo values(1);
INSERT 0 1

Запустите точку сохранения, вставьте одну и ту же строку дважды.Это приведет к ошибке:

# savepoint bar;
SAVEPOINT
# insert into foo values(2);
INSERT 0 1
# insert into foo values(2);
ERROR:  duplicate key value violates unique constraint "foo_pkey"

Откатитесь до точки сохранения, затем вставьте другую строку.

# rollback to savepoint bar;
ROLLBACK
# insert into foo values(3);
INSERT 0 1

Подтвердите и посмотрите, что там:

# commit;
COMMIT
# select * from foo;
 i 
---
 1
 3
(2 rows)
2 голосов
/ 11 мая 2011

Я не знаю, как обойтись, может быть, но я просто не знаю, что это такое. Как только у Postgres возникнет проблема в транзакции, он полностью ее убьет, и ваша единственная надежда - перезапустить ее. Это означает, что вы должны убедиться, что ваш код будет работать правильно, прежде чем объединять все в единое целое (особенно такие вещи, как дубликаты первичных ключей и отсутствующие внешние ключи и т. Д.).

1 голос
/ 11 мая 2011

Сделайте следующее:

INSERT INTO table (column list)
SELECT v.* FROM (VALUES (....), (....), (....)) v
     LEFT JOIN table t ON t.t_unique_column=v.column1 -- choose the matching column
     WHERE t.t_unique_column IS NULL
RETURNING *

Это позволит вам вставить большую часть строк без проверки исключений для каждой строки, а предложение RETURNING возвращает вам то, что было вставлено, сгенерированные последовательности PK и т. Д.является самым быстрым решением (кроме COPY).

1 голос
/ 11 мая 2011

Отказ от ответственности: я почти ничего не знаю о Java / JDBC.

Два "решения":

  • не группируют все вставки в одной транзакции, выполняют их отдельно
  • взгляните на SAVEPOINT с
0 голосов
/ 11 мая 2011

Проблема должна быть не в том, как обрабатывать исключения, а в том, как предотвратить исключения. Эта ссылка должна дать вам информацию о том, как изящно игнорировать вставки, которые не будут работать из-за дублирования ключей.

0 голосов
/ 11 мая 2011

Вы пытались переместить коммит за пределы блока try (возможно, в блок finnaly)?И, возможно, это как-то связано с возвратом false (пытались ли вы увидеть это, код не проверяет этот логический параметр позднее и выполняет какой-то откат, если он ложный?)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...