如何通过Java在SQLite中强制执行外键约束?
看来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。
当你查看SQLite外键支持页面时,我会解释它
- 必须使用外键支持编译SQLlite
- 您仍然必须为PRAGMA的每个连接打开它
- 创建表时,必须将外键定义为约束
广告1)引自此处 :
如果命令“PRAGMA foreign_keys”不返回任何数据而不是包含“0”或“1”的单行,则您使用的SQLite版本不支持外键(因为它超过3.6.19或因为它编译时使用SQLITE_OMIT_FOREIGN_KEY或SQLITE_OMIT_TRIGGER定义 )。
你对PRAGMA foreign_keys;
的结果如何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) );
像这样的代码:
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; }
这段代码取自此 。
遗憾的是,我无法对之前海报的答案发表评论,但作为其他任何可能来到这里的人,第一个代码片段:
connection.createStatement().execute("PRAGMA foreign_keys = ON");
当您的SQLite版本是最新的并支持外键支持时,绝对可行。
尝试
connection = DriverManager.getConnection("jdbc:sqlite:test.db;foreign keys=true;");
基于您链接的问题,它看起来很可能是候选人。
在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数据库中插入exception时,看看如何解决这样的表
我以为我通过将外键语句填充到如下所示的属性中来修复这两个问题:
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);
这个页面在转换为Clojure时非常有用,但我的解决方案却有所不同。 所以,对于后人来说,即使OP要求Java,这就是我在Clojure中做到的:
(def db-spec {:connection-uri "jdbc:sqlite:db.sqlite3?foreign_keys=on;"})
谷歌搜索同样的问题时我发现了这个问题。 我使用sqlitejdbc-v056.jar
,它使用旧版本的SQLite驱动程序,不支持外键。
我从Maven Repository尝试了似乎是Xerial驱动程序v3.7.2
我还没有研究过这些驱动程序之间的区别,但是两者之间的热切换没有破坏任何东西并解决了我的问题,所以,我希望这有助于某些人。
我在mybatis-config.xml中使用mybatis:
这对mybatis框架起作用。