如何通过Java在SQLite中强制执行外键约束?

时间:2012-03-19 17:29:00

标签: java sqlite jdbc foreign-keys

默认情况下,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;");

但这些都不起作用。我在这里缺少什么吗?

我见过this answer,我想做同样的事情,只使用JDBC。

8 个答案:

答案 0 :(得分:31)

这样的代码:

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

不起作用。 您必须创建org.sqlite.SQLiteConfig并在从DriverManager调用getConnection时将其设置为属性。

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

答案 1 :(得分:16)

当你看SQLite Foreign Key Support page我会解释那个

  1. 必须使用外键支持编译SQLlite
  2. 您仍然必须为PRAGMA
  3. 的每个连接启用它
  4. 创建表时必须将外键定义为约束
  5. 广告1)引自here

      

    如果命令“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)您是否使用外键支持创建了表格?引自here

    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 :(得分:4)

我很遗憾无法评论上一张海报的答案,但作为其他任何可能来到这里的人的第一个代码片段:

connection.createStatement().execute("PRAGMA foreign_keys = ON");
当您的SQLite版本是最新的并支持外键支持时,

绝对可行。

答案 3 :(得分:1)

尝试

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

根据您链接的问题,它看起来很可能是候选人。

答案 4 :(得分:1)

在Linux桌面上,当我尝试时,

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

sqlite3(3.7.13)认为我的数据库文件 /path/to/test.db;foreign keys = true 。这导致了奇怪,但我认为合适,错误:表不存在

请参阅how to solve no such table while inserting exception in sqlite data base

我以为我通过将外键语句填充到如下所示的属性中来解决这两个问题:

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仍然允许违反约束。更多的是与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);

答案 5 :(得分:1)

这个页面在转换为Clojure时非常有用,但我的解决方案却有所不同。所以,对于后人来说,即使OP要求Java,这就是我在Clojure中做到的:

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

答案 6 :(得分:0)

我在谷歌搜索同样的问题时发现了这个问题。我使用的是来自Zentussqlitejdbc-v056.jar,它使用旧版本的SQLite驱动程序,并且不支持外键。

我尝试了来自Maven Repository

的Xerial驱动程序v3.7.2

我还没有研究过这些驱动程序之间的区别,但两者之间的热切换没有破坏任何问题并解决了我的问题,所以,我希望这对某人有帮助。

答案 7 :(得分:0)

我在mybatis-config.xml中使用mybatis:
<property name="url" value="jdbc:sqlite:example.db?foreign_keys=on;"/>
这对mybatis框架起作用。