如何通过 Java 在 SQLite 中强制执行外键约束?
Posted
技术标签:
【中文标题】如何通过 Java 在 SQLite 中强制执行外键约束?【英文标题】:How do you enforce foreign key constraints in SQLite through Java? 【发布时间】:2012-04-04 05:15:15 【问题描述】:默认情况下,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。
【问题讨论】:
您使用的是什么版本的 SQLite? (外键约束在 3.6.19 中引入。) 3.6.14.2,显然。甚至没有意识到。 【参考方案1】:这样的代码:
DriverManager.getConnection("jdbc:sqlite:some.db;foreign keys=true;")
不起作用。
从 DriverManager 调用 getConnection 时,您必须创建 org.sqlite.SQLiteConfig
并将其设置为属性。
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。
【讨论】:
这就像一个魅力!这又是应该被接受为答案的答案之一。 谢谢!很好的答案。【参考方案2】:当您查看 SQLite Foreign Key Support page 时,我会解释
-
SQLlite 必须在编译时支持外键
您仍然需要为每次与 PRAGMA 的连接打开它
创建表时必须将外键定义为约束
广告 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!
Ad 2) 您的第一个代码 sn-p 执行 PRAGMA as 语句,我认为这行不通。根据您的评论,第三个片段不起作用:SQLite 驱动程序将整个字符串解释为数据库的位置,而不是将“外键=true”部分作为连接设置”。所以只有第二个 sn-p 可以工作。
Ad 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)
);
【讨论】:
是的,该表是使用外键支持创建的。我应该很快注意到第三种方法根本不起作用,SQLite 驱动程序将整个字符串解释为数据库的位置,而不是将“外键=true”部分作为连接设置。 第二种 OP 的每个连接都具有属性的方式有效,但它应该只是.setProperty("foreign_keys", "true")
- 没有编译指示词。我刚刚在SQLiteConfig
来源中找到了它,它有一个包含所有编译指示及其属性值的枚举(那里还有更多)。也许它和以前不同,但这是最重要的答案之一,所以在这里【参考方案3】:
这个页面在翻译到 Clojure 时很有帮助,但是我的解决方案有所不同。因此,对于后代,即使 OP 要求使用 Java,我在 Clojure 中也是这样做的:
(def db-spec :connection-uri "jdbc:sqlite:db.sqlite3?foreign_keys=on;")
【讨论】:
谢谢!!!这一定是魔法发生的地方github.com/clojure/java.jdbc/blob/master/src/main/clojure/… 太棒了。这是我在看一个 Java 问题——但我真的很想知道 Clojure 的答案。感谢发帖! (虽然我不确定它是否适合我——但至少这给了我一个起点)【参考方案4】:很遗憾,我无法评论之前发帖者的答案,但作为对可能来到这里的其他人的提醒,第一个代码 sn-p:
connection.createStatement().execute("PRAGMA foreign_keys = ON");
当您的 SQLite 版本是最新版本并支持外键支持时,绝对可以工作。
【讨论】:
【参考方案5】:试试
connection = DriverManager.getConnection("jdbc:sqlite:test.db;foreign keys=true;");
根据您链接的问题,它看起来是一个可能的候选人。
【讨论】:
对不起,应该提到我已经尝试过了,但也没有用。【参考方案6】:在 linux 桌面上,当我尝试时,
connection = DriverManager.getConnection("jdbc:sqlite:/path/to/test.db;foreign keys=true;");
sqlite3 (3.7.13) 认为我的数据库 file 是 /path/to/test.db;foreign keys=true。这导致了奇怪但我认为是适当的错误:table does not exist
见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);
【讨论】:
【参考方案7】:我使用 mybatis,在 mybatis-config.xml 中:<property name="url" value="jdbc:sqlite:example.db?foreign_keys=on;"/>
这适用于 mybatis 框架。
【讨论】:
【参考方案8】:我在谷歌搜索同样的问题时发现了这个问题。我使用的是 Zentus 中的 sqlitejdbc-v056.jar
,它使用的是旧版本的 SQLite 驱动程序,并且不支持外键。
我尝试了来自Maven Repository 的Xerial 驱动程序v3.7.2
我没有研究这些驱动程序之间的区别,但是两者之间的热切换并没有破坏任何东西并解决了我的问题,所以,我希望这对某人有所帮助。
【讨论】:
以上是关于如何通过 Java 在 SQLite 中强制执行外键约束?的主要内容,如果未能解决你的问题,请参考以下文章