使用Java Jena API读取Apache Jena TDB数据库为空及锁异常排查
问题
我用tdbload创建了Apache Jena TDB数据库,用tdbquery能正常查询出数据。但用Java Jena API(代码里用TDB2Factory连接)以只读方式查询时,数据集显示为空且无命名图;执行Java程序后再用tdbquery,还会出现锁文件不兼容的错误。
程序输出
dir exists ? true tdb2 ?true empty ? true size:0 Done
锁错误信息
org.apache.jena.tdb1.base.file.FileException: Unable to check TDB lock owner, the lock file contents appear to be for a TDB2 database. Please try loading this location as a TDB2 database. See https://jena.apache.org/documentation/tdb/faqs.html for more information. at org.apache.jena.tdb1.base.file.LocationLock.getOwner(LocationLock.java:114) at org.apache.jena.tdb1.base.file.LocationLock.canObtain(LocationLock.java:143) at org.apache.jena.tdb1.sys.StoreConnection._makeAndCache(StoreConnection.java:263) at org.apache.jena.tdb1.sys.StoreConnection.make(StoreConnection.java:227) at org.apache.jena.tdb1.sys.StoreConnection.make(StoreConnection.java:241) at org.apache.jena.tdb1.transaction.DatasetGraphTransaction.<init>(DatasetGraphTransaction.java:76) at org.apache.jena.tdb1.sys.TDBMaker.createDirect(TDBMaker.java:116) at java.base/java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1713) at org.apache.jena.tdb1.sys.TDBMaker._create(TDBMaker.java:102) (...)
Java代码
import java.util.Arrays; import java.util.*; import java.io.*; import org.apache.jena.query.*; import org.apache.jena.tdb2.*; import org.apache.jena.rdf.model.*; import org.apache.jena.riot.*; public class Minikit { void instanceMainWithExit(final List<String> args) { try { String directory="/path/to/TDB.rdfs"; File f = new File(directory); System.err.println("dir exists ?"+ f.exists()); Dataset dataset = TDB2Factory.connectDataset(directory) ; System.err.println("tdb2 ?" + TDB2Factory.isTDB2(dataset)); dataset.begin(ReadWrite.READ); System.err.println("empty ? "+dataset.isEmpty()); { Iterator<String> it = dataset.listNames(); while(it.hasNext()) { System.err.println("NAME="+it.next()); } } { Iterator<org.apache.jena.rdf.model.Resource> it = dataset.listModelNames(); while(it.hasNext()) { System.err.println("R="+it.next()); } } Model model = dataset.getDefaultModel(); System.err.println("size:"+model.size()); StmtIterator it = model.listStatements(); while(it.hasNext()) { System.err.println(it.next()); } it.close(); dataset.commit(); dataset.end(); model.close(); dataset.close(); System.err.println("Done"); } catch(Throwable err) { err.printStackTrace(); System.exit(-1); } } public static void main(final String[] args) throws Throwable { new Minikit().instanceMainWithExit(Arrays.asList(args)); } }
编译命令
javac -cp "/path/to/conda/apache-jena/bin/../lib/*" Minikit.java
环境信息
tdbquery --version Apache Jena version 6.1.0 Apache Jena TDB1 version 6.1.0 $ java -version openjdk version "23.0.1" 2024-10-15 OpenJDK Runtime Environment (build 23.0.1+11-39) OpenJDK 64-Bit Server VM (build 23.0.1+11-39, mixed mode, sharing)
解决方案
核心问题
你用tdbload创建的是TDB1格式的数据库,但Java代码错误地使用TDB2Factory连接,导致两个问题:
- TDB2无法识别TDB1的存储结构,因此查询不到数据,显示数据集为空;
- Java程序用TDB2打开数据库时会生成TDB2锁文件,后续用TDB1的
tdbquery工具访问时,因锁文件格式不兼容触发错误。
修复步骤
修改Java代码,改用TDB1 API连接
替换代码中TDB2相关的类为TDB1的实现:- 替换导入:将
import org.apache.jena.tdb2.*;改为import org.apache.jena.tdb.TDBFactory; - 替换连接逻辑:将
Dataset dataset = TDB2Factory.connectDataset(directory);改为Dataset dataset = TDBFactory.createDataset(directory); - 移除TDB2版本判断:删除
System.err.println("tdb2 ?" + TDB2Factory.isTDB2(dataset));语句
修改后的核心代码片段:
import org.apache.jena.tdb.TDBFactory; // ... Dataset dataset = TDBFactory.createDataset(directory); dataset.begin(ReadWrite.READ); // ...- 替换导入:将
清理冲突锁文件
执行Java程序后,数据库目录会生成TDB2锁文件,需手动删除这些文件(如tdb.lock),才能让tdbquery(TDB1)正常访问。保持版本一致性
- 用TDB1工具创建的数据库,全程使用TDB1的API和工具操作;
- 若要切换到TDB2,需用
tdb2.tdbload重新导入数据,再用TDB2的API和tdb2.tdbquery工具操作。
内容的提问来源于stack exchange,提问作者Pierre
相关产品推荐
相关产品推荐

