blob: 2d4754e96e3facabbe3c08eafe6e59403b7717c4 [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<title>Apache Jena - Jena JDBC - A SPARQL over JDBC driver framework</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="/css/bootstrap.min.css" rel="stylesheet" media="screen">
<link href="/css/bootstrap-icons.css" rel="stylesheet" media="screen"><link rel="stylesheet" type="text/css" href="https://jena.apache.org/sass/jena.1b17c39a117e22b46db4c66f6395dc27c134a60377d87d2d5745b8600eb69722.css" integrity="sha256-GxfDmhF&#43;IrRttMZvY5XcJ8E0pgN32H0tV0W4YA62lyI=">
<link rel="shortcut icon" href="/images/favicon.ico" />
</head>
<body>
<nav class="navbar navbar-expand-lg bg-body-tertiary" role="navigation">
<div class="container">
<div class="navbar-header">
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<a class="navbar-brand" href="/index.html">
<img class="logo-menu" src="/images/jena-logo/jena-logo-notext-small.png" alt="jena logo">Apache Jena</a>
</div>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li id="homepage" class="nav-item"><a class="nav-link" href="/index.html"><span class="bi-house"></span> Home</a></li>
<li id="download" class="nav-item"><a class="nav-link" href="/download/index.cgi"><span class="bi-download"></span> Download</a></li>
<li class="nav-item dropdown">
<a href="#" class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false"><span class="bi-journal"></span> Learn <b class="caret"></b></a>
<ul class="dropdown-menu">
<li class="dropdown-header">Tutorials</li>
<li><a class="dropdown-item" href="/tutorials/index.html">Overview</a></li>
<li><a class="dropdown-item" href="/documentation/fuseki2/index.html">Fuseki Triplestore</a></li>
<li><a class="dropdown-item" href="/documentation/notes/index.html">How-To's</a></li>
<li><a class="dropdown-item" href="/documentation/query/manipulating_sparql_using_arq.html">Manipulating SPARQL using ARQ</a></li>
<li><a class="dropdown-item" href="/tutorials/rdf_api.html">RDF core API tutorial</a></li>
<li><a class="dropdown-item" href="/tutorials/sparql.html">SPARQL tutorial</a></li>
<li><a class="dropdown-item" href="/tutorials/using_jena_with_eclipse.html">Using Jena with Eclipse</a></li>
<li class="dropdown-divider"></li>
<li class="dropdown-header">References</li>
<li><a class="dropdown-item" href="/documentation/index.html">Overview</a></li>
<li><a class="dropdown-item" href="/documentation/query/index.html">ARQ (SPARQL)</a></li>
<li><a class="dropdown-item" href="/documentation/io/">RDF I/O</a></li>
<li><a class="dropdown-item" href="/documentation/assembler/index.html">Assembler</a></li>
<li><a class="dropdown-item" href="/documentation/tools/index.html">Command-line tools</a></li>
<li><a class="dropdown-item" href="/documentation/rdfs/">Data with RDFS Inferencing</a></li>
<li><a class="dropdown-item" href="/documentation/geosparql/index.html">GeoSPARQL</a></li>
<li><a class="dropdown-item" href="/documentation/inference/index.html">Inference API</a></li>
<li><a class="dropdown-item" href="/documentation/ontology/">Ontology API</a></li>
<li><a class="dropdown-item" href="/documentation/permissions/index.html">Permissions</a></li>
<li><a class="dropdown-item" href="/documentation/extras/querybuilder/index.html">Query Builder</a></li>
<li><a class="dropdown-item" href="/documentation/rdf/index.html">RDF API</a></li>
<li><a class="dropdown-item" href="/documentation/rdfconnection/">RDF Connection - SPARQL API</a></li>
<li><a class="dropdown-item" href="/documentation/rdfstar/index.html">RDF-star</a></li>
<li><a class="dropdown-item" href="/documentation/shacl/index.html">SHACL</a></li>
<li><a class="dropdown-item" href="/documentation/shex/index.html">ShEx</a></li>
<li><a class="dropdown-item" href="/documentation/tdb/index.html">TDB</a></li>
<li><a class="dropdown-item" href="/documentation/tdb2/index.html">TDB2</a></li>
<li><a class="dropdown-item" href="/documentation/query/text-query.html">Text Search</a></li>
</ul>
</li>
<li class="nav-item dropdown">
<a href="#" class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false"><span class="bi-journal-code"></span> Javadoc <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="/documentation/javadoc.html">All Javadoc</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/arq/">ARQ</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/fuseki2/">Fuseki</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/geosparql/">GeoSPARQL</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/jena/">Jena Core</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/permissions/">Permissions</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/extras/querybuilder/">Query Builder</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/shacl/">SHACL</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/tdb/">TDB</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/text/">Text Search</a></li>
</ul>
</li>
</ul>
<form class="d-flex" role="search" action="/search" method="GET">
<div class="input-group">
<input class="form-control border-end-0 border m-0" type="search" name="q" id="search-query" placeholder="Search...." aria-label="Search" style="width: 10rem;">
<button class="btn btn-outline-secondary border-start-0 border" type="submit">
<i class="bi-search"></i>
</button>
</div>
</form>
<ul class="navbar-nav">
<li id="ask" class="nav-item"><a class="nav-link" href="/help_and_support/index.html" title="Ask"><span class="bi-patch-question"></span><span class="text-body d-none d-xxl-inline"> Ask</span></a></li>
<li class="nav-item dropdown">
<a href="#" title="Get involved" class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false"><span class="bi-megaphone"></span><span class="text-body d-none d-xxl-inline"> Get involved </span><b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="/getting_involved/index.html">Contribute</a></li>
<li><a class="dropdown-item" href="/help_and_support/bugs_and_suggestions.html">Report a bug</a></li>
<li class="dropdown-divider"></li>
<li class="dropdown-header">Project</li>
<li><a class="dropdown-item" href="/about_jena/about.html">About Jena</a></li>
<li><a class="dropdown-item" href="/about_jena/architecture.html">Architecture</a></li>
<li><a class="dropdown-item" href="/about_jena/citing.html">Citing</a></li>
<li><a class="dropdown-item" href="/about_jena/team.html">Project team</a></li>
<li><a class="dropdown-item" href="/about_jena/contributions.html">Related projects</a></li>
<li><a class="dropdown-item" href="/about_jena/roadmap.html">Roadmap</a></li>
<li><a class="dropdown-item" href="/about_jena/security-advisories.html">Security Advisories</a></li>
<li class="dropdown-divider"></li>
<li class="dropdown-header">ASF</li>
<li><a class="dropdown-item" href="https://www.apache.org/">Apache Software Foundation</a></li>
<li><a class="dropdown-item" href="https://www.apache.org/foundation/sponsorship.html">Become a Sponsor</a></li>
<li><a class="dropdown-item" href="https://www.apache.org/licenses/LICENSE-2.0">License</a></li>
<li><a class="dropdown-item" href="https://www.apache.org/security/">Security</a></li>
<li><a class="dropdown-item" href="https://www.apache.org/foundation/thanks.html">Thanks</a></li>
</ul>
</li>
<li class="nav-item" id="edit"><a class="nav-link" href="https://github.com/apache/jena-site/edit/main/source/documentation/jdbc/__index.md" title="Edit this page on GitHub"><span class="bi-pencil-square"></span><span class="text-body d-none d-xxl-inline"> Edit this page</span></a></li>
</ul>
</div>
</div>
</nav>
<div class="container">
<div class="row">
<div class="col-md-12">
<div id="breadcrumbs">
<ol class="breadcrumb mt-4 p-2 bg-body-tertiary">
<li class="breadcrumb-item"><a href='/documentation'>DOCUMENTATION</a></li>
<li class="breadcrumb-item active">JDBC</li>
</ol>
</div>
<h1 class="title">Jena JDBC - A SPARQL over JDBC driver framework</h1>
<main class="d-flex flex-xl-row flex-column">
<aside class="text-muted align-self-start mb-3 p-0 d-xl-none d-block">
<h2 class="h6 sticky-top m-0 p-2 bg-body-tertiary">On this page</h2>
<nav id="TableOfContents">
<ul>
<li><a href="#documentation">Documentation</a></li>
<li><a href="#overview">Overview</a>
<ul>
<li><a href="#treatment-of-results">Treatment of Results</a></li>
</ul>
</li>
<li><a href="#basic-usage">Basic Usage</a>
<ul>
<li><a href="#establishing-a-connection">Establishing a Connection</a></li>
<li><a href="#performing-queries">Performing Queries</a></li>
<li><a href="#performing-updates">Performing Updates</a></li>
</ul>
</li>
<li><a href="#alternatives">Alternatives</a></li>
</ul>
</nav>
</aside>
<article class="flex-column me-lg-4">
<blockquote>
<p>Jena JDBC will be removed in Jena5.</p>
</blockquote>
<p>Jena JDBC is a set of libraries which provide SPARQL over JDBC driver implementations.</p>
<p>This is a pure SPARQL over JDBC implementation, there is no attempt to present the underlying
RDF data model as a relational model through the driver and only SPARQL queries and updates
are supported.</p>
<p>It provides type 4 drivers in that they are pure Java based but the drivers are not JDBC compliant since
by definition they <strong>do not</strong> support SQL.</p>
<p>This means that the drivers can be used with JDBC tools provided that those tools don&rsquo;t restrict you to SQL
or auto-generate SQL. So it can be used with a tool like <a href="http://squirrel-sql.sourceforge.net">SquirrelSQL</a>
since you can freely enter SPARQL queries and updates. Conversely it cannot be used with a tool like a SQL based
ORM which generates SQL.</p>
<h2 id="documentation">Documentation</h2>
<ul>
<li><a href="#overview">Overview</a></li>
<li><a href="#basic-usage">Basic Usage</a></li>
<li><a href="#alternatives">Alternatives</a></li>
<li><a href="drivers.html">Jena JDBC Drivers</a></li>
<li><a href="artifacts.html">Maven Artifacts for Jena JDBC</a></li>
<li><a href="custom_driver.html">Implementing a custom Jena JDBC Driver</a></li>
</ul>
<h2 id="overview">Overview</h2>
<p>Jena JDBC aims to be a pure SPARQL over JDBC driver, it assumes that all commands that come in are
either SPARQL queries or updates and processes them as such.</p>
<p>As detailed on the <a href="drivers.html">drivers</a> page there are actually three drivers provided currently:</p>
<ul>
<li><a href="drivers.html#in-memory">In-Memory</a> - uses an in-memory dataset to provide non-persistent storage</li>
<li><a href="drivers.html#tdb">TDB</a> - uses a <a href="/documentation/tdb/">TDB</a> dataset to provide persistent and transactional storage</li>
<li><a href="drivers.html#remote-endpoint">Remote Endpoint</a> - uses HTTP based remote endpoints to access any SPARQL protocol compliant storage</li>
</ul>
<p>These are all built on a core library which can be used to build <a href="custom_driver.html">custom drivers</a>
if desired. This means that all drivers share common infrastructure and thus exhibit broadly speaking
the same behavior around handling queries, updates and results.</p>
<p>Jena JDBC is published as a Maven module via its <a href="artifacts.html">maven artifacts</a>. The source for Jena JDBC may be <a href="/download/index.cgi">downloaded</a> as part of the source distribution.</p>
<h3 id="treatment-of-results">Treatment of Results</h3>
<p>One important behavioral aspect to understand is how results are treated compared to a traditional
JDBC driver. SPARQL provides four query forms and thus four forms of results while JDBC assumes all
results have a simple tabular format. Therefore one of the main jobs of the core library is to marshal
the results of each kind of query into a tabular format. For <code>SELECT</code> queries this is a trivial mapping,
for <code>CONSTRUCT</code> and <code>DESCRIBE</code> the triples are mapped to columns named <code>Subject</code>, <code>Predicate</code> and <code>Object</code>
respectively, finally for <code>ASK</code> the boolean is mapped to a single column named <code>ASK</code>.</p>
<p>The second issue is that JDBC expects uniform column typing throughout a result set which is not
something that holds true for SPARQL results. Therefore the core library takes a pragmatic approach to column
typing and makes the exact behavior configurable by the user. The default behavior of the core library is
to type all columns as <code>Types.NVARCHAR</code> with a Java type of <code>String</code>, this provides the widest compatibility
possible with both the SPARQL results and consuming tools since we can treat everything as a string. We
refer to this default behavior as medium compatibility, it is sufficient to allow JDBC tools to interpret
results for basic display but may be unsuitable for further processing.</p>
<p>We then provide two alternatives, the first of which we refer to as high compatibility aims to present the
data in a way that is more amenable to subsequent processing by JDBC tools. In this mode the column types
in a result set are detected by sniffing the data in the first row of the result set and assigning appropriate
types. For example if the first row for a given column has the value <code>&quot;1234&quot;^^xsd:integer</code> then it would
be assigned the type <code>Types.BIGINT</code> and have the Java type of <code>Long</code>. Doing this allows JDBC tools to carry
out subsequent calculations on the data in a type appropriate way. It is important to be aware that this
sniffing may not be accurate for the entire result set so can still result in errors processing some rows.</p>
<p>The second alternative we refer to as low compatibility and is designed for users who are using the driver
directly and are fully aware that they are writing SPARQL queries and getting SPARQL results. In this mode
we make no effort to type columns in a friendly way instead typing them as <code>Types.JAVA_OBJECT</code> with the Java
type <code>Node</code> (i.e. the Jena <a href="/documentation/javadoc/jena/org.apache.jena.core/org/apache/jena/graph/Node.html">Node</a> class).</p>
<p>Regardless of how you configure to do column typing the core library does it best to allow you to marshal values
into strong types. For example even if using default compatibility and your columns are typed as strings
from a JDBC perspective you can still call <code>getLong(&quot;column&quot;)</code> and if there is a valid conversion the
library will make it for you.</p>
<p>Another point of interest is around our support of different result set types. The drivers support both
<code>ResultSet.TYPE_FORWARD_ONLY</code> and <code>ResultSet.TYPE_SCROLL_INSENSITIVE</code>, note that regardless of the type
chosen and the underlying query type all result sets are <code>ResultSet.CONCUR_READ_ONLY</code> i.e. the <code>setLong()</code>
style methods cannot be used to update the underlying RDF data. Users should be aware that the default
behavior is to use forward only result sets since this allows the drivers to stream the results and
minimizes memory usage. When scrollable result sets are used the drivers will cache all the results into
memory which can use lots of memory when querying large datasets.</p>
<h2 id="basic-usage">Basic Usage</h2>
<p>The following takes you through the basic usage of the in-memory JDBC driver. The code should be familiar
to anyone who has used JDBC before and is easily used with our other <a href="drivers.html">drivers</a> simply by
changing the connection URL appropriately.</p>
<h3 id="establishing-a-connection">Establishing a Connection</h3>
<p>Firstly we should ensure that the driver we wish to use is registered with the JDBC driver manager, a static
method is provided for this:</p>
<pre><code>MemDriver.register();
</code></pre>
<p>Once this is done we can then make a JDBC connection just be providing an appropriate connection URL:</p>
<pre><code>// Make a connection using the In-Memory driver starting from an empty dataset
Connection conn = DriverManager.getConnection(&quot;jdbc:jena:mem:empty=true&quot;);
</code></pre>
<p>Now we can go ahead and use the connection as you would normally.</p>
<h3 id="performing-queries">Performing Queries</h3>
<p>You make queries as you would with any JDBC driver, the only difference being that the queries must be SPARQL:</p>
<pre><code>// Need a statement
Statement stmt = conn.createStatement();
try {
// Make a query
ResultSet rset = stmt.executeQuery(&quot;SELECT DISTINCT ?type WHERE { ?s a ?type } LIMIT 100&quot;);
// Iterate over results
while (rset.next()) {
// Print out type as a string
System.out.println(rset.getString(&quot;type&quot;));
}
// Clean up
rset.close();
} catch (SQLException e) {
System.err.println(&quot;SQL Error - &quot; + e.getMessage());
} finally {
stmt.close();
}
</code></pre>
<h3 id="performing-updates">Performing Updates</h3>
<p>You make updates as you would with any JDBC driver. Again the main difference is that updates must be SPARQL,
one downside of this is that SPARQL provides no way to indicate the number of triples/quads affected by an update
so the JDBC driver will either return <code>0</code> for successful updates or throw a <code>SQLException</code> for failed updates:</p>
<pre><code>// Need a statement
Statement stmt = conn.createStatement();
// Make an update
try {
stmt.executeUpdate(&quot;INSERT DATA { &lt;http://x&gt; &lt;http://y&gt; &lt;http://z&gt; }&quot;);
System.out.println(&quot;Update succeeded&quot;);
} catch (SQLException e) {
System.out.println(&quot;Update Failed &quot; - + e.getMessage());
} finally {
// Clean up
stmt.close();
}
</code></pre>
<h2 id="alternatives">Alternatives</h2>
<p>If Jena JDBC does not fulfill your use case you may also be interested in some 3rd party
projects which do SPARQL over JDBC in other ways:</p>
<ul>
<li><a href="https://github.com/Claudenw/jdbc4sparql">Claude Warren&rsquo;s jdbc4sparql</a> - An alternative approach that does expose
the underlying RDF data model as a relational model and supports translating SQL into SPARQL</li>
<li><a href="http://code.google.com/p/jdbc4sparql/">William Greenly&rsquo;s jdbc4sparql</a> - A similar approach to Jena JDBC restricted
to accessing HTTP based SPARQL endpoints</li>
<li><a href="https://code.google.com/p/scon/wiki/Introduction">Paul Gearon&rsquo;s scon</a> - A similar approach to Jena JDBC restricted
to accessing HTTP based SPARQL endpoints</li>
</ul>
</article>
<aside class="text-muted align-self-start mb-3 mb-xl-5 p-0 d-none d-xl-flex flex-column sticky-top">
<h2 class="h6 sticky-top m-0 p-2 bg-body-tertiary">On this page</h2>
<nav id="TableOfContents">
<ul>
<li><a href="#documentation">Documentation</a></li>
<li><a href="#overview">Overview</a>
<ul>
<li><a href="#treatment-of-results">Treatment of Results</a></li>
</ul>
</li>
<li><a href="#basic-usage">Basic Usage</a>
<ul>
<li><a href="#establishing-a-connection">Establishing a Connection</a></li>
<li><a href="#performing-queries">Performing Queries</a></li>
<li><a href="#performing-updates">Performing Updates</a></li>
</ul>
</li>
<li><a href="#alternatives">Alternatives</a></li>
</ul>
</nav>
</aside>
</main>
</div>
</div>
</div>
<footer class="bd-footer py-4 py-md-5 mt-4 mt-lg-5 bg-body-tertiary">
<div class="container" style="font-size:80%" >
<p>
Copyright &copy; 2011&ndash;2024 The Apache Software Foundation, Licensed under the
<a href="https://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.
</p>
<p>
Apache Jena, Jena, the Apache Jena project logo, Apache and the Apache feather logos are trademarks of
The Apache Software Foundation.
<br/>
<a href="https://privacy.apache.org/policies/privacy-policy-public.html"
>Apache Software Foundation Privacy Policy</a>.
</p>
</div>
</footer>
<script src="/js/popper.min.js.js" type="text/javascript"></script>
<script src="/js/bootstrap.min.js" type="text/javascript"></script>
<script src="/js/improve.js" type="text/javascript"></script>
<script type="text/javascript">
(function() {
'use strict'
const links = document.querySelectorAll(`a[href="${window.location.pathname}"]`)
if (links !== undefined && links !== null) {
for (const link of links) {
link.classList.add('active')
let parentElement = link.parentElement
let count = 0
const levelsLimit = 4
while (['UL', 'LI'].includes(parentElement.tagName) && count <= levelsLimit) {
if (parentElement.tagName === 'LI') {
parentElement.querySelector('a:first-child').classList.add('active')
}
parentElement = parentElement.parentElement
count++
}
}
}
})()
</script>
</body>
</html>