SQL (Structured Query Language) hat sich als Abfragesprache für relationale Datenbanken durchgesetzt.
Java ist eine verbreitete moderne Programmiersprache, die wie SQL plattformunabhängig ist,
sehr gut mit SQL zusammenarbeitet und besonders auf der Serverseite optimal auch für komplexe Anwendungen geeignet ist.
Persistenz per objektrelationalem Mapping (O/R-Mapping) ist nicht Thema der folgenden Beschreibungen, sondern nur direkte Zugriffe per JDBC.
Weiteres zu O/R finden Sie unter java-hibernate.htm.
Java-Anwendungen greifen auf SQL-Datenbanken über einen JDBC-Treiber zu (Java DataBase Connectivity). Dadurch kann der Java-Source-Code weitgehend datenbankunabhängig gehalten werden, so dass ein späterer Wechsel der SQL-Datenbank leicht möglich ist. Genaueres zu JDBC erfahren Sie unter http://www.oracle.com/technetwork/java/javase/jdbc.
In den meisten Fällen sind JDBC-Type-4-Treiber optimal. Sie sind sehr schnell und sehr einfach zu installieren.
Einen zu Ihrer Datenbank passenden JDBC-Treiber finden Sie am leichtesten unter http://industry.java.sun.com/products/jdbc/drivers.
Bei Multiuser-Anwendungen (z.B. in Webservern) greifen oft viele Benutzer gleichzeitig auf eine Datenbank zu. Um ressourcenschonend mit nur wenigen Datenbankverbindungen auskommen zu können und diese auch nicht immer wieder neu aufbauen zu müssen, wird Connection Pooling eingesetzt. Während hierfür früher externe Erweiterungen notwendig waren, ist dies mittlerweile Teil der JDBC2-Spezifikation und in Java-EE-Produkten integriert. Näheres hierzu finden Sie unter http://www.oracle.com/technetwork/java/javase/jdbc.
Class.forName( "org.hsqldb.jdbcDriver" ); cn = DriverManager.getConnection( "jdbc:hsqldb:file:C:/hSqlDbData/MeineDb", "sa", dbPwd ); |
java -classpath <path>\hsqldb.jar org.hsqldb.util.DatabaseManager |
java -classpath <path>\hsqldb.jar org.hsqldb.util.DatabaseManager -url "jdbc:hsqldb:file:C:/hSqlDbData/MeineDb" |
Type: | HSQL Database Engine Standalone |
Driver: | org.hsqldb.jdbcDriver |
URL: | jdbc:hsqldb:file:C:/hSqlDbData/MeineDb |
User: | sa |
Command | Create Table: | CREATE TABLE xx ( i INTEGER, s VARCHAR, d DATE ); |
Command | Insert: | INSERT INTO xx VALUES ( 123, 'abcABC', '2004-01-01' ); |
Command | Insert: | INSERT INTO xx VALUES ( 789, 'äöüߧ€', '2005-12-31' ); |
Command | Select: | SELECT * FROM xx; |
View | Refresh Tree: | [+] XX |
Class.forName( "com.mysql.jdbc.Driver" ); cn = DriverManager.getConnection( "jdbc:mysql://MyDbComputerNameOrIP:3306/myDatabaseName", dbUsr, dbPwd ); |
Class.forName( "org.postgresql.Driver" ); cn = DriverManager.getConnection( "jdbc:postgresql://MyDbComputerNameOrIP/myDatabaseName", dbUsr, dbPwd ); |
set CLASSPATH=<...>\ojdbc7.jar |
Class.forName( "oracle.jdbc.OracleDriver" ); cn = DriverManager.getConnection( "jdbc:oracle:thin:@MyDbComputerNameOrIP:1521:ORCL", dbUsr, dbPwd ); |
Sehen Sie sich die weiteren Hinweise unter oraclexe-db.htm und die Oracle-Doku unter Oracle 11.1 und Oracle XE 11.2 an.
Class.forName( "COM.ibm.db2.jdbc.app.DB2Driver" ); cn = DriverManager.getConnection( "jdbc:db2:myDatabaseName", dbUsr, dbPwd ); |
DB2/400 auf AS/400 (iSeries):
Class.forName( "com.ibm.as400.access.AS400JDBCDriver" ); cn = DriverManager.getConnection( "jdbc:as400://MyDbComputerNameOrIP/MyLib", dbUsr, dbPwd ); |
cn = DriverManager.getConnection( "jdbc:as400://MyDbComputerNameOrIP;naming=system;libraries=,lib1,lib2,lib3", dbUsr, dbPwd ); |
DB2/400 auf AS/400 (iSeries), DataSource für XA-Two-Phase-Commit:
DB2-Dokus:
Class.forName( "interbase.interclient.Driver" ); cn = DriverManager.getConnection( "jdbc:interbase://MyDbComputerNameOrIP/myDatabasePath/myDatabaseFile", dbUsr, dbPwd ); |
cn = DriverManager.getConnection( "jdbc:interbase://MyServer/C:/InterBase-Data/MyDbFile.gdb", dbUsr, dbPwd ); |
cn = DriverManager.getConnection( "jdbc:interbase://MyServer//usr/local/InterBase-Data/MyDbFile.gdb", dbUsr, dbPwd ); |
Class.forName( "org.firebirdsql.jdbc.FBDriver" ); cn = DriverManager.getConnection( "jdbc:firebirdsql://MyDbComputerNameOrIP/myDatabasePath/myDatabaseFile", dbUsr, dbPwd ); |
Class.forName( "com.sybase.jdbc2.jdbc.SybDriver" ); cn = DriverManager.getConnection( "jdbc:sybase:Tds:MyDbComputerNameOrIP:2638", dbUsr, dbPwd ); |
Class.forName( "net.sourceforge.jtds.jdbc.Driver" ); cn = DriverManager.getConnection( "jdbc:jtds:sqlserver://MyDbComputerNameOrIP:1433/master", dbUsr, dbPwd ); |
Class.forName( "com.microsoft.jdbc.sqlserver.SQLServerDriver" ); cn = DriverManager.getConnection( "jdbc:microsoft:sqlserver://MyDbComputerNameOrIP:1433", dbUsr, dbPwd ); |
Class.forName( "sun.jdbc.odbc.JdbcOdbcDriver" ); Connection cn = DriverManager.getConnection( "jdbc:odbc:" + sDsn, dbUsr, dbPwd ); |
Voraussetzung für das folgende einfache Beispiel ist eine aktive SQL-Datenbank, die bereits eine Tabelle enthält.
Anleitungen zum Anlegen einer Database und einer Tabelle finden Sie unter
sql.htm, mysql.htm und
postgresql.htm.
Der unten gezeigte Code muss in eine Datei 'DbTableShow.java' gespeichert werden und folgendermaßen compiliert und gestartet werden:
set classpath=.;<JdbcTreiberPfad>\<JdbcTreiberDatei>
javac DbTableShow.java
java DbTableShow
Das Programm erfragt dann die erforderlichen Parameter.
Alternativ können die Parameter auch direkt auf der Kommandozeile beim Aufruf übergeben werden:
set classpath=.;<JdbcTreiberPfad>\<JdbcTreiberDatei>
javac DbTableShow.java
java DbTableShow <TabellenName> <JdbcTreiberKlasse> <DatenbankUrl> <Benutzer> <Passwort>
(Falls Ihr Webbrowser Zeilen umgebrochen hat: Es müssen drei Zeilen eingegeben werden.)
<JdbcTreiberPfad> und <JdbcTreiberDatei> müssen Sie durch den Pfad und den Namen des zu Ihrer Datenbank passenden JDBC-Treibers ersetzen. <JdbcTreiberDatei> sollte ein JDBC-Type-4-Treiber sein und muss im Classpath enthalten sein.
<JdbcTreiberKlasse> muss durch den zur <JdbcTreiberDatei> passenden Treiber-Klassennamen ersetzt werden.
<DatenbankUrl> muss durch die URL-Adresse der Datenbank ersetzt werden.
<TabellenName> muss durch den Namen der in der Datenbank enthaltenen Tabelle ersetzt werden.
Eine konkrete Sequenz könnte für hSqlDb zum Beispiel folgendermaßen lauten:
set CLASSPATH=.;hsqldb.jar
java org.hsqldb.util.DatabaseManager -url "jdbc:hsqldb:file:C:/hSqlDbData/MeineDb"
javac DbTableShow.java
java xx DbTableShow org.hsqldb.jdbcDriver jdbc:hsqldb:file:C:/hSqlDbData/MeineDb sa
(Falls Ihr Webbrowser Zeilen umgebrochen hat: Es müssen vier Zeilen eingegeben werden.)
Für MySQL könnte eine konkrete Sequenz zum Beispiel folgendermaßen lauten:
set CLASSPATH=.;mysql-connector-java-5.1.16-bin.jar
javac DbTableShow.java
java DbTableShow MeineTestTabelle com.mysql.jdbc.Driver jdbc:mysql://localhost:3306/MeineDb root mysqlpwd
(Falls Ihr Webbrowser Zeilen umgebrochen hat: Es müssen drei Zeilen eingegeben werden.)
Für viele weitere Datenbanken finden Sie Beispiele für <JdbcTreiberDatei>, <JdbcTreiberKlasse> und <DatenbankUrl> oben unter java-sql.htm#JDBC.
// DbTableShow.java import java.io.*; import java.sql.*; public class DbTableShow { public static void main( String[] args ) { String dbTbl=null, dbDrv=null, dbUrl=null, dbUsr="", dbPwd=""; if( args.length > 2 ) { dbTbl = args[0]; dbDrv = args[1]; dbUrl = args[2]; if( args.length > 3 ) dbUsr = args[3]; if( args.length > 4 ) dbPwd = args[4]; } else { try { BufferedReader in = new BufferedReader( new InputStreamReader( System.in ) ); System.out.println( "Name der Tabelle eingeben (z.B. MeineTestTabelle):" ); dbTbl = in.readLine(); System.out.println( "Name des Datenbanktreibers eingeben (z.B. com.mysql.jdbc.Driver):" ); dbDrv = in.readLine(); System.out.println( "Url der Datenbank eingeben (z.B. jdbc:mysql://localhost:3306/MeineDb):" ); dbUrl = in.readLine(); System.out.println( "Benutzername (z.B. root):" ); dbUsr = in.readLine(); System.out.println( "Passwort (z.B. mysqlpwd):" ); dbPwd = in.readLine(); } catch( IOException ex ) { System.out.println( ex ); } } showDbTable( dbTbl, dbDrv, dbUrl, dbUsr, dbPwd ); } static void showDbTable( String dbTbl, String dbDrv, String dbUrl, String dbUsr, String dbPwd ) { if( dbTbl == null || dbTbl.length() == 0 || dbDrv == null || dbDrv.length() == 0 || dbUrl == null || dbUrl.length() == 0 ) { System.out.println( "Fehler: Parameter fehlt." ); return; } Connection cn = null; Statement st = null; ResultSet rs = null; try { // Select fitting database driver and connect: Class.forName( dbDrv ); cn = DriverManager.getConnection( dbUrl, dbUsr, dbPwd ); st = cn.createStatement(); rs = st.executeQuery( "select * from " + dbTbl ); // Get meta data: ResultSetMetaData rsmd = rs.getMetaData(); int i, n = rsmd.getColumnCount(); // Print table content: for( i=0; i<n; i++ ) System.out.print( "+---------------" ); System.out.println( "+" ); for( i=1; i<=n; i++ ) // Attention: first column with 1 instead of 0 System.out.print( "| " + extendStringTo14( rsmd.getColumnName( i ) ) ); System.out.println( "|" ); for( i=0; i<n; i++ ) System.out.print( "+---------------" ); System.out.println( "+" ); while( rs.next() ) { for( i=1; i<=n; i++ ) // Attention: first column with 1 instead of 0 System.out.print( "| " + extendStringTo14( rs.getString( i ) ) ); System.out.println( "|" ); } for( i=0; i<n; i++ ) System.out.print( "+---------------" ); System.out.println( "+" ); } catch( Exception ex ) { System.out.println( ex ); } finally { try { if( rs != null ) rs.close(); } catch( Exception ex ) {/* nothing to do*/} try { if( st != null ) st.close(); } catch( Exception ex ) {/* nothing to do*/} try { if( cn != null ) cn.close(); } catch( Exception ex ) {/* nothing to do*/} } } // Extend String to length of 14 characters static final String extendStringTo14( String s ) { if( s == null ) { s = ""; } final String sFillStrWithWantLen = " "; final int iWantLen = sFillStrWithWantLen.length(); final int iActLen = s.length(); if( iActLen < iWantLen ) return (s + sFillStrWithWantLen).substring( 0, iWantLen ); if( iActLen > 2 * iWantLen ) return s.substring( 0, 2 * iWantLen ); return s; } }
Ein weiteres ähnliches Beispiel finden Sie unter java-sql-csv-html.htm.
... gibt es in jsp-grundlagen.htm.
Um Binärdaten (z.B. Bilder) in einer SQL-Datenbank zu speichern, muss die Tabellenspalte für das 'Binary Large Object' je nach SQL-Datenbank als BLOB, LONGBLOB, LONG RAW oder BYTEA definiert sein (siehe sql.htm#SQL-Datentypen).
Für MySQL zum Beispiel so:
CREATE TABLE MyTable ( Name VARCHAR PRIMARY KEY, MyImage BLOB );
Und für PostgreSQL 7.2 zum Beispiel so:
CREATE TABLE MyTable ( Name VARCHAR PRIMARY KEY, MyImage BYTEA );
Der folgende Code-Ausschnitt zeigt, wie beliebige Binärdaten in einer SQL-RDBMS gespeichert werden können. Es wird hier von einer Datei ausgegangen ('sFilePathAndName'). Stattdessen kann natürlich auch direkt ein Stream gespeichert werden. Im Beispiel ist noch keine Fehlerbehandlung implementiert.
Class.forName( ... ); Connection dbCon = DriverManager.getConnection( ... ); File fl = new File( sFilePathAndName ); FileInputStream fis = new FileInputStream( fl ); PreparedStatement pstmt = dbCon.prepareStatement( "update MyTable set MyImage = ? where ..." ); pstmt.setBinaryStream( 1, fis, (int)fl.length() ); pstmt.executeUpdate(); pstmt.close(); dbCon.close(); fis.close(); |
Der folgende Code-Ausschnitt zeigt, wie Binärdaten aus einer SQL-RDBMS geladen werden. Hier im Beispiel werden die Binärdaten in eine Datei gespeichert ('sFilePathAndName'). Stattdessen kann natürlich auch direkt der Stream verwertet werden, wie das Image-Beispiel weiter unten zeigt. Im Beispiel ist noch keine Fehlerbehandlung implementiert. Statt mit 'getBinaryStream()' kann bei den meisten Datenbanken (und Treibern) auch mit 'getBytes()' gelesen werden.
Class.forName( ... ); Connection dbCon = DriverManager.getConnection( ... ); Statement st = dbCon.createStatement(); ResultSet rs = st.executeQuery( "select MyImage from MyTable where ..." ); if( rs.next() ) { InputStream is = rs.getBinaryStream( "MyImage" ); FileOutputStream fos = new FileOutputStream( sFilePathAndName ); byte[] buff = new byte[8192]; int len; while( 0 < (len = is.read( buff )) ) fos.write( buff, 0, len ); fos.close(); is.close(); } rs.close(); st.close(); dbCon.close(); |
Ein komplettes Programmierbeispiel zum Speichern von Binärdateien (z.B. Bildern) in eine Datenbank könnte folgendermaßen aussehen:
import java.io.*; import java.sql.*; public class DbImgStore { public static void main( String[] args ) { if( 9 != args.length ) { System.out.println( "Usage:\n" + " java DbImgStore drv url usr pwd tbl keyColumn keyValue imgColumn imgFile\n" + "e.g.\n" + " java DbImgStore com.mysql.jdbc.Driver jdbc:mysql://localhost:3306/MeineDb" + " root mysqlpwd MeineAdressen Name Torsten Foto img/Torsten-Horn.jpg" ); System.exit( 1 ); } FileInputStream fis = null; Connection cn = null; PreparedStatement st = null; try { File fl = new File( args[8] ); // imgFile fis = new FileInputStream( fl ); Class.forName( args[0] ); // drv cn = DriverManager.getConnection( args[1], args[2], args[3] ); // url, usr, pwd // update tbl set imgColumn = 'imgFile?' where keyColumn = 'keyValue?': st = cn.prepareStatement( "update " + args[4] + " set " + args[7] + " = ? where " + args[5] + " = ?" ); st.setBinaryStream( 1, fis, (int)fl.length() ); // imgFile st.setString( 2, args[6] ); // keyValue st.executeUpdate(); System.out.println( fl.length() + " Bytes successfully loaded." ); } catch( Exception ex ) { System.out.println( ex ); } finally { try { if( null != st ) st.close(); } catch( Exception ex ) {/*ok*/} try { if( null != cn ) cn.close(); } catch( Exception ex ) {/*ok*/} try { if( null != fis ) fis.close(); } catch( Exception ex ) {/*ok*/} } } }
Ein komplettes Programmierbeispiel zum Anzeigen in einer Datenbank als BLOB gespeicherter Bilder könnte folgendermaßen aussehen:
import java.awt.*; import java.awt.event.*; import java.awt.image.BufferedImage; import java.io.InputStream; import java.sql.*; import java.util.Vector; import javax.imageio.ImageIO; public class DbImgShow extends Frame { public static void main( String[] args ) { if( 6 != args.length ) { System.out.println( "Usage:\n" + " java DbImgShow drv url usr pwd tbl imgColumn\n" + "e.g.\n" + " java DbImgShow com.mysql.jdbc.Driver jdbc:mysql://localhost:3306/MeineDb" + " root mysqlpwd MeineAdressen Foto" ); System.exit( 1 ); } new DbImgShow( args ); } DbImgShow( String[] args ) { setSize( 100, 100 ); setVisible( true ); add( new ImgShowCanvas( args ) ); pack(); addWindowListener( new WindowAdapter() { public void windowClosing( WindowEvent ev ) { dispose(); System.exit( 0 ); } } ); } } class ImgShowCanvas extends Canvas { private String[] ss; private BufferedImage[] imgs; ImgShowCanvas( String[] args ) { Vector vStr = new Vector(); Vector vImg = new Vector(); Connection cn = null; Statement st = null; ResultSet rs = null; try { Class.forName( args[0] ); cn = DriverManager.getConnection( args[1], args[2], args[3] ); st = cn.createStatement(); rs = st.executeQuery( "select * from " + args[4] ); while( rs.next() ) { InputStream is = rs.getBinaryStream( args[5] ); if( null != is ) { vStr.add( rs.getString( 1 ) ); vImg.add( ImageIO.read( is ) ); try { is.close(); } catch( Exception ex ) {/*ok*/} } } } catch( Exception ex ) { System.out.println( ex ); } finally { try { if( null != rs ) rs.close(); } catch( Exception ex ) {/*ok*/} try { if( null != st ) st.close(); } catch( Exception ex ) {/*ok*/} try { if( null != cn ) cn.close(); } catch( Exception ex ) {/*ok*/} } ss = (String[])(vStr.toArray( new String[vStr.size()] )); imgs = (BufferedImage[])(vImg.toArray( new BufferedImage[vImg.size()] )); } public void paint( Graphics g ) { int w = 0; g.drawString( "Error", 30, 40 ); for( int i=0; i<ss.length && i<imgs.length; i++ ) { g.drawString( ss[i], w, 15 ); g.drawImage( imgs[i], w, 20, this ); w += imgs[i].getWidth( this ); } } public Dimension getPreferredSize() { int w=0, h=80; for( int i=0; i<imgs.length; i++ ) { w += imgs[i].getWidth( this ); h = Math.max( h, imgs[i].getHeight( this ) ); } w = Math.max( w, 100 ); h += 20; return new Dimension( w, h ); } public Dimension getMinimumSize() { return getPreferredSize(); } }