Language bindings: Java / JDBC |
|
2011 January 28 |
Back to Language Bindings |
Test environment
Linux Debian:My first test
$
javac Sample.java $ java -classpath ".:sqlite-jdbc.3.7.2.jar" Sample |
First SpatiaLite test (failure)
stmt.execute("SELECT load_extension('/usr/local/lib/libspatialite.so'); |
import
org.sqlite.SQLiteConfig; ... SQLiteConfig config = new SQLiteConfig; config.enableLoadExtension(true); Connection conn = DriverManager.getConnection("path", config.toProperties); Statement stmt = conn.createStatement(); stmt.execute("SELECT load_extension('/usr/local/lib/libspatialite.so')"); |
Java sample program
SpatialiteSample.java
import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.sql.PreparedStatement; import org.sqlite.SQLiteConfig; public class SpatialiteSample { public static void main(String[] args) throws ClassNotFoundException { // load the sqlite-JDBC driver using the current class loader Class.forName("org.sqlite.JDBC"); Connection conn = null; try { // enabling dynamic extension loading // absolutely required by SpatiaLite SQLiteConfig config = new SQLiteConfig(); config.enableLoadExtension(true); // create a database connection conn = DriverManager.getConnection("jdbc:sqlite:spatialite.sample", config.toProperties()); Statement stmt = conn.createStatement(); stmt.setQueryTimeout(30); // set timeout to 30 sec. // loading SpatiaLite stmt.execute("SELECT load_extension('/usr/local/lib/libspatialite.so')"); // enabling Spatial Metadata // using v.2.4.0 this automatically initializes SPATIAL_REF_SYS and GEOMETRY_COLUMNS String sql = "SELECT InitSpatialMetadata()"; stmt.execute(sql); // creating a POINT table sql = "CREATE TABLE test_pt ("; sql += "id INTEGER NOT NULL PRIMARY KEY,"; sql += "name TEXT NOT NULL)"; stmt.execute(sql); // creating a POINT Geometry column sql = "SELECT AddGeometryColumn('test_pt', "; sql += "'geom', 4326, 'POINT', 'XY')"; stmt.execute(sql); // creating a LINESTRING table sql = "CREATE TABLE test_ln ("; sql += "id INTEGER NOT NULL PRIMARY KEY,"; sql += "name TEXT NOT NULL)"; stmt.execute(sql); // creating a LINESTRING Geometry column sql = "SELECT AddGeometryColumn('test_ln', "; sql += "'geom', 4326, 'LINESTRING', 'XY')"; stmt.execute(sql); // creating a POLYGON table sql = "CREATE TABLE test_pg ("; sql += "id INTEGER NOT NULL PRIMARY KEY,"; sql += "name TEXT NOT NULL)"; stmt.execute(sql); // creating a POLYGON Geometry column sql = "SELECT AddGeometryColumn('test_pg', "; sql += "'geom', 4326, 'POLYGON', 'XY')"; stmt.execute(sql); // inserting some POINTs // please note well: SQLite is ACID and Transactional, // so (to get best performance) the whole insert cycle // will be handled as a single TRANSACTION conn.setAutoCommit(false); int i; for (i = 0; i < 100000; i++) { // for POINTs we'll use full text sql statements sql = "INSERT INTO test_pt (id, name, geom) VALUES ("; sql += i + 1; sql += ", 'test POINT #"; sql += i + 1; sql += "', GeomFromText('POINT("; sql += i / 1000.0; sql += " "; sql += i / 1000.0; sql += ")', 4326))"; stmt.executeUpdate(sql); } conn.commit(); // checking POINTs sql = "SELECT DISTINCT Count(*), ST_GeometryType(geom), "; sql += "ST_Srid(geom) FROM test_pt"; ResultSet rs = stmt.executeQuery(sql); while(rs.next()) { // read the result set String msg = "> Inserted "; msg += rs.getInt(1); msg += " entities of type "; msg += rs.getString(2); msg += " SRID="; msg += rs.getInt(3); System.out.println(msg); } // inserting some LINESTRINGs // this time we'll use a Prepared Statement sql = "INSERT INTO test_ln (id, name, geom) "; sql += "VALUES (?, ?, GeomFromText(?, 4326))"; PreparedStatement ins_stmt = conn.prepareStatement(sql); conn.setAutoCommit(false); for (i = 0; i < 100000; i++) { // setting up values / binding String name = "test LINESTRING #"; name += i + 1; String geom = "LINESTRING ("; if ((i%2) == 1) { // odd row: five points geom += "-180.0 -90.0, "; geom += -10.0 - (i / 1000.0); geom += " "; geom += -10.0 - (i / 1000.0); geom += ", "; geom += -10.0 - (i / 1000.0); geom += " "; geom += 10.0 + (i / 1000.0); geom += ", "; geom += 10.0 + (i / 1000.0); geom += " "; geom += 10.0 + (i / 1000.0); geom += ", 180.0 90.0"; } else { // even row: two points geom += -10.0 - (i / 1000.0); geom += " "; geom += -10.0 - (i / 1000.0); geom += ", "; geom += 10.0 + (i / 1000.0); geom += " "; geom += 10.0 + (i / 1000.0); } geom += ")"; ins_stmt.setInt(1, i+1); ins_stmt.setString(2, name); ins_stmt.setString(3, geom); ins_stmt.executeUpdate(); } conn.commit(); // checking LINESTRINGs sql = "SELECT DISTINCT Count(*), ST_GeometryType(geom), "; sql += "ST_Srid(geom) FROM test_ln"; rs = stmt.executeQuery(sql); while(rs.next()) { // read the result set String msg = "> Inserted "; msg += rs.getInt(1); msg += " entities of type "; msg += rs.getString(2); msg += " SRID="; msg += rs.getInt(3); System.out.println(msg); } // inserting some POLYGONs // this time too we'll use a Prepared Statement sql = "INSERT INTO test_pg (id, name, geom) "; sql += "VALUES (?, ?, GeomFromText(?, 4326))"; ins_stmt = conn.prepareStatement(sql); conn.setAutoCommit(false); for (i = 0; i < 100000; i++) { // setting up values / binding String name = "test POLYGON #"; name += i + 1; ins_stmt.setInt(1, i+1); ins_stmt.setString(2, name); String geom = "POLYGON(("; geom += -10.0 - (i / 1000.0); geom += " "; geom += -10.0 - (i / 1000.0); geom += ", "; geom += 10.0 + (i / 1000.0); geom += " "; geom += -10.0 - (i / 1000.0); geom += ", "; geom += 10.0 + (i / 1000.0); geom += " "; geom += 10.0 + (i / 1000.0); geom += ", "; geom += -10.0 - (i / 1000.0); geom += " "; geom += 10.0 + (i / 1000.0); geom += ", "; geom += -10.0 - (i / 1000.0); geom += " "; geom += -10.0 - (i / 1000.0); geom += "))"; ins_stmt.setInt(1, i+1); ins_stmt.setString(2, name); ins_stmt.setString(3, geom); ins_stmt.executeUpdate(); } conn.commit(); // checking POLYGONs sql = "SELECT DISTINCT Count(*), ST_GeometryType(geom), "; sql += "ST_Srid(geom) FROM test_pg"; rs = stmt.executeQuery(sql); while(rs.next()) { // read the result set String msg = "> Inserted "; msg += rs.getInt(1); msg += " entities of type "; msg += rs.getString(2); msg += " SRID="; msg += rs.getInt(3); System.out.println(msg); } } catch(SQLException e) { // if the error message is "out of memory", // it probably means no database file is found System.err.println(e.getMessage()); } finally { try { if(conn != null) conn.close(); } catch(SQLException e) { // connection close failed. System.err.println(e); } } } } |
$ javac -classpath ".:sqlite-jdbc.3.7.2.jar"
SpatialiteSample.java $ java -classpath ".:sqlite-jdbc.3.7.2.jar" SpatialiteSample |
Conclusions
|
Caveat Although the Xerial JDBC connector seems to be really good, I noticed several potential flaws.Very shortly said, your SQL statements have to be absolutely clean and well tested: because when the JDBC connector encounters some invalid SQL (not at all an exceptional condition during the development life-cycle), it's most probable you'll then get a fatal JVM crash than a soft error exception. I became quite crazy attempting to identify the cause for so frequent crashes during my tests: untill I finally realized that the problem simply was some stupid missing braket or quotation mark in complex SQL statements. C can safely survive to all this without any damage, nicely reporting a soft and polite error message. On the other side JDBC / JVM are unexorably unforgiving (and unstable) when they handle such trivial errors. |
JDBC oddities
strcpy(sql,
"INSERT INTO xxx (id, geometry) VALUES (?, "); strcat(sql, "GeomFromText('POINT(? ?, ? ?)', 4326))"; sqlite3_prepare_v2 (db_handle, sql, strlen (sql), &stmt, NULL); sqlite3_bind_int (stmt, 0, 1); sqlite3_bind_double (stmt, 1, 10.01); sqlite3_bind_double (stmt, 2, 20.02); sqlite3_bind_double (stmt, 3, 30.03); sqlite3_bind_double (stmt, 4, 40.04); sqlite3_step (stmt); |
sql
= "INSERT INTO xxx (id, geometry) VALUES (?, "; sql += "GeomFromText('POINT(? ?, ? ?)', 4326))"; stmt = conn.prepareStatement(sql); stmt.setInt(1, 1); stmt.setDouble(2, 10.01); stmt.setDouble(3, 20.02); stmt.setDouble(4, 30.03); stmt.setDouble(5, 40.04); stmt.executeUpdate(); |
Back to Language Bindings |
Author: Alessandro Furieri a.furieri@lqt.it | |
This work is licensed under the Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) license. | |
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. |