Reputation: 2013
I have worked with Apache Derby before, but I have never used it in a Gradle Project. I have created a simple Derby Database in the root of my project using ij
Derby tool by running the following commands:
connect 'jdbc:derby:MyDbTest;create=true';
CREATE TABLE Hashes (
string_id int,
RandString varchar(255)
);
INSERT INTO Hashes (string_id, RandString) values (1, 'sdfdsfsw');
SELECT * FROM Hashes;
After this, my Java Code in Main.java
looks like:
package com.company;
import java.io.File;
import java.sql.*;
public class Main {
public static void main(String[] args) {
System.out.println("Current working directory : "+ new File(".").getAbsolutePath());
try {
Class.forName("org.apache.derby.jdbc.ClientDriver").newInstance();
} catch (Exception e) {
e.printStackTrace(); //Does not get executed!
}
Connection conn = null;
try
{
conn = DriverManager.getConnection("jdbc:derby:MyDbTest"); //Exception here!!
System.out.println("Connected to database MyDbTest");
Statement s = conn.createStatement();
ResultSet rs = s.executeQuery(
"select string_id, RandString from Hashes");
while(rs.next()) {
int string_id = rs.getInt("string_id");
String randString = rs.getString("RandString");
System.out.printf("string_id: %s, RandString: %s\n", string_id, randString);
}
}
catch (SQLException sqle)
{
printSQLException(sqle);
} finally {
try {
if (conn != null) {
conn.close();
DriverManager.getConnection("jdbc:derby:;shutdown=true;deregister=false");
}
} catch (SQLException sqle) {
printSQLException(sqle);
}
}
}
public static void printSQLException(SQLException e)
{
//According to this page:
//https://db.apache.org/derby/papers/DerbyTut/embedded_intro.html
//" A clean shutdown always throws SQL exception XJ015, which can be ignored."
if(e.getSQLState().equals("XJ015")) return; //Ignore
// Unwraps the entire exception chain to unveil the real cause of the
// Exception.
while (e != null)
{
System.err.println("\n----- SQLException -----");
System.err.println(" SQL State: " + e.getSQLState());
System.err.println(" Error Code: " + e.getErrorCode());
System.err.println(" Message: " + e.getMessage());
// for stack traces, refer to derby.log or uncomment this:
e.printStackTrace(System.err);
e = e.getNextException();
}
}
}
I seem to be able to load the ClientDriver
initially, but then when I try to get a connection to the Database I get the Exception
. The first line ensures the Current Working Directory is the root of my project where the MyDbTest
database is located.
My build.gradle
file looks like:
apply plugin: 'java'
apply plugin:'application'
mainClassName = "com.company.Main"
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
compile group: 'org.apache.derby', name: 'derbyclient', version: '10.14.1.0'
compile group: 'org.apache.derby', name: 'derbytools', version: '10.14.1.0'
runtime group: 'org.apache.derby', name: 'derbyclient', version: '10.14.1.0'
runtime group: 'org.apache.derby', name: 'derbytools', version: '10.14.1.0'
}
A gradle run
gives me:
Current working directory : /Users/<myname>/Documents/sources/tempFive/.
----- SQLException -----
SQL State: 08001
Error Code: 0
Message: No suitable driver found for jdbc:derby:MyDbTest
java.sql.SQLException: No suitable driver found for jdbc:derby:MyDbTest
at java.sql.DriverManager.getConnection(DriverManager.java:689)
at java.sql.DriverManager.getConnection(DriverManager.java:270)
at com.company.Main.main(Main.java:25)
I have made sure that my Derby Client and my version of the Derby Database is the same. I'm on Mac OSX 10.12 using IntelliJ 2017.3 and Java 8 update 151 if that helps.
I have worked with Apache Derby before and I can get this code to work without Gradle. The two causes of this exception mentioned in the answer to the other question are:
ClientDriver
(Or should I try to load some other class to exclude this possibility.)I was apparently unaware that I was using the Embedded Driver and not the Client Driver. When I used this without Gradle, I used to put all the jars in the entire Derby Lib directory in the classpath without bothering about what was used and what wasn't. My bad. So the first thing to change would be delete the try catch
in my main()
method:
try {
Class.forName("org.apache.derby.jdbc.ClientDriver").newInstance();
} catch (Exception e) {
e.printStackTrace(); //Does not get executed!
}
The ClientDriver
is never used, so there is no point in loading it. Next, as Mark Rotteveel pointed out I only need to depend on org.apache.derby:derby
. This was my real mistake, so I put below the complete corrected build.gradle
file:
apply plugin: 'java'
apply plugin:'application'
mainClassName = "com.company.Main"
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
compile group: 'org.apache.derby', name: 'derby', version: '10.14.1.0'
}
This is all I needed.
Upvotes: 0
Views: 2753
Reputation: 109174
You are using the wrong Derby driver, by using derbyclient
, you specify that you want to use the Derby (network) client driver, which supports the URL:
jdbc:derby://server[:port]/databaseName[;URLAttributes=value[;...]]
Your URL doesn't match, so it is rejected by the driver, and eventually java.sql.DriverManager
will report that it didn't find a suitable driver.
Instead you need to use the dependency org.apache.derby:derby
, as you seem to want to use the Derby Embedded driver. This driver is included in the full derby
package, which also includes the Derby database itself, but not in derbyclient
. This driver supports URL format:
jdbc:derby:databaseName;URLAttributes
Alternatively you do want to connect to an externally running Derby server, and in that case you are using the wrong URL.
See also Libraries provided by Derby and Database connection URL.
Upvotes: 3