# Embedded DB für Java



## cpu32 (26. Jul 2011)

Hallo zusammen,

ich bin vor einigen Tagen von VB.Net auf Java umgestiegen und komme mit der "neuen" Sprache auch prima zurecht! Nun möchte ich in ein Programm aber eine Datenbank einbetten. Mein Ziel ist es eine SQL-Server-Datenbank die ich vor einiger Zeit(also noch für VB.Net) mit dem SQL Server Express Managment Studio erstellt habe in das neue Java Programm so einzubinden, dass sowohl die eigentliche Datenbank als auch die entsprechend benötigten Treiber in der .jar-Datei "verschwinden", also komplett eingebettet sind. Versucht habe ich mich bereits an JavaDB alias durby. Die einzubettende DB ist recht klein(max. 5MB) Als IDE benutze ich übrigens Eclipse. 
Vielleicht könnt ihr mir ein par Tips geben welche Datenbank dafür am besten geeignet ist und wie ich sie dann in mein Programm einbinde.
Ich bin wie gesagt recht neu auf dem Gebiet. Vielleicht habe ich bei Google etc. einfach nach den falschen Begriffen gesucht... 

cpu32


----------



## maki (26. Jul 2011)

Kannst hier auch mal suchen, haben so ein Thema 1-2 mal pro Woche, Vorzugsweise mit dem Titel "welche db".

Die DB kannst du nicht ins Jar einbetten, muss ja schließlich geändert werden, kann aber zur Laufzeit erzeugt werden.


----------



## nillehammer (26. Jul 2011)

Ich benutze selbst HSQLDB. Die kann man entweder als eigenen Serverprozess betreiben (so wie SQLServer oder MySql) oder man bindet die jar Datei in sein Programm ein und kann an in-process drauf zugreifen


----------



## Gast2 (26. Jul 2011)

H2 Database Engine


----------



## cpu32 (26. Jul 2011)

Danke schon mal für die schnellen Antworten!

Gesucht habe ich auch schon, und es wie gesagt ja auch schon mit derby probiert, bekomme es aber nicht so richtig hin... Und ich habe leider nirgends ein Tutorial oder der gleichen gefunden 

Ich werde nochmal etwas herumprobieren... Vielen Dank schon mal!

cpu32


----------



## cpu32 (26. Jul 2011)

Nun hat sich noch eine Frage ergeben... in der connectionURL muss ich ja den DB-Namen übergeben, muss ich dort dann einen absoluten Pfard zu der .mdf-Datei angeben?


----------



## maki (26. Jul 2011)

*verschoben*


----------



## cpu32 (26. Jul 2011)

Hallo nochmal,

habe meine bisherigen Probleme mit eurer Hilfe (für euch ein paar Worte, aber es war für mich echt hilfreich!!  ) weitgehend gelöst, d.h. ich kann nun Datenbanken erstellen und auch darauf zugreifen. Mein Problem besteht aber in der migration (nennt man das so?) meiner bestehemden MDF-Datei in das "neue" Dantenbanksystem von derby. Außerdem suche ich nach einem einfachen Tool um die eingebetteten Datenbanken zu bearbeiten (also einem Tool wie dem Managment Studio für den SQL-Server von MS)
Dann habe ich's, glaub ich, geschafft....

cpu32


----------



## nillehammer (26. Jul 2011)

> Außerdem suche ich nach einem einfachen Tool um die eingebetteten Datenbanken zu bearbeiten (also einem Tool wie dem Managment Studio für den SQL-Server von MS)


Für sowas benutze ich persönlich sehr gerne SQurrel SQL (SQuirreL SQL Client Home Page)


----------



## cpu32 (26. Jul 2011)

Danke für die schnelle Antwort! Nur bringt mir das leider im Moment noch nichts, da ich die MDF-Datei nicht migriert bekomme...


----------



## nillehammer (26. Jul 2011)

> Danke für die schnelle Antwort! Nur bringt mir das leider im Moment noch nichts, da ich die MDF-Datei nicht migriert bekomme...


Auf dem Gebiet bin ich leider etwas ahnungslos (hab noch nie den MS SQL-Server benutzt). Deswegen nur zwei allgemeine Vorschläge. Du könntest Dich ber jdbc mit dem Server verbinden und eine "Select all" Abfrage machen, mit der Du in Java ein Objektmodell aufbaust. Danach genau das Objektmodell in die neue Datenbank speichern.
Eine andere Idee wäre, die Daten in csv-Dateien zu exportieren. Eine Google-Suche ergab u.a. den Treffer hier:
Export CSV Data From MSSQL Server Management Studio Express  Ozzie Perez


----------



## cpu32 (26. Jul 2011)

Aber wie soll ich dann die CSV Datei in meine Derby-DB bekommen? - Oh Mann ich fühl mich so ahnungslos und dumm :bahnhof:


----------



## turtle (27. Jul 2011)

Ich bin ja bekanntermassen ein Fan von mybatis.

Damit würde ich mir ein einfaches Migrations-Tool schreiben, wie nillehammer schon angedeutet hat. Dieses Tool macht zwei Verbindungen zu Datenbanken auf, einmal Deine Quell-SQL-Server-Datenbank, und die andere DB ist die Ziel-Derby-DB. Um per JDBC auf SQL-Server zuzugreifen, benötigst den JDBC-Treiber, den Du einfach hier runterladen kannst

Dann liest Dein Tool alle Zeilen aus allen Tabellen aus und schreibst sie in die Ziel-DB. Damit das einfach bleibt, würde ich mit dem bereits erwähnten Squirrel mir das Schema der Quell-Datenbank anschauen und die Tabellen manuell (oder programmatisch) in der Ziel-DB erzeugen, abhängig davon von der Anzahl der Tabellen


----------



## turtle (27. Jul 2011)

Wenn Du wirklich schon CSV-Dateien hast, kannst Du natürlich auch mit JDBC auf diese Dateien zugreifen. Dann wäre also die Quell-Datenbank die CSV-Datei.


----------



## cpu32 (28. Jul 2011)

Danke für all die Antworten!!! Ihr seid echt Klasse hier  
Hab das mit dem CSV-Import schon folgendermaßen hinbakommen:

```
Statement stmt = conn.createStatement();
			stmt.execute("Create Table Tabellenname (EinSpaltenName VARCHAR(255))"); // Zum erstellen der Tabelle (wenn Tabelle vorhanden natürlich nicht nötig)
			PreparedStatement ps=conn.prepareStatement(
				    "CALL SYSCS_UTIL.SYSCS_IMPORT_TABLE  (?,?,?,?,?,?,?)");
		    ps.setString(1,null);
		    ps.setString(2,"Tabellenname");
		    ps.setString(3,"c:\..."); //der Dateipfard
		    ps.setString(4,null);
		    ps.setString(5,null);
		    ps.setString(6,"UTF8"); //Codierung (wenn mans nicht angibt gibts probleme mit den umlauten)
		    ps.setString(7,"1"); 
		    ps.execute();
```


Ich habe aber noch eine Frage ... ich habe nun schon viel herumprobiert, bekomms aber mal wieder nicht hin  
Mein Ziel ist diesmal das erstellen einer Tabelle, nur wenn sie noch nicht vorhanden ist... ich habe auch bei google einiges gefunden aber es funzt alles nicht so recht...

mein ansatz:

```
rs = dmd.getTables(null, "APP", "Filme_Parts", null) ;
			if (!rs.next()) {
			stmt.execute("Create Table Tabellenname (Spaltenname Integer)");
			}
```

aber wenn die tabelle vorhanden ist erstellt er sie trozdem, oder versucht es zumindest was natürlich eine Exception gibt... Wie bereits gesagt benutze ich derby alias JavaDB im embedded mode

Ich hoffe ihr könnt mir noch einmal aus der Patsche helfen :/

Danke!!

cpu32


----------



## nillehammer (28. Jul 2011)

In MySql gäbe es da den schönen Zusatz "if not exists" in der SQL-Query. Ber Derby gibts das nicht. Aber hier hat einer schön beschrieben, was man da machen kann: Create Table IF NOT EXISTS … in JavaDB/Derby  Frickelblog


----------



## cpu32 (28. Jul 2011)

Diesen Weg habe ich  ja mehr oder weniger auch gewählt
Aber jetzt hab ichs noch mal genau so wie auf der genannten Website gemacht aber der versucht immernoch die Tabelle zu erstellen  Ich bekomme also immernoch diese Exception:
java.sql.SQLException: Table/View 'Tabellenname' ist bereits in Schema 'APP' vorhanden.
Mein geänderter Code:

```
DatabaseMetaData dmd = conn.getMetaData();
			ResultSet rs = dmd.getTables(null,"APP", "Tabellenname",null);
			if (!rs.next()) {
			stmt.executeUpdate("Create Table Tabellename (Spaltenname Integer)")
```
Ich bin doch mal davon ausgegangen, dass das auf der Website (Create Table IF NOT EXISTS … in JavaDB/Derby  Frickelblog) angegebene "s" ein Statement sein soll - oder ist das falsch, weil im Text drüber steht nix dazu 


Danke auf jeden fall schon mal für die schnelle Antwort und überhaupt deine Bemühungen 

cpu32


----------



## turtle (28. Jul 2011)

Sehe ich falsch oder steht da einmal Tabellenname und einmal Tabellename?


----------



## cpu32 (29. Jul 2011)

```
DatabaseMetaData dmd = conn.getMetaData();
            ResultSet rs = dmd.getTables(null,"APP", "Tabellenname",null);
            if (!rs.next()) {
            stmt.executeUpdate("Create Table Tabellenname (Spaltenname Integer)")
```

Sorry, war nur ein Tipfehler, hatte aber nichts mit dem eigentlichen Problem zu tun, da ich 'Tabellenname' nur für den eigentlichen Namen eingesetz habe, um den Code für euch besser verständlich zu machen und nicht meine geheimsten Geheimnisse preiszzugeben 

Aber mal im Ernst.. Ich hab den Code nun schon genau so übernommen blos die SQl-Querry etwas geändert, also meiner DB angepasst(Tabellen-Name und Spalten geändert), und es funktionier immer noch nicht...  Kann mir denn keiner sagen was ich falsch mache??? 

cpu32


----------



## nillehammer (29. Jul 2011)

Hallo,

die Methode DataBaseMetadata.getTables erwartet Parameter, um die Suchergebnisse zu filtern. Z.B. führt der zweite Parameter dazu, dass nur Tabellen im Schema "APP" ausgegeben werden. Ich bin ziemlich sicher, dass Deine Tabellen nicht im Schema "APP" liegen. Wenn ich mir Deine create-Table-Statements so anschaue, würde ich vermuten, dass Deine Tabellen in garkeinem Schema liegen. Dafür wäre der Parameter dann "". Aber Sicherheit schafft nur ein Blick in Deine Datenbank mit einem Tool. Falls Dich die Funktionen von  DataBaseMetadata näher interessieren, hier der Link zu den javadocs: Java Platform SE 6


----------



## cpu32 (29. Jul 2011)

Also anhand der Fehlermeldung sieht man doch, dass die Tabelle in dem Schema 'App' liegt:
java.sql.SQLException: Table/View 'Tabellenname' ist bereits in Schema 'APP' vorhanden. 
Und diese Exception kommt immer noch, und auch wenn ich statt "App" null eingebe  Wenn ich aber anstatt "App" "" Schreibe kommt das gleiche  
Das Problem ist ich verstehe, auch mit Doc, das ganze nicht so richtig:
Wenn da steht
	
	
	
	





```
if (!rs.next()) {
```
was gibt denn rs.next genau zurück? Also was bedutet das Ergebnis? -Das die Tabelle existiert? - Ich hab mir nun schon alles mögliche durchgelesen (deine Links auch!), Aber wenn ich das lese, siehts für mich aus als würde getTables Strings zurückgeben und kein boolean? ???:L


----------



## Gast2 (29. Jul 2011)

next() bewegt den Zeiger auf die nächste Zeile und gibt true zurück wenn die Zeile gültig ist.


----------



## nillehammer (29. Jul 2011)

Hallo,



> Also anhand der Fehlermeldung sieht man doch, dass die Tabelle in dem Schema 'App' liegt:


Wenn man sie sieht. Du hast sie leider nicht gepostet, deswegen musste ich raten.


> was gibt denn rs.next genau zurück?


Das Ergebnis jeder SQL-Abfrage ist eine Menge von Zeilen (Englisch "rows") welche je nach Abfrage 1 bis n Spalten/Werte enthalten. Das ResultSet ist Java's Abstraktion von diesem Abfrageergebnis.

Mit next() iterierst Du über die Zeilen, die das ResultSet enthält. Gleichzeitig sagt es Dir, ob noch eine weitere Zeile enthalten ist. In diesem konkreten Fall ermittelst Du, ob es eine Tabelle mit einem bestimmten Namen gibt. Wenn beim Aufruf von next() false zurück kommt, gibt es sie nicht und Du kannst sie anlegen.

Der beschriebene Weg ist so simpel, dass er funktionieren muss. Also entweder steckt noch ein Fehler in Deinem Code. Dabei können wir Dir helfen, wenn Du ihn postest und bitte etwas mehr als nen Dreizeiler. Es kann ja sein, dass der Fehler an einer anderen Stelle ist. Oder es liegt an Deiner DB-Konfiguration. Dabei können wir Dir nicht helfen (Du kannst ja schlecht eine Derby DB posten . Du kannst aber selbst noch etwas tiefer hinein schauen

```
DatabaseMetaData dmd = conn.getMetaData();
```
Setze an dieser Zeile einen BreakPoint (bei Eclipse per Doppelklick auf die Zeilennummer am linken Rand) und rufe Dein Programm statt mit Run mit Debug auf. Es bleibt dann an der Zeile stehen. Wenn Du dann "Step over" in der Symbolleiste (wieder Eclipse) anklickst, springt es genau eine Zeile weiter. Du kannst dich jetzt durch den Inhalt von DatabaseMetaData durch hangeln und schauen, was für Informationen da überhaupt drinnen stehen.

Gruß nillehammer


----------



## cpu32 (29. Jul 2011)

```
public static void connect() throws Exception{
//		Verbindung aufbauen
		//	DB-Treiber registrieren 
			String driver = "org.apache.derby.jdbc.EmbeddedDriver";
			Class.forName(driver);		
		//	ConnectionURL erstellen (Datenbank wird in einem Dialog ausgewählt
			String dbName = DB_Auswahl.choosenfile; 
			String connectionURL = "jdbc:derby:" + dbName + ";create=true";		
		//	Verbindung aufbauen
			conn = DriverManager.getConnection(connectionURL);
		//	Statement mit Verbindung verbinden
			stmt = conn.createStatement();
		//	Verbindung aufgebaut!

DatabaseMetaData dmd = conn.getMetaData();
			ResultSet rs = dmd.getTables(null, null, "Filme",null);
			if (rs.next() == false) {
		
			// Tabelle 'Filme' erstellen, falls sie nicht existiert
			stmt.execute("Create Table Filme (Name varchar(255), " +
					"Serie varchar(255), Jahr integer, FSK integer, Genre varchar(255), Subgenre varchar(255), Filmtyp varchar(255), " +
					"Infos varchar(255), FilmID  INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1))");
	}
conn.close
}
```
Also hier der Code... 

Hab das ganze debugged ... oder zumindest versucht  
Auch wenn die Tabellen existieren und das resultset true liefern müsste, liefert es false...
An der DB kanns eigentlich nicht liegen, da ich den ganz normalen JDBC-Treiber implementiert hab und auch jetzt immer wieder neue Datenbanken erstellt habe... Und nicht dran 'rumgeschraubt' hab. 
Ich verstehs nicht - Wenns nicht klappt (was ich mir nicht erklären könnte) müsste ich eben in den Dialog, wo ich auch den DB-Pfard abfrage ne checkbox rein bauen ob die Tabellen erstellt werden sollen :/

cpu32


----------



## nillehammer (29. Jul 2011)

Hallo,

ich glaube zwar nicht, dass das die Ursache des Fehler ist, aber Du solltest so bald als möglich ResultSet.close() und Statement.close() aufrufen, um die jdbc-Resourcen wieder frei zugeben.

Das mit dem Haken in der GUI muss nicht sein. Es gilt zwar nicht als guter Stil, Ablaufsteuerung mit Exceptions zu machen (deswegen ja der "Versuch" mit den DataBaseMetaData), aber Du kannst um dein create-Statement durchaus einen try-catch Block machen und die Exception, die anzeigt, dass die Tabelle schon existiert, einfach schlucken, loggen oder als Warnmeldung an der Gui anzeigen.

Gruß nillehammer


----------



## Ariol (29. Jul 2011)

Ich hatte mir damals einen "Manager" für Derby gebastelt:
http://www.java-forum.org/codeschni...kmanager-fuer-derby-multipleoutputstream.html


----------



## turtle (30. Jul 2011)

ich vermute Deine Abfrage macht die Suche case-sensitive. Daher probier mal

```
dmd.getTables(null,"APP", "TABELLENNAME ",null);
```


----------

