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

前提是你 提交于 2019-11-27 08:54:32

When you look at the SQLite Foreign Key Support page I would interpret that

  1. SQLlite has to be compiled with foreign key support
  2. You still have to turn it on for each connection with PRAGMA
  3. You have to define the foreign key as constraint when you create the table

Ad 1) Quoted from here:

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

What is your result for 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! So you have to update SQLite, if this is possible!

Ad 2) Your first code snippet executes the PRAGMA as statement, I don't think this will work. 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.

Ad 3) Did you create the table with foreign key support? 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)
);

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.

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.

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.

Try

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

Based on the question you linked, it looks to be a likely candidate.

toddg

On a linux desktop, when I tried,

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. 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

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. Some more noodling with Xerial's driver and this is what finally worked:

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. So, for posterity, even though the OP asked for Java, this is how I did it in Clojure:

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

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.

I tried what seems to be the Xerial driver v3.7.2 from the Maven Repository

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 :
<property name="url" value="jdbc:sqlite:example.db?foreign_keys=on;"/>
that's work for mybatis framework.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!