简体   繁体   English

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

[英]How do you enforce foreign key constraints in SQLite through Java?

It appears that SQLite does not enforce foreign keys by default. 看来SQLite默认不强制执行外键。 I'm using sqlitejdbc-v056.jar and I've read that using PRAGMA foreign_keys = ON; 我正在使用sqlitejdbc-v056.jar并且我已经阅读了使用PRAGMA foreign_keys = ON; will turn on foreign key constraints, and that this needs to be turned on in a per-connection basis. 将打开外键约束,并且需要在每个连接的基础上打开它。

My question is: what Java statements do I need to execute to turn on this command? 我的问题是:我需要执行哪些Java语句来打开此命令? I've tried: 我试过了:

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

and

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

and

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

but none of those work. 但这些都不起作用。 Is there something I am missing here? 这里有什么我想念的吗?

I've seen this answer and I want to do exactly the same thing, only using JDBC. 我已经看到了这个答案 ,我想做同样的事情,只使用JDBC。

Code like this: 像这样的代码:

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

Does not work. 不行。 You have to create org.sqlite.SQLiteConfig and set it as properties when call getConnection from DriverManager. 您必须创建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 code taken from this . 这段代码取自

When you look at the SQLite Foreign Key Support page I would interpret that 当你查看SQLite外键支持页面时,我会解释它

  1. SQLlite has to be compiled with foreign key support 必须使用外键支持编译SQLlite
  2. You still have to turn it on for each connection with PRAGMA 您仍然必须为PRAGMA的每个连接打开它
  3. You have to define the foreign key as constraint when you create the table 创建表时,必须将外键定义为约束

Ad 1) Quoted from here : 广告1)引自此处

If the command "PRAGMA foreign_keys" returns no data instead of a single row containing "0" or "1", then the version of SQLite you are using does not support foreign keys (either because it is older than 3.6.19 or because it was compiled with SQLITE_OMIT_FOREIGN_KEY or SQLITE_OMIT_TRIGGER defined ). 如果命令“PRAGMA foreign_keys”不返回任何数据而不是包含“0”或“1”的单行,那么您使用的SQLite版本不支持外键(因为它超过3.6.19或因为它编译时使用SQLITE_OMIT_FOREIGN_KEY或SQLITE_OMIT_TRIGGER定义 )。

What is your result for PRAGMA foreign_keys; 你对PRAGMA foreign_keys;的结果如何PRAGMA foreign_keys; ?

Update: from your comment I see you are using 3.6.14.2, this means your version is not supporting foreign key constraints! 更新:从你的评论我看到你正在使用3.6.14.2,这意味着你的版本不支持外键约束! So you have to update SQLite, if this is possible! 所以你必须更新SQLite,如果可能的话!

Ad 2) Your first code snippet executes the PRAGMA as statement, I don't think this will work. 广告2)您的第一个代码段执行PRAGMA语句,我认为这不会起作用。 The third snipped didn't work based on your comment: the SQLite driver interprets the whole string as the location of the database, instead of taking the "foreign keys=true" part as connection settings" . So only the second snippet will work. 第三个剪辑根据你的评论不起作用: SQLite驱动程序将整个字符串解释为数据库的位置,而不是将“foreign keys = true”部分作为连接设置“ 。所以只有第二个片段才有效。

Ad 3) Did you create the table with foreign key support? 广告3)您是否创建了具有外键支持的表? Quoted from 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)
);

I unfortunately can't comment on the previous poster's answer but as a heads up for anybody else who may come by here, the first code snippet: 遗憾的是,我无法对之前海报的答案发表评论,但作为其他任何可能来到这里的人,第一个代码片段:

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

absolutely does work when your version of SQLite is up to date and supports foreign key support. 当您的SQLite版本是最新的并支持外键支持时,绝对可行。

On a linux desktop, when I tried, 在linux桌面上,当我尝试时,

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

sqlite3 (3.7.13) thought that my database file was /path/to/test.db;foreign keys=true . sqlite3(3.7.13)认为我的数据库文件/path/to/test.db;foreign keys = true This led to the strange, but I guess appropriate, error: table does not exist 这导致了奇怪,但我认为合适,错误: 表不存在

See how to solve no such table while inserting exception in sqlite data base 在sqlite数据库中插入异常时,看看如何解决这样的表

I thought I had fixed both of these issues by stuffing the foreign key statement into a property like so: 我以为我通过将外键语句填充到如下所示的属性中来解决这两个问题:

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);

But even tho the database name issue was resolved, SQLite was still allowing constraint violations. 但即使解决了数据库名称问题,SQLite仍然允许违反约束。 Some more noodling with Xerial's driver and this is what finally worked: 使用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);

this page was helpful when translating to Clojure, however my solution was different. 这个页面在转换为Clojure时非常有用,但我的解决方案却有所不同。 So, for posterity, even though the OP asked for Java, this is how I did it in Clojure: 所以,对于后代来说,即使OP要求Java,这就是我在Clojure中做到的:

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

Try 尝试

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

Based on the question you linked, it looks to be a likely candidate. 基于您链接的问题,它看起来很可能是候选人。

I found this question while Googling the same problem. 谷歌搜索同样的问题时我发现了这个问题。 I was using sqlitejdbc-v056.jar from Zentus , which uses an older version of the SQLite driver, and doesn't support foreign keys. 我用sqlitejdbc-v056.jarZentus ,它使用SQLite的驱动程序的旧版本,并且不支持外键。

I tried what seems to be the Xerial driver v3.7.2 from the Maven Repository 我从Maven Repository尝试了似乎是Xerial驱动程序v3.7.2

I have not researched the difference between these drivers, but a hot-switch between the two didn't break anything and fixed my issue, so, I hope this helps someone. 我没有研究过这些驱动程序之间的区别,但是两者之间的热切换没有破坏任何东西并解决了我的问题,所以,我希望这有助于某些人。

I use mybatis, in mybatis-config.xml : 我在mybatis-config.xml中使用mybatis:
<property name="url" value="jdbc:sqlite:example.db?foreign_keys=on;"/>
that's work for mybatis framework. 这对mybatis框架有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM