Package and use embedded database (H2.db file) inside a Jar? - java

I'm using H2 embedded database for my application. I would like to contain everything the application needs in it's own Jar, including it's database if possible. My app does not need to create temp files or anything, so basically the user just runs the Jar.
Is it possible to embed a database inside a Jar, and be able to INSERT new records as well as just SELECT out?
EDIT: Just to clarify, I'm not looking to embed the H2 driver jar inside my distributable jar, I'm looking to embed the h2 database file (someDatabase.h2.db file) inside a Jar and still be able to write/read from that database.

If you wish to embed the myDatabase.h2.db file inside the .jar, you can do so, but you'll have read-only access to the database. As .jar files are read-only, you can't modify them and therefore can't execute INSERT, DELETE or any DDL command.
That being said, below is an explanation on how to embed it read-only.
According to H2's documentation:
The JDBC URL "jdbc:h2:~/myDatabase" tells the H2 Engine to look for a database file named myDatabase.h2.db in the home directory of the current user.
The JDBC URL "jdbc:h2:file:/myDatabase" tells the H2 Engine to look for a database file named myDatabase.h2.db in the current directory (where the java program was executed).
If you embed the h2.db file inside a .jar, it is not accessible in a plain way. It is only accessible as a file inside a zip file.
In order to make H2 uset it, you have to use a zip as URL:
jdbc:h2:zip:~/data.zip!/test
See more in "Read Only Databases in Zip or Jar File".
When you embed the file as a resource in the jar, you may get it's relative url. Using...
MyClass.class.getClassLoader().getResource("myDatabase.h2.db")
...you'll get something like:
jar:file:/C:/folder1/folder2/myJar.jar!/myDatabase.h2.db
You can then manipulate it as a String and pass as JDBC URL connection to H2.

Related

HSQLDB in resources within a WAR

I've developed a small application using Spring Boot, which uses HSQLDB as a database to store users, for the time being. What I want to do is store the database within Maven's resource folder. My application.properties file contains the following configuration:
#...
spring.datasource.url=jdbc:hsqldb:file:src/main/resources/database/dashboard
#...
So, whenever I start the application with Java (right click on my Application's main() and Run As Spring Boot App), the database is stored right.
But, after packaging a WAR file with mvn clean install spring-boot:repackage, deploying it into Tomcat, e.g., and running it, the database is not stored within the exploded WAR.
My question is how can I tell spring.datasource.url=jdbc:hsqldb:file:* property to store the database within Maven Resources directory (which will point still after exploding the WAR)? Could I use some sort of environment variable as used in pom.xml?
EDIT
Given the answers by #Steve C and #fredt, I've realised that the database shouldn't be stored within the war. Instead, I'll store it within the user's Home dir spring.datasource.url=jdbc:hsqldb:file:~/tomcat_webapp_data/dashboard/database.. Thank you so much!
The directories and contents of a WAR file are read-only.
You can set the read_only flag in the HSQLDB database .properties file before including in the WAR. You access this kind of database with a jdbc:hsqldb:res:<path> URL.
If you want to store data in a persistent and updatable database, connect to the (at first non-existent) database within your application and set up its tables if they don't yet exist with data from a resource. You can then store data. The database path should be outside the directories that are used for jars and resources.
Contrary to one of the comments, HSQLDB is not limited to storing data in memory and can have disk-based tables, called CACHED tables.
You can include a variable in the database URL to pick up a pre-defined property from the web server. For example:
jdbc:hsqldb:file:${mydbpath}
See http://hsqldb.org/doc/2.0/guide/dbproperties-chapt.html#dpc_variables_url
Maven's src/main/resources directory is a build time path, not a runtime path.
If you're building a jar file, then everything in src/main/resources is copied to the root of the jar.
If you're building a war file, then everything in src/main/resources is copied to the root of the /WEB-INF/classes directory in the war.
Now, your JDBC URL jdbc:hsqldb:file:src/main/resources/database/dashboard is indicating a file with a relative path. At runtime this path is relative to the current working directory - and it's unlikely to exist at runtime anyway.
If you really want to build the database within your WAR, then given:
you're deploying an exploded WAR file (it's impossible to write to the content of the WAR file itself);
you really really want to store the database within the exploded WAR;
you want to put it in WEB-INF/database/dashboard (there's security implications if you store outside of the WEB-INF directory);
then you can compute the JDBC url using something like:
...
String databaseDirectoryName = servletContext.getRealPath("WEB-INF/database");
File databaseDirectory = new File(databaseDirectoryName);
if (!databaseDirectory.exists()) {
if (!databaseDirectory.mkdirs()) {
throw new RuntimeException("Failed to create database directory");
}
}
File databaseFile = new File(databaseDirectory, "dashboard");
String jdbcURL = "jdbc:hsqldb:" + databaseFile.toURI();
...
Getting that into your Spring configuration is an exercise for you; but using #Configuration and #Bean springs to mind as a way to do this - you just need to get access to the servletContext at Spring configuration time.

write to sqlite db packaged inside a jar

I'm trying to use a DB for reading and writing that is contained in a JAR.
I can read in it, but can't write throwed exeception :
java.sql.SQLException: path to '/database/scddata.db': 'LocationOfJar/database' does not exist
Is there any way I can bundle the database file inside a JAR?
Thanks in advance.
Jar files does not allows to write.
So :
define a working path (in properties for example). Let's call it : workingPath/file.db.
on init of your program, before opening your db.
check if db exists in working path
if does not exists : copy your jar file.db file to workingPath/file.db .
Then you program will use the db from workingPath/file.db for execution.

how to connect sqLite database to netbeans

I want to create some applications in Java netbeans using sqLite manager. i had done the following steps.
I have done plugin to Mozilla Firefox a sqLite-manger database
I have create database calling "mydb".
I have create a table with 2 values fname , lname.
I got mydb.sqlite file.
In netbeans library i have add jar file calling sqlite-jdbc 3.7.2 jar
then i copy the file mydb.sqlite from the folder and paste into netbeans project folder .
I want to connect with my project calling "test" in netbeans.
how to connect with netbeans application
Here is example http://www.tutorialspoint.com/sqlite/sqlite_java.htm
Most important part is jdbc url to create connection:
jdbc:sqlite:mydb.sqlite
This url assumes that test.db located in same directory, u application starts from. But u can put path to certain db.
For example:
jdbc:sqlite:c:/temp/sqlite/mydb.sqlite
If u distribute u application when there u manage some initialization. Actually u have to set environment for u application before start. Let's say u have good working application in netbeans and u copy application to another machine.
Configure environment for application to make it same as actual working application instance in netbeans. Question u should think about
What path to database to use relative or absolute?
Where database location on filesystem (absolute path to database)?
Where directory from which application starts (relative path to database)?
Useful information:
jdbc driver will create database mysql.sqlite if it doesn't exists (path to directory "c:/temp/sqlite" should be real) and after u can recreate necessary structure of database.
u can use System Properties https://docs.oracle.com/javase/tutorial/essential/environment/sysprop.html especially user.dir and user.home to set predefined location of u database (create database in there or copy existing database file)

Connect to a SQlite file inside a .jar file with JDBC? [duplicate]

I have created a Swing application that uses SQLite as a local database. The database file is located in project's root directory.
Project/DatabaseFile
The application runs fine on Eclipse, but when I run the packaged executable Jar, I get the following error:
No such table : table1
This means that the database is not reachable. When I examined the contents of the resulting JAR file, the database file was not there anymore.
In the code, I've linked the database as follows:
jdbc:sqlite:DatabaseFile
My question is, how to include the SQLite database in the executable Jar?
EDIT
When I placed the DB file in the source Folder Project/src/DatabaseFile and changed the path to jdbc:sqlite:src/DatabaseFile, it worked on Eclipse but again when running the Jar file as java -jar Project.jar. It said:
path to 'src/DatabaseFile': 'C:\Users\name\src' does not exist
I think I need to specify a relative path for the database.
EDIT
This is how I connect to the database:
public Connection getConnection(){
try{
Class.forName("org.sqlite.JDBC").newInstance();
con = DriverManager.getConnection("jdbc:sqlite:src/DatabaseFile");
} catch (Exception e) {
Log.fatal("Méthode: getConnection() | Class : SQLiteConnection | msg system : " + e.getMessage());
}
return con;
}
What library are you using for SQLite?
I did a search based on the connection URI you indicated and found this one. In the documentation it says:
2009 May 19th: sqlite-jdbc-3.6.14.1 released. This version supports "jdbc:sqlite::resource:" syntax to access read-only DB files contained in JAR archives, or external resources specified via URL, local files address etc. (see also the detailes)
If that is the driver you are using, then I would suggest the following connection URI:
"jdbc:sqlite::resource:DatabaseFile"
The key is that since your database is in a jar file, it can not be access as a file with FileInputStream. Instead it must be accessed through the JVM's support for it (namely with Class.getResource() or Class.getResourceAsStream()). Do note that resources contained within jar files are read-only. You won't be able to save any changes to your database.
I have found two different ways to name the filepath depending on how you are trying to access it. Assuming you are accessing the db is located in /yourproject/resource/ or /yourproject/bin/resource ( havent narrowed it down, mine is in both and I'm happy with it) you should use this as your path:
//Eclipse test path
String url = "jdbc:sqlite:resource/mydb.db";
or
//runnable jar path
String url = "jdbc:sqlite::resource:mydb.db";
then
mysqlitedatasource.setUrl(url);
Your way also works... by putting the db in /src

How to change the read/write permission of SQLite database on windows?

I created a software using NetBeans and SQLite database. When I clean and build, the executable jar file and database work fine. It can read and write data from the database.
Then I created .exe file using "install creator" and after installing the software, the same dist folder is created in Program files on my Windows PC. When I run the executable jar file from that dist folder, it can only read the database, but can't write. I get this message
java.sql.SQLException:attempt to write a readonly database
Can anyone please help me solve this problem? Thanks in advance.
check this
The problem, as it turns out, is that the PDO SQLite driver requires that if you are going to do a write operation (INSERT,UPDATE,DELETE,DROP, etc), then the folder the database resides in must have write permissions, as well as the actual database file.
I found this information in a comment at the very bottom of the PDO SQLite driver manual page.
You should write the user specific data to the Application Data folder of current user.
You can get the ROAMING directory from
String path = System.getenv("APPDATA");
Or if you want to make it platform independent you can use getProperty which will give you users home directory and then you can write to specific directory:
String path = System.getProperty("user.home");
You can form the sqlite on path like
String sqliteUrl = "jdbc:sqlite:"+path+"sample.db";
Use this code line:
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\databasefile.db"
I can say this is the proper way of creating DB in application folder on to the drive like C:\ without permission
Use this code line:
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\Yourfile.db"
I can say this is the proper way of crating DB without permission on to the drive like C:\

Categories