Подтвердить что ты не робот

Как вы применяете ограничения внешнего ключа в SQLite через Java?

Похоже, SQLite не применяет внешние ключи по умолчанию. Я использую sqlitejdbc-v056.jar, и я прочитал, что использование PRAGMA foreign_keys = ON; приведет к ограничениям внешнего ключа и что это потребует для включения в каждом соединении.

Мой вопрос: какие инструкции Java нужно выполнить для включения этой команды? Я пробовал:

connection.createStatement().execute("PRAGMA foreign_keys = ON");

и

Properties properties = new Properties();
properties.setProperty("PRAGMA foreign_keys", "ON");
connection = DriverManager.getConnection("jdbc:sqlite:test.db", properties);

и

connection = DriverManager.getConnection("jdbc:sqlite:test.db;foreign keys=true;");

но никто из них не работает. Здесь что-то не хватает?

Я видел этот ответ, и я хочу сделать то же самое, только используя JDBC.

4b9b3361

Ответ 1

Когда вы смотрите страницу поддержки внешних ключей SQLite, я бы понял, что

  • SQLlite должен быть скомпилирован с поддержкой внешнего ключа.
  • Вам все равно нужно включить его для каждого соединения с PRAGMA
  • Вы должны определить внешний ключ как ограничение при создании таблицы

Объявление 1) Цитата из здесь:

Если команда "PRAGMA foreign_keys" не возвращает данные вместо одной строки, содержащей "0" или "1", тогда используемая вами версия SQLite не поддерживает внешние ключи (либо из-за того, что она старше, чем 3.6.19 или потому что он был скомпилирован с SQLITE_OMIT_FOREIGN_KEY или SQLITE_OMIT_TRIGGER, определенным).

Каков ваш результат для PRAGMA foreign_keys;?

Обновление: из вашего комментария. Я вижу, что вы используете 3.6.14.2, это означает, что ваша версия не поддерживает ограничения внешнего ключа! Поэтому вам нужно обновить SQLite, если это возможно!

Объявление 2) Ваш первый фрагмент кода выполняет инструкцию PRAGMA как таковой, я не думаю, что это сработает. Третий отрезанный не работал на основе вашего комментария: драйвер SQLite интерпретирует всю строку как местоположение базы данных, вместо того, чтобы в качестве параметров подключения принимать часть "foreign keys = true". Таким образом, будет работать только второй фрагмент.

Объявление 3) Создали ли вы таблицу с поддержкой внешнего ключа? Цитируется из здесь:

CREATE TABLE artist(
  artistid    INTEGER PRIMARY KEY, 
  artistname  TEXT
);
CREATE TABLE track(
  trackid     INTEGER, 
  trackname   TEXT, 
  trackartist INTEGER,
  FOREIGN KEY(trackartist) REFERENCES artist(artistid)
);

Ответ 2

Код вроде этого:

DriverManager.getConnection("jdbc:sqlite:some.db;foreign keys=true;")

Не работает. Вы должны создать org.sqlite.SQLiteConfig и установить его как свойства при вызове getConnection из DriverManager.

public static final String DB_URL = "jdbc:sqlite:database.db";  
public static final String DRIVER = "org.sqlite.JDBC";  

public static Connection getConnection() throws ClassNotFoundException {  
    Class.forName(DRIVER);  
    Connection connection = null;  
    try {  
        SQLiteConfig config = new SQLiteConfig();  
        config.enforceForeignKeys(true);  
        connection = DriverManager.getConnection(DB_URL,config.toProperties());  
    } catch (SQLException ex) {}  
    return connection;  
}

Этот код взят из this.

Ответ 3

Я, к сожалению, не могу комментировать предыдущий ответ на плакат, но как хедз-ап для кого-то еще, кто может приехать сюда, первого фрагмента кода:

connection.createStatement().execute("PRAGMA foreign_keys = ON");

абсолютно работает, когда ваша версия SQLite обновлена ​​и поддерживает поддержку внешнего ключа.

Ответ 4

Try

connection = DriverManager.getConnection("jdbc:sqlite:test.db;foreign keys=true;");

Основываясь на вопросе, который вы связали, он выглядит вероятным кандидатом.

Ответ 5

На рабочем столе Linux, когда я попытался,

connection = DriverManager.getConnection("jdbc:sqlite:/path/to/test.db;foreign keys=true;");

sqlite3 (3.7.13) считал, что моя база данных была /path/to/test.db;foreign keys = true. Это привело к странной, но, я думаю, соответствующей ошибке: таблица не существует

См. как решить такую ​​таблицу при вставке исключения в базу данных sqlite

Мне показалось, что я исправил оба эти вопроса, набив выражение внешнего ключа в такое свойство:

private final Properties connectionProperties = new Properties();
connectionProperties.setProperty("PRAGMA foreign_keys", "ON");
private final String connectionString = String.format("jdbc:sqlite:%s", absolute_path_to_sqlite_db);
Connection connection = DriverManager.getConnection(connectionString, connectionProperties);

Но даже проблема с именем базы данных была решена, SQLite по-прежнему допускает нарушения ограничений. Еще немного noodling с драйвером Xerial, и вот что, наконец, сработало:

private final Properties connectionProperties = new Properties();
SQLiteConfig config = new SQLiteConfig();
config.enforceForeignKeys(true);
connectionProperties = config.toProperties();
private final String connectionString = String.format("jdbc:sqlite:%s", absolute_path_to_sqlite_db);
Connection connection = DriverManager.getConnection(connectionString, connectionProperties);

Ответ 6

Я нашел этот вопрос, в то время как Googling та же проблема. Я использовал sqlitejdbc-v056.jar из Zentus, который использует более старую версию драйвера SQLite и не поддерживает внешние ключи.

Я пробовал то, что кажется драйвером Xerial v3.7.2 из Репозиторий Maven

Я не исследовал разницу между этими драйверами, но "горячий" переключатель между ними ничего не сломал и исправил мою проблему, поэтому я надеюсь, что это кому-то поможет.

Ответ 7

Эта страница была полезна при переводе на Clojure, однако мое решение было другим. Итак, для потомков, хотя OP запросил Java, так я сделал это в Clojure:

(def db-spec {:connection-uri "jdbc:sqlite:db.sqlite3?foreign_keys=on;"})