{"id":387,"date":"2011-11-03T14:16:51","date_gmt":"2011-11-03T12:16:51","guid":{"rendered":"http:\/\/www.kristiansborg.dk\/bibliotek\/?page_id=387"},"modified":"2011-11-03T14:22:05","modified_gmt":"2011-11-03T12:22:05","slug":"kapitel-4-jdbc","status":"publish","type":"page","link":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-4-jdbc\/","title":{"rendered":"Kapitel 4 JDBC"},"content":{"rendered":"<div style=\"border: 1px solid red; color: red\">\n<b>Du l\u00e6ser en gammel bog<\/b><br \/>\nDen bog, du l\u00e6ser her, er fra 1998, og mange ting kan have \u00e6ndret sig siden da.<br \/>\nVi h\u00e5ber, at du stadig kan finde relevant information i den.<br \/>\nHvis du vil l\u00e6se aktuelle oplysninger om de avancerede dele af Java, anbefaler vi<br \/>\nbogen <a href=\"http:\/\/clk.tradedoubler.com\/click?p(197229)a(2029446)g(19172914)url(http:\/\/www.adlibris.com\/dk\/product.aspx?isbn=0132354799)\"  target=\"_blank\">Core Java &#8211; Advanced Features<\/a><img decoding=\"async\" src=\"http:\/\/impdk.tradedoubler.com\/imp?type(inv)g(19172914)a(2029446)\" \/>\n<\/div>\n<p>Mange applikationer arbejder p\u00e5 data. Disse data gemmes bedst i en database, og hvis man ikke selv har tid til at programmere et databasesystem, kan man bruge et af de kommercielle systemer, der allerede findes. Det giver blot det problem, at man ikke selv har programmeret interfacet til databasen, og man er s\u00e5ledes afh\u00e6ngig producentens information, n\u00e5r man skal skrive et program, der tilg\u00e5r databasen. N\u00e5r man har skrevet programmet, er det knyttet meget t\u00e6t til databasen. Hvis man senere finder ud af, at det er bedre at bruge en anden database, skal hovedparten af programmet sandsynligvis skrives om. Dette kan ogs\u00e5 v\u00e6re tilf\u00e6ldet, hvis man installerer en ny version af den samme database.<\/p>\n<p>&nbsp;<\/p>\n<p>For at im\u00f8dekomme dette problem blev ODBC-standarden defineret. Det er en standard, der g\u00f8r, at man kan tilg\u00e5 databaser fra forskellige leverand\u00f8rer p\u00e5 en ensartet m\u00e5de. Fremgangsm\u00e5den er den, at man installerer nogle drivere p\u00e5 sin computer. Disse drivere s\u00f8rger for at overs\u00e6tte programmernes foresp\u00f8rgsler i ODBC-sprog til et sprog, databasen forst\u00e5r.<\/p>\n<p>&nbsp;<\/p>\n<p>I forhold til Java har ODBC imidlertid det problem, at det kr\u00e6ver, at der skal installeres platformsafh\u00e6ngigt software p\u00e5 brugerens computer. For at undg\u00e5 dette blev JDBC \u2013 Java DataBase Connectivity \u2013 defineret. JDBC-standarden g\u00f8r det muligt at tilg\u00e5 en database, der underst\u00f8tter JDBC, p\u00e5 en platformsuafh\u00e6ngig m\u00e5de. Da JDBC blev udviklet, var det imidlertid klart, at det ikke var alle databaseproducenter, der havde mulighed for at underst\u00f8tte standarden omg\u00e5ende. Derfor blev der udviklet forskellige grader af JDBC, hvor alle ikke beh\u00f8ver at v\u00e6re platformsuafh\u00e6ngige.<\/p>\n<p>&nbsp;<\/p>\n<p>For at kunne bruge JDBC er det n\u00f8dvendigt at installere JDBC-drivere til den database, man \u00f8nsker adgang til. Disse drivers kan dog skrives i Java og kan s\u00e5ledes v\u00e6re platformsuafh\u00e6ngig \u2013 det afh\u00e6nger af JDBC-drivernes type.<\/p>\n<p>&nbsp;<\/p>\n<p>Der findes f\u00f8lgende typer JDBC-drivere:<\/p>\n<p>&nbsp;<\/p>\n<ul>\n<li>JDBC-ODBC-bro<em>en <\/em>giver adgang fra JDBC til ODBC-databaser. Dette kr\u00e6ver, at der installeres ODBC-drivers p\u00e5 brugerens computer. Denne fremgangsm\u00e5de er ikke platformsuafh\u00e6ngig.<\/li>\n<li>En native-API partiel Java-driver\u00a0konverterer JDBC-kald direkte til kald i databasens API. Dette kr\u00e6ver, at der bliver installeret software fra producenten p\u00e5 brugerens computer.<\/li>\n<li>En ren Java net-protokol\u00a0konverterer JDBC-kald til en producentuafh\u00e6ngig netprotokol. Beskederne bliver af databaseserveren konverteret til databasens eget sprog.<\/li>\n<li>En ren Java native-protokol\u00a0konverterer JDBC-kald direkte til den protokol, databasen bruger.<\/li>\n<\/ul>\n<p><em> <\/em><\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>I dette kapitel vil der blive brugt en JDBC-ODBC-bro til at skaffe adgang til en Microsoft Access database, men fremgangsm\u00e5den er naturligvis n\u00e6sten den samme uafh\u00e6ngigt af, hvilken database man bruger. Da der i kapitlet vil blive skrevet foresp\u00f8rgsler og kommandoer i SQL\u00a0(Structured Query Language), er det en fordel at have kendskab til dette sprog. Har man brug for at f\u00e5 det genopfrisket, kan man bruge appendiks B hertil. Ellers kan appendikset bruges som opslagsv\u00e6rk, n\u00e5r man selv formulerer SQL-foresp\u00f8rgsler.<\/p>\n<p>&nbsp;<\/p>\n<h1>Databasen<\/h1>\n<p>&nbsp;<\/p>\n<p>Den database, der bliver brugt i eksemplerne i dette kapitel, er som n\u00e6vnt en Access-database. Denne database indeholder en tabel ved navn AdresseTabel. Nedenst\u00e5ende skema viser, hvilke attributter der findes i tabellen.<\/p>\n<p>&nbsp;<\/p>\n<table border=\"1\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td width=\"326\" valign=\"top\">Navn<\/td>\n<td width=\"326\" valign=\"top\">Type<\/td>\n<\/tr>\n<tr>\n<td width=\"326\" valign=\"top\">AdresselistID<\/td>\n<td width=\"326\" valign=\"top\">Langt heltal (auto-nummerering)<\/td>\n<\/tr>\n<tr>\n<td width=\"326\" valign=\"top\">Fornavn<\/td>\n<td width=\"326\" valign=\"top\">Tekst<\/td>\n<\/tr>\n<tr>\n<td width=\"326\" valign=\"top\">Efternavn<\/td>\n<td width=\"326\" valign=\"top\">Tekst<\/td>\n<\/tr>\n<tr>\n<td width=\"326\" valign=\"top\">Adresse<\/td>\n<td width=\"326\" valign=\"top\">Tekst<\/td>\n<\/tr>\n<tr>\n<td width=\"326\" valign=\"top\">Postnr<\/td>\n<td width=\"326\" valign=\"top\">Tekst<\/td>\n<\/tr>\n<tr>\n<td width=\"326\" valign=\"top\">Bynavn<\/td>\n<td width=\"326\" valign=\"top\">Tekst<\/td>\n<\/tr>\n<tr>\n<td width=\"326\" valign=\"top\">Telefon<\/td>\n<td width=\"326\" valign=\"top\">Tekst<\/td>\n<\/tr>\n<tr>\n<td width=\"326\" valign=\"top\">Mobiltelefon<\/td>\n<td width=\"326\" valign=\"top\">Tekst<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>&nbsp;<\/p>\n<h1>Driverne<\/h1>\n<p>&nbsp;<\/p>\n<p>Det f\u00f8rste, man skal g\u00f8re, n\u00e5r man vil skrive en applikation, der benytter en database, er at finde de drivere, der skal bruges til at tilg\u00e5 den p\u00e5g\u00e6ldende database. De fleste databaseproducenter l\u00e6gger driverne p\u00e5 deres hjemmeside, men de findes ofte i flere versioner. Valget st\u00e5r i disse tilf\u00e6lde ofte imellem en version, der er platformsuafh\u00e6ngig og en, der ikke er. Ofte byder den ikke-uafh\u00e6ngige version p\u00e5 flere muligheder og h\u00f8jere hastighed end den uafh\u00e6ngige, og man m\u00e5 i s\u00e5 fald vurdere, hvor vigtigt platformsuafh\u00e6ngigheden er.<\/p>\n<p>&nbsp;<\/p>\n<h1>ODBC<\/h1>\n<p>&nbsp;<\/p>\n<p>Hvis man v\u00e6lger at bruge en ODBC-JDBC-bro, skal man indstille sine ODBC-drivere korrekt. Fra Windows 95 g\u00f8r man det fra det punkt, der hedder 32-bit ODBC, i Kontrolpanelet. Her skal man give den database, man vil anvende, et navn. Dette navn bruges fra de programmer, der tilg\u00e5r databasen. Fordelen ved denne fremgangsm\u00e5de er, at programmerne er uafh\u00e6ngige af, hvor databasen er placeret \u2013 bare den er registreret med det samme navn.<\/p>\n<p>&nbsp;<\/p>\n<p>Registreringen af databasen foreg\u00e5r under fanen System DSN,<\/p>\n<p>&nbsp;<\/p>\n<p>hvor man skal klikke p\u00e5 knappen Tilf\u00f8j. Som det fremg\u00e5r af figur 4.1, bliver man nu pr\u00e6senteret for en oversigt over alle de ODBC-drivere, der er installeret p\u00e5 computeren. I den n\u00e6ste dialogboks kan man angive datakildenavnet. Det er det navn, der skal benyttes fra ens programmer. Derudover skal man v\u00e6lge, hvilken databasefil navnet skal referere til. Figur 4.2 viser, hvordan Access ODBC-driver er sat op til de eksempler, der bliver gennemg\u00e5et i dette kapitel.<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"http:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0401.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft size-full wp-image-389\" title=\"0401\" src=\"http:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0401.png\" alt=\"\" width=\"441\" height=\"323\" srcset=\"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0401.png 441w, https:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0401-300x219.png 300w\" sizes=\"auto, (max-width: 441px) 100vw, 441px\" \/><\/a><\/p>\n<p>Ops\u00e6tning af ODBC-drivere trin 1.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"http:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0402.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft size-full wp-image-388\" title=\"0402\" src=\"http:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0402.png\" alt=\"\" width=\"489\" height=\"410\" srcset=\"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0402.png 489w, https:\/\/www.kristiansborg.dk\/bibliotek\/wp-content\/uploads\/2011\/11\/0402-300x251.png 300w\" sizes=\"auto, (max-width: 489px) 100vw, 489px\" \/><\/a><\/p>\n<p>Ops\u00e6tning af ODBC-drivere trin 2.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<h1>Forbindelsen<\/h1>\n<p>&nbsp;<\/p>\n<p>Selve applikationen skal oprette en forbindelse til databasen og herefter sende de SQL-kommandoer, der skal udf\u00f8res. For at kunne oprette en forbindelse til databasen er det imidlertid et krav, at Java kender eksistensen af den driver, man vil bruge. Derfor skal driveren registreres. Det foretages af nedenst\u00e5ende kode:<\/p>\n<p>&nbsp;<\/p>\n<p>try<\/p>\n<p>{<\/p>\n<p>Class.forName(&#8220;sun.jdbc.odbc.JdbcOdbcDriver&#8221;);<\/p>\n<p>}<\/p>\n<p>catch (ClassNotFoundException cnfe)<\/p>\n<p>{<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>S\u00e6tningen Class.forName(&#8220;sun.jdbc.odbc.JdbcOdbcDriver&#8221;) indl\u00e6ser klassen sun.jdbc.odbc.JdbcOdbcDriver, der er JDBC-driveren til JDBC-ODBC-broen.<\/p>\n<p>&nbsp;<\/p>\n<p>Class.forName\u00a0bliver beskrevet yderligere i kapitel Reflections i denne bog. I denne sammenh\u00e6ng er det tilstr\u00e6kkeligt at vide, at metodekaldet indl\u00e6ser driveren, der automatisk registrerer sig selv.<\/p>\n<p>&nbsp;<\/p>\n<p>Hvis man str\u00e6ber efter en platformsuafh\u00e6ngig implementering med JDBC, skal man v\u00e6re forsigtig med at angive driverens klassenavn direkte i koden. Det er nemlig ikke alle drivere, der er platformsuafh\u00e6ngige. Emnet platformsuafh\u00e6ngighed beskrives n\u00e6rmere i kapitlet 100% Pure Java senere i denne bog. P\u00e5 nuv\u00e6rende tidspunkt er det dog relevant at komme med nogle bem\u00e6rkninger om, hvordan man kan sikre en platformsuafh\u00e6ngig implementering.<\/p>\n<p>&nbsp;<\/p>\n<p>Det kan man eksempelvis g\u00f8re ved at lade brugeren selv v\u00e6lge, hvilken driver der skal benyttes. Til dette form\u00e5l skal man bruge en liste over de installerede JDBC-drivere. Denne liste stilles til r\u00e5dighed af klassen DriverManager. Listen omfatter kun de drivere, der er registreret i manageren. Klassen DriverList viser, hvordan man kan f\u00e5 og udskrive en liste over de installerede drivere.<\/p>\n<p>&nbsp;<\/p>\n<p>import java.sql.*;<\/p>\n<p>import java.util.*;<\/p>\n<p>&nbsp;<\/p>\n<p>public class DriverList<\/p>\n<p>{<\/p>\n<p>public static final void main (String args[])<\/p>\n<p>{<\/p>\n<p>try<\/p>\n<p>{<\/p>\n<p>Class.forName(&#8220;sun.jdbc.odbc.JdbcOdbcDriver&#8221;);<\/p>\n<p>\/*<\/p>\n<p>&#8230;<\/p>\n<p>indl\u00e6s flere drivere<\/p>\n<p>&#8230;<\/p>\n<p>*\/<\/p>\n<p>}<\/p>\n<p>catch (ClassNotFoundException cnfe)<\/p>\n<p>{<\/p>\n<p>}<\/p>\n<p>Enumeration drivers = DriverManager.getDrivers();<\/p>\n<p>&nbsp;<\/p>\n<p>while (drivers.hasMoreElements())<\/p>\n<p>{<\/p>\n<p>System.out.println(drivers.nextElement());<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Metoden getDrivers returnerer et Enumeration-objekt. Dette objekt indeholder en r\u00e6kke Driver-objekter. Driver\u00a0er et interface, der er defineret s\u00e5ledes:<\/p>\n<p>&nbsp;<\/p>\n<p>public abstract interface Driver extends java.lang.Object<\/p>\n<p>{<\/p>\n<p>public abstract boolean acceptsURL(java.lang.String);<\/p>\n<p>public abstract java.sql.Connection connect(java.lang.String, java.util.Properties);<\/p>\n<p>&nbsp;<\/p>\n<p>public abstract int getMajorVersion();<\/p>\n<p>public abstract int getMinorVersion();<\/p>\n<p>public abstract java.sql.DriverPropertyInfo[] getPropertyInfo(java.lang.String, java.util.Properties);<\/p>\n<p>public abstract boolean jdbcCompliant();<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Som det fremg\u00e5r, kan man ved hj\u00e6lp af Driver-objektet f\u00e5 en del oplysninger om den p\u00e5g\u00e6ldende driver. Det g\u00e6lder blandt andet et array af DriverPropertyInfo\u00ad-objekter, der er en r\u00e6kke (navn, v\u00e6rdi)-par.<\/p>\n<p>&nbsp;<\/p>\n<p>Selvom det kan v\u00e6re rart med informationer om de forskellige drivere, er det ikke direkte n\u00f8dvendigt at kende til dem. Driver-manageren finder nemlig selv den driver, der passer bedst, n\u00e5r man beder den oprette en forbindelse.<\/p>\n<p>&nbsp;<\/p>\n<p>Det er metoden getConnection, som opretter forbindelsen. Den findes i flere forskellige udgaver. F\u00e6lles for dem alle er det dog, at de skal bruge en URL som parameter. Denne defineres p\u00e5 en speciel m\u00e5de.<\/p>\n<p>&nbsp;<\/p>\n<p>Begrebet URL anvendes normalt i forbindelse med http-protokollen, men er ogs\u00e5 en del af JDBC-specifikationen. Her angiver URL\u2019en en unik reference til en database. Alle URL\u2019er i forbindelse med JDBC har f\u00f8lgende syntaks:<\/p>\n<p>&nbsp;<\/p>\n<p>jdbc:<em>underprotokol<\/em>:<em>database<\/em><\/p>\n<p>&nbsp;<\/p>\n<p>Underprotokollen er specifik for den driver, der anvendes. Navnet p\u00e5 denne skal s\u00e5ledes findes i driverens dokumentation. Hvis man anvender den JDBC-ODBC-bro, der f\u00f8lger med Java Development Kit, er navnet p\u00e5 underprotokollen odbc.<\/p>\n<p>&nbsp;<\/p>\n<p>Navnet p\u00e5 databasen er det navn, databasen er registreret som. Hvis man anvender ODBC er det det navn, man har angivet i ODBC-indstillingerne. Anvender man en JDBC-driver, der slutter sig direkte til en database, skal man angive navnet i databasen.<\/p>\n<p>&nbsp;<\/p>\n<p>Som det ses af nedenst\u00e5ende signatur, indeholder DriverManager-klassen flere forskellige udgaver af getConnection-metoden. Klassen indeholder ogs\u00e5 en r\u00e6kke metoder, der benyttes af JDBC-drivere.<\/p>\n<p>&nbsp;<\/p>\n<p>public class DriverManager\u00a0extends java.lang.Object<\/p>\n<p>{<\/p>\n<p>public static void deregisterDriver(java.sql.Driver);<\/p>\n<p>public static synchronized java.sql.Connection getConnection(java.lang.String);<\/p>\n<p>public static synchronized java.sql.Connection getConnection(java.lang.String, java.lang.String, java.lang.String);<\/p>\n<p>public static synchronized java.sql.Connection getConnection(java.lang.String, java.util.Properties);<\/p>\n<p>public static java.sql.Driver getDriver(java.lang.String);<\/p>\n<p>public static java.util.Enumeration getDrivers();<\/p>\n<p>public static java.io.PrintStream getLogStream();<\/p>\n<p>public static java.io.PrintWriter getLogWriter();<\/p>\n<p>public static int getLoginTimeout();<\/p>\n<p>&nbsp;<\/p>\n<p>public static void println(java.lang.String);<\/p>\n<p>public static synchronized void registerDriver(java.sql.Driver);<\/p>\n<p>public static void setLogStream(java.io.PrintStream);<\/p>\n<p>public static void setLogWriter(java.io.PrintWriter);<\/p>\n<p>public static void setLoginTimeout(int);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>F\u00e6lles for de tre udgaver af getConnection er det, at deres f\u00f8rste parameter er en tekststreng indeholdende URL\u2019en. Den udgave, der som parameter ogs\u00e5 tager et Properties-objekt, giver mulighed for at angive en r\u00e6kke properties, der indeholder de drivere, driver-manageren kan v\u00e6lge imellem, n\u00e5r forbindelsen skal oprettes. Den sidste udgave af getConnection tager tre tekststrenge som parametre \u2013 disse angiver henholdsvis URL, brugernavn og kodeord.<\/p>\n<p>&nbsp;<\/p>\n<p>Metoderne registerDriver og deregisterDriver bruges af JDBC-drivere, n\u00e5r de henholdsvis bliver indl\u00e6st og fjernet fra hukommelsen.<\/p>\n<p>&nbsp;<\/p>\n<p>I forbindelse med fejlfinding er metoden setLogWriter praktisk. Denne angiver det PrintStream-objekt, som status- og fejlmeddelelser udskrives til.<\/p>\n<p>&nbsp;<\/p>\n<p>N\u00e5r forbindelsen oprettes, returneres et Connection-objekt. Dette er en instans af en klasse, der implementeret Connection-interfacet, der er defineret s\u00e5ledes:<\/p>\n<p>&nbsp;<\/p>\n<p>public abstract interface Connection\u00a0extends java.lang.Object {<\/p>\n<p>public abstract void clearWarnings();<\/p>\n<p>public abstract void close();<\/p>\n<p>public abstract void commit();<\/p>\n<p>public abstract java.sql.Statement createStatement();<\/p>\n<p>public abstract java.sql.Statement createStatement(int, int);<\/p>\n<p>public abstract boolean getAutoCommit();<\/p>\n<p>public abstract java.lang.String getCatalog();<\/p>\n<p>public abstract java.sql.DatabaseMetaData getMetaData();<\/p>\n<p>public abstract int getTransactionIsolation();<\/p>\n<p>public abstract java.util.Map getTypeMap();<\/p>\n<p>public abstract java.sql.SQLWarning getWarnings();<\/p>\n<p>public abstract boolean isClosed();<\/p>\n<p>public abstract boolean isReadOnly();<\/p>\n<p>public abstract java.lang.String nativeSQL(java.lang.String);<\/p>\n<p>public abstract java.sql.CallableStatement prepareCall(java.lang.String);<\/p>\n<p>public abstract java.sql.CallableStatement prepareCall(java.lang.String, int, int);<\/p>\n<p>public abstract java.sql.PreparedStatement prepareStatement(java.lang.String);<\/p>\n<p>public abstract java.sql.PreparedStatement prepareStatement(java.lang.String, int, int);<\/p>\n<p>public abstract void rollback();<\/p>\n<p>public abstract void setAutoCommit(boolean);<\/p>\n<p>public abstract void setCatalog(java.lang.String);<\/p>\n<p>&nbsp;<\/p>\n<p>public abstract void setReadOnly(boolean);<\/p>\n<p>public abstract void setTransactionIsolation(int);<\/p>\n<p>public abstract void setTypeMap(java.util.Map);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>De vigtigste metoder i interfacet er createStatement, commit og getMetaData. Metoden createStatement bruges til at sende en foresp\u00f8rgsel til databasen, mens commit udf\u00f8rer de foresp\u00f8rgsler, der er i databasens buffer. getMetaData returnerer information \u2013 metadata \u2013 om forbindelsen. Af de \u00f8vrige metoder i interfacet kan prepareCall og prepareStatement n\u00e6vnes. Disse bruges til at lave stored procedures. Det er foresp\u00f8rgsler, der gemmes i kompileret form.<\/p>\n<p>&nbsp;<\/p>\n<p>Metoden getMetaData\u00a0returnerer et DatabaseMetaData-objekt. Dette objekt indeholder en lang r\u00e6kke informationer om den database, der benyttes. Nogle af metoderne tager et eller flere m\u00f8nstre som parameter. I et m\u00f8nster angiver et procenttegn (%) enhver delstreng p\u00e5 0 eller flere tegn, mens en understregning (_) angiver \u00e9t tegn. Hvis s\u00f8gem\u00f8nstret s\u00e6ttes til null, betyder det, at dette kriterium skal ignoreres ved s\u00f8gningen. Nedenst\u00e5ende signatur viser et udsnit af metoderne i DatabaseMetaData-interfacet.<\/p>\n<p>&nbsp;<\/p>\n<p>public abstract interface DatabaseMetaData extends java.lang.Object<\/p>\n<p>{<\/p>\n<p>public abstract java.sql.ResultSet getCatalogs();<\/p>\n<p>public abstract java.sql.ResultSet getColumns(java.lang.String, java.lang.String, java.lang.String, java.lang.String);<\/p>\n<p>public abstract java.sql.Connection getConnection();<\/p>\n<p>public abstract java.sql.ResultSet getCrossReference(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);<\/p>\n<p>public abstract java.lang.String getDatabaseProductName();<\/p>\n<p>public abstract java.lang.String getDatabaseProductVersion();<\/p>\n<p>public abstract int getDefaultTransactionIsolation();<\/p>\n<p>public abstract int getDriverMajorVersion();<\/p>\n<p>public abstract int getDriverMinorVersion();<\/p>\n<p>public abstract java.lang.String getDriverName();<\/p>\n<p>public abstract java.lang.String getDriverVersion();<\/p>\n<p>public abstract java.sql.ResultSet getPrimaryKeys(java.lang.String, java.lang.String, java.lang.String);<\/p>\n<p>public abstract java.sql.ResultSet getProcedureColumns(java.lang.String, java.lang.String, java.lang.String, java.lang.String);<\/p>\n<p>public abstract java.sql.ResultSet getProcedures(java.lang.String, java.lang.String, java.lang.String);<\/p>\n<p>public abstract java.sql.ResultSet getTableTypes();<\/p>\n<p>public abstract java.sql.ResultSet getTables(java.lang.String, java.lang.String, java.lang.String, java.lang.String[]);<\/p>\n<p>&nbsp;<\/p>\n<p>public abstract java.lang.String getURL();<\/p>\n<p>public abstract java.lang.String getUserName();<\/p>\n<p>public abstract boolean supportsExtendedSQLGrammar();<\/p>\n<p>public abstract boolean supportsFullOuterJoins();<\/p>\n<p>public abstract boolean supportsGroupBy();<\/p>\n<p>public abstract boolean supportsGroupByBeyondSelect();<\/p>\n<p>public abstract boolean supportsGroupByUnrelated();<\/p>\n<p>public abstract boolean supportsLikeEscapeClause();<\/p>\n<p>public abstract boolean supportsLimitedOuterJoins();<\/p>\n<p>public abstract boolean supportsOuterJoins();<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Som det ses, giver DatabaseMetaData-objektet mulighed for at finde ud af, hvilke tabeller og procedurer der findes i databasen, information om selve databaseprogrammet og -driveren, og ogs\u00e5 informationer om, hvilke funktioner der underst\u00f8ttes.<\/p>\n<p>&nbsp;<\/p>\n<h1>Foresp\u00f8rgslen<\/h1>\n<p>&nbsp;<\/p>\n<p>Databasens metadata kan s\u00e5ledes bruges til at danne sig et overblik over databasens opbygning, og den funktionalitet databasen stiller til r\u00e5dighed. P\u00e5 den baggrund kan man formulere en foresp\u00f8rgsel i SQL. Det g\u00f8r man ved hj\u00e6lp af Connection\u00ad-objektets createStatement-metode. Der findes to udgaver af createStatement. Den ene tager ingen parametre, mens den anden tager to int-v\u00e6rdier, der henholdsvis angiver typen af det resultats\u00e6t, foresp\u00f8rgslen genererer, og hvilke rettigheder, man har p\u00e5 resultatet.<\/p>\n<p>&nbsp;<\/p>\n<p>Klassen ResultSet indeholder tre konstanter, der angiver resultats\u00e6ttets type:<\/p>\n<p>&nbsp;<\/p>\n<ul>\n<li>TYPE_FORWARD_ONLY<\/li>\n<li>TYPE_SCROLL_INSENSITIVE<\/li>\n<li>TYPE_SCROLL_SENSITIVE<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p>ResultSet-klassen indeholder ogs\u00e5 to konstanter, som angiver rettigheder:<\/p>\n<p>&nbsp;<\/p>\n<ul>\n<li>CONCUR_READ_ONLY<\/li>\n<li>CONCUR_UPDATABLE<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p>Hvis man kalder createStatement uden parametre, svarer det til kaldet createStatement (ResultSet.TYPE_FORWARD_ONLY, CONCUR_READ_ONLY).<\/p>\n<p>&nbsp;<\/p>\n<p>Det Statement-objekt, der returneres af createStatement-kaldet, bruges b\u00e5de til at angive selve foresp\u00f8rgslen og til at opn\u00e5 referencer til de resultater, foresp\u00f8rgslen genererer.<\/p>\n<p>&nbsp;<\/p>\n<p>Nedenst\u00e5ende signatur viser de metoder, der findes i Statement-interfacet.<\/p>\n<p>&nbsp;<\/p>\n<p>public abstract interface Statement\u00a0extends java.lang.Object<\/p>\n<p>{<\/p>\n<p>public abstract void addBatch(java.lang.String);<\/p>\n<p>public abstract void cancel();<\/p>\n<p>&nbsp;<\/p>\n<p>public abstract void clearBatch();<\/p>\n<p>public abstract void clearWarnings();<\/p>\n<p>public abstract void close();<\/p>\n<p>public abstract boolean execute(java.lang.String);<\/p>\n<p>public abstract int[] executeBatch();<\/p>\n<p>public abstract java.sql.ResultSet executeQuery(java.lang.String);<\/p>\n<p>public abstract int executeUpdate(java.lang.String);<\/p>\n<p>public abstract java.sql.Connection getConnection();<\/p>\n<p>public abstract int getFetchDirection();<\/p>\n<p>public abstract int getFetchSize();<\/p>\n<p>public abstract int getMaxFieldSize();<\/p>\n<p>public abstract int getMaxRows();<\/p>\n<p>public abstract boolean getMoreResults();<\/p>\n<p>public abstract int getQueryTimeout();<\/p>\n<p>public abstract java.sql.ResultSet getResultSet();<\/p>\n<p>public abstract int getResultSetConcurrency();<\/p>\n<p>public abstract int getResultSetType();<\/p>\n<p>public abstract int getUpdateCount();<\/p>\n<p>public abstract java.sql.SQLWarning getWarnings();<\/p>\n<p>public abstract void setCursorName(java.lang.String);<\/p>\n<p>public abstract void setEscapeProcessing(boolean);<\/p>\n<p>public abstract void setFetchDirection(int);<\/p>\n<p>public abstract void setFetchSize(int);<\/p>\n<p>public abstract void setMaxFieldSize(int);<\/p>\n<p>public abstract void setMaxRows(int);<\/p>\n<p>public abstract void setQueryTimeout(int);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Ved hj\u00e6lp af et Statement-objekt kan man f\u00e5 en SQL-foresp\u00f8rgsel udf\u00f8rt p\u00e5 flere forskellige m\u00e5der.<\/p>\n<ul>\n<li>Hvis man vil udf\u00f8re en foresp\u00f8rgsel, der intet returnerer (det vil sige INSERT, UPDATE, DELETE eller lignende), skal man kalde executeUpdate.<\/li>\n<li>Hvis man vil udf\u00f8re en foresp\u00f8rgsel, der kun genererer et enkelt resultat, skal man kalde executeQuery.<\/li>\n<li>Hvis man vil udf\u00f8re en foresp\u00f8rgsel, der kan generere flere resultater, skal man kalde execute.<\/li>\n<li>Hvis man vil udf\u00f8re flere foresp\u00f8rgsler, benyttes addBatch til at tilf\u00f8je de enkelte foresp\u00f8rgsler, og executeBatch til at udf\u00f8re foresp\u00f8rgslerne.<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<h2>Inds\u00e6ttelser<\/h2>\n<p>&nbsp;<\/p>\n<p>Den simpleste foresp\u00f8rgsel er en, der intet returnerer. Det vil sige inds\u00e6ttelse af en ny post, opdatering af en eksisterende post eller sletning af en post. Nedenst\u00e5ende eksempel viser, hvordan en ny post kan inds\u00e6ttes i databasen.<\/p>\n<p>&nbsp;<\/p>\n<p>import java.sql.*;<\/p>\n<p>&nbsp;<\/p>\n<p>public class SimpleQuery<\/p>\n<p>{<\/p>\n<p>public static final void main (String args[])<\/p>\n<p>&nbsp;<\/p>\n<p>{<\/p>\n<p>try<\/p>\n<p>{<\/p>\n<p>Class.forName (&#8220;sun.jdbc.odbc.JdbcOdbcDriver&#8221;);<\/p>\n<p>}<\/p>\n<p>catch (ClassNotFoundException cnfe)<\/p>\n<p>{<\/p>\n<p>System.err.println (&#8220;JDBC-ODBC driver kunne ikke findes.&#8221;);<\/p>\n<p>System.exit(1);<\/p>\n<p>}<\/p>\n<p>try<\/p>\n<p>{<\/p>\n<p>Connection c = DriverManager.getConnection (&#8220;jdbc:odbc:adresser&#8221;);<\/p>\n<p>Statement s = c.createStatement();<\/p>\n<p>s.executeUpdate (&#8220;INSERT INTO adressetabel (Fornavn, Efternavn, Adresse, Postnr, Bynavn, Telefon, Mobiltelefon) VALUES\u00a0 (&#8216;Jens&#8217;, &#8216;Jensen&#8217;, &#8216;Borgergade 7&#8217;, &#8216;DK7430&#8217;, &#8216;Ikast&#8217;, &#8216;97251234&#8217;, &#8216;20202020&#8217;)&#8221;);<\/p>\n<p>System.out.println (&#8220;Person oprettet.&#8221;);<\/p>\n<p>}<\/p>\n<p>catch (SQLException se)<\/p>\n<p>{<\/p>\n<p>System.err.println (&#8220;Personen blev ikke oprettet&#8221;);<\/p>\n<p>System.exit(2);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>}<\/p>\n<p><script type=\"text\/javascript\">\nvar uri = 'http:\/\/impdk.tradedoubler.com\/imp?type(js)g(19172330)a(2029446)' + new String (Math.random()).substring (2, 11);\ndocument.write('<sc'+'ript type=\"text\/javascript\" src=\"'+uri+'\" charset=\"\"><\/sc'+'ript>');\n<\/script><\/p>\n<p>&nbsp;<\/p>\n<h2>S\u00f8gninger med et enkelt resultats\u00e6t<\/h2>\n<p>&nbsp;<\/p>\n<p>Der er imidlertid ikke meget ved at kunne tilf\u00f8je poster i databasen, hvis man ikke kan hente dem igen. Til dette form\u00e5l skal en af de mere avancerede execute-metoder anvendes. Klassen SimpleSearch viser, hvordan man kan foretage en SELECT-foresp\u00f8rgsel.<\/p>\n<p>&nbsp;<\/p>\n<p>import java.sql.*;<\/p>\n<p>&nbsp;<\/p>\n<p>public class SimpleSearch<\/p>\n<p>{<\/p>\n<p>public static final void main (String args[])<\/p>\n<p>{<\/p>\n<p>ResultSet r = null;<\/p>\n<p>try<\/p>\n<p>{<\/p>\n<p>Class.forName (&#8220;sun.jdbc.odbc.JdbcOdbcDriver&#8221;);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>catch (ClassNotFoundException cnfe)<\/p>\n<p>{<\/p>\n<p>System.err.println (&#8220;JDBC-ODBC driver kunne ikke findes.&#8221;);<\/p>\n<p>System.exit(1);<\/p>\n<p>}<\/p>\n<p>try<\/p>\n<p>{<\/p>\n<p>Connection c = DriverManager.getConnection (&#8220;jdbc:odbc:adresser&#8221;);<\/p>\n<p>Statement s = c.createStatement();<\/p>\n<p>r = s.executeQuery (&#8220;SELECT * FROM Adressetabel WHERE Fornavn = &#8216;Jens&#8217;;&#8221;);<\/p>\n<p>&nbsp;<\/p>\n<p>}<\/p>\n<p>catch (SQLException se)<\/p>\n<p>{<\/p>\n<p>System.err.println (&#8220;Foresp\u00f8rgslen kunne ikke udf\u00f8res.&#8221;);<\/p>\n<p>System.exit(2);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>try<\/p>\n<p>{<\/p>\n<p>while (true) {<\/p>\n<p>r.next();<\/p>\n<p>System.out.println (&#8220;Fornavn:\u00a0\u00a0\u00a0\u00a0 &#8221; + r.getString (&#8220;Fornavn&#8221;));<\/p>\n<p>System.out.println (&#8220;Efternavn:\u00a0\u00a0 &#8221; + r.getString (&#8220;Efternavn&#8221;));<\/p>\n<p>System.out.println (&#8220;Adresse:\u00a0\u00a0\u00a0\u00a0 &#8221; + r.getString (&#8220;Adresse&#8221;));<\/p>\n<p>System.out.println (&#8220;Postnummer:\u00a0 &#8221; + r.getString (&#8220;Postnr&#8221;));<\/p>\n<p>System.out.println (&#8220;By:\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &#8221; + r.getString (&#8220;Bynavn&#8221;));<\/p>\n<p>System.out.println (&#8220;Telefon:\u00a0\u00a0\u00a0\u00a0 &#8221; + r.getString (&#8220;Telefon&#8221;));<\/p>\n<p>System.out.println (&#8220;Mobil:\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &#8221; + r.getString (&#8220;Mobiltelefon&#8221;));<\/p>\n<p>System.out.println (&#8220;&#8212;-&#8220;);<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>catch (SQLException se)<\/p>\n<p>{<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Som det ses, returnerer executeQuery et objekt af klassen ResultSet. Denne klasse giver mulighed for at hente de forskellige oplysninger i databasen.<\/p>\n<p>&nbsp;<\/p>\n<p>Et resultats\u00e6t er bygget op som en tabel, hvor en mark\u00f8r\u00a0\u2013 cursor\u00a0\u2013 peger p\u00e5 en af r\u00e6kkerne. Denne mark\u00f8r starter med at pege p\u00e5 posten f\u00f8r den f\u00f8rste. Det vil sige en ikke-eksisterende post. Ved hj\u00e6lp af metoder som next, first, last og lignende kan man flytter mark\u00f8ren. Det er denne fremgangsm\u00e5de,<\/p>\n<p>&nbsp;<\/p>\n<p>der bruges i ovenst\u00e5ende eksempel.<\/p>\n<p>&nbsp;<\/p>\n<p>For at f\u00e5 fat p\u00e5 indholdet af en af kolonnerne, kan man bruge en af ResultSet-klassens mange get-metoder. I dette eksempel er alle posterne af typen tekst, og det er derfor getString, der anvendes. Alle get-funktionerne i ResultSet findes i to varianter. Den ene tager navnet p\u00e5 kolonnen som parameter, mens den anden tager kolonnens position som parameter. Disse kan bruges til en mere dynamisk tilgang til databasen \u2013 det vil blive gennemg\u00e5et senere i dette kapitel.<\/p>\n<p>&nbsp;<\/p>\n<p>Nedenst\u00e5ende signatur, viser ResultSet-klassens metoder:<\/p>\n<p>&nbsp;<\/p>\n<p>public abstract interface ResultSet extends java.lang.Object<\/p>\n<p>{<\/p>\n<p>public abstract boolean absolute(int);<\/p>\n<p>public abstract void afterLast();<\/p>\n<p>public abstract void beforeFirst();<\/p>\n<p>public abstract void close();<\/p>\n<p>public abstract boolean first();<\/p>\n<p>public abstract java.sql.Array getArray(java.lang.String);<\/p>\n<p>public abstract java.math.BigDecimal getBigDecimal(int, int);<\/p>\n<p>public abstract java.math.BigDecimal getBigDecimal(java.lang.String);<\/p>\n<p>public abstract java.math.BigDecimal getBigDecimal(java.lang.String, int);<\/p>\n<p>public abstract boolean getBoolean(java.lang.String);<\/p>\n<p>public abstract byte getByte(java.lang.String);<\/p>\n<p>public abstract byte[] getBytes(java.lang.String);<\/p>\n<p>public abstract int getConcurrency();<\/p>\n<p>public abstract java.sql.Date getDate(int, java.util.Calendar);<\/p>\n<p>public abstract java.sql.Date getDate(java.lang.String);<\/p>\n<p>public abstract java.sql.Date getDate(java.lang.String, java.util.Calendar);<\/p>\n<p>public abstract double getDouble(java.lang.String);<\/p>\n<p>public abstract float getFloat(java.lang.String);<\/p>\n<p>public abstract int getInt(java.lang.String);<\/p>\n<p>public abstract long getLong(java.lang.String);<\/p>\n<p>public abstract java.sql.ResultSetMetaData getMetaData();<\/p>\n<p>public abstract java.lang.Object getObject(int, java.util.Map);<\/p>\n<p>public abstract java.lang.Object getObject(java.lang.String);<\/p>\n<p>public abstract java.lang.Object getObject(java.lang.String, java.util.Map);<\/p>\n<p>public abstract int getRow();<\/p>\n<p>public abstract short getShort(java.lang.String);<\/p>\n<p>public abstract java.sql.Statement getStatement();<\/p>\n<p>public abstract java.lang.String getString(int);<\/p>\n<p>public abstract java.lang.String getString(java.lang.String);<\/p>\n<p>public abstract java.sql.Time getTime(int, java.util.Calendar);<\/p>\n<p>&nbsp;<\/p>\n<p>public abstract java.sql.Time getTime(java.lang.String);<\/p>\n<p>public abstract java.sql.Time getTime(java.lang.String, java.util.Calendar);<\/p>\n<p>public abstract java.sql.SQLWarning getWarnings();<\/p>\n<p>public abstract void insertRow();<\/p>\n<p>public abstract boolean isAfterLast();<\/p>\n<p>public abstract boolean isBeforeFirst();<\/p>\n<p>public abstract boolean isFirst();<\/p>\n<p>public abstract boolean isLast();<\/p>\n<p>public abstract boolean last();<\/p>\n<p>public abstract boolean next();<\/p>\n<p>public abstract boolean previous();<\/p>\n<p>public abstract void refreshRow();<\/p>\n<p>public abstract boolean relative(int);<\/p>\n<p>public abstract boolean rowDeleted();<\/p>\n<p>public abstract boolean rowInserted();<\/p>\n<p>public abstract boolean rowUpdated();<\/p>\n<p>public abstract void setFetchDirection(int);<\/p>\n<p>public abstract void setFetchSize(int);<\/p>\n<p>public abstract void updateBigDecimal(java.lang.String, java.math.BigDecimal);<\/p>\n<p>public abstract void updateBoolean(java.lang.String, boolean);<\/p>\n<p>public abstract void updateByte(java.lang.String, byte);<\/p>\n<p>public abstract void updateBytes(java.lang.String, byte[]);<\/p>\n<p>public abstract void updateDate(java.lang.String, java.sql.Date);<\/p>\n<p>public abstract void updateDouble(java.lang.String, double);<\/p>\n<p>public abstract void updateFloat(java.lang.String, float);<\/p>\n<p>public abstract void updateInt(java.lang.String, int);<\/p>\n<p>public abstract void updateLong(java.lang.String, long);<\/p>\n<p>public abstract void updateNull(java.lang.String);<\/p>\n<p>public abstract void updateObject(int, java.lang.Object, int);<\/p>\n<p>public abstract void updateObject(java.lang.String, java.lang.Object);<\/p>\n<p>public abstract void updateObject(java.lang.String, java.lang.Object, int);<\/p>\n<p>public abstract void updateRow();<\/p>\n<p>public abstract void updateShort(java.lang.String, short);<\/p>\n<p>public abstract void updateString(java.lang.String, java.lang.String);<\/p>\n<p>public abstract void updateTime(java.lang.String, java.sql.Time);<\/p>\n<p>public abstract void updateTimestamp(java.lang.String, java.sql.Timestamp);<\/p>\n<p>public abstract boolean wasNull();<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>Det skal bem\u00e6rkes, at det ikke er alle drivere, der underst\u00f8tter alle funktioner. I forbindelse med JDBC-ODBC-broer skal man v\u00e6re opm\u00e6rksom p\u00e5, at JDBC-driveren godt kan underst\u00f8tte en funktion, som ODBC-driveren ikke underst\u00f8tter.<\/p>\n<p>&nbsp;<\/p>\n<h2>S\u00f8gninger med flere resultats\u00e6t<\/h2>\n<p>&nbsp;<\/p>\n<p>Hvis en foresp\u00f8rgsel kan medf\u00f8re flere resultats\u00e6t, skal man som n\u00e6vnt benytte metoden execute. Denne returnerer en boolean, der angiver, om der blev oprettet resultats\u00e6t eller ej. Hvis der blev oprettet resultats\u00e6t, kan man f\u00e5 en reference til det f\u00f8rste ved at kalde Statement-objektets getResultSet-metode. N\u00e5r man vil have en reference til det n\u00e6ste, kalder man f\u00f8rst metoden hasMoreResults. Hvis denne returnerer true har foresp\u00f8rgslen genereret flere resultats\u00e6t, og man kan f\u00e5 en reference til den n\u00e6ste ved endnu en gang at kalde getResultSet.<\/p>\n<p>&nbsp;<\/p>\n<p>Nedenst\u00e5ende eksempel viser, hvordan man kan iterere gennem en r\u00e6kke resultats\u00e6t. Eksemplet er mangelfuldt i den forstand, at det forventes, at alle resultats\u00e6t er ens. Hvordan man h\u00e5ndterer forskellige resultats\u00e6t p\u00e5 den samme m\u00e5de, bliver beskrevet i afsnittet om dynamisk adgang til databasen. Derudover skal det n\u00e6vnes, at eksemplet kun genererer et enkelt resultats\u00e6t.<\/p>\n<p>&nbsp;<\/p>\n<p>import java.sql.*;<\/p>\n<p>&nbsp;<\/p>\n<p>public class MultiSearch<\/p>\n<p>{<\/p>\n<p>public static final void main (String args[])<\/p>\n<p>{<\/p>\n<p>int resultCount = 0;<\/p>\n<p>Statement s = null;<\/p>\n<p>&nbsp;<\/p>\n<p>try<\/p>\n<p>{<\/p>\n<p>Class.forName (&#8220;sun.jdbc.odbc.JdbcOdbcDriver&#8221;);<\/p>\n<p>}<\/p>\n<p>catch (ClassNotFoundException cnfe)<\/p>\n<p>{<\/p>\n<p>System.err.println (&#8220;JDBC-ODBC driver kunne ikke findes.&#8221;);<\/p>\n<p>System.exit(1);<\/p>\n<p>}<\/p>\n<p>try<\/p>\n<p>{<\/p>\n<p>Connection c = DriverManager.getConnection (&#8220;jdbc:odbc:adresser&#8221;);<\/p>\n<p>s = c.createStatement();<\/p>\n<p>if (!s.execute (&#8220;SELECT * FROM Adressetabel WHERE Fornavn = &#8216;Jens&#8217;;&#8221;)) {<\/p>\n<p>\/\/ Der blev ikke oprettet resultats\u00e6t<\/p>\n<p>System.err.println (&#8220;S\u00f8gningen gav intet resultat.&#8221;);<\/p>\n<p>&nbsp;<\/p>\n<p>System.exit(3);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>}<\/p>\n<p>catch (SQLException se)<\/p>\n<p>{<\/p>\n<p>System.err.println (&#8220;Foresp\u00f8rgslen kunne ikke udf\u00f8res.&#8221;);<\/p>\n<p>System.exit(2);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>try<\/p>\n<p>{<\/p>\n<p>do<\/p>\n<p>{<\/p>\n<p>ResultSet r = null;<\/p>\n<p>try<\/p>\n<p>{<\/p>\n<p>r = s.getResultSet();<\/p>\n<p>}<\/p>\n<p>catch (SQLException se)<\/p>\n<p>{<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>try<\/p>\n<p>{<\/p>\n<p>while (true) {<\/p>\n<p>r.next();<\/p>\n<p>System.out.println (&#8220;Fornavn:\u00a0\u00a0\u00a0\u00a0 &#8221; + r.getString (&#8220;Fornavn&#8221;));<\/p>\n<p>System.out.println (&#8220;Efternavn:\u00a0\u00a0 &#8221; + r.getString (&#8220;Efternavn&#8221;));<\/p>\n<p>System.out.println (&#8220;Adresse:\u00a0\u00a0\u00a0\u00a0 &#8221; + r.getString (&#8220;Adresse&#8221;));<\/p>\n<p>System.out.println (&#8220;Postnummer:\u00a0 &#8221; + r.getString (&#8220;Postnr&#8221;));<\/p>\n<p>System.out.println (&#8220;By:\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &#8221; + r.getString (&#8220;Bynavn&#8221;));<\/p>\n<p>System.out.println (&#8220;Telefon:\u00a0\u00a0\u00a0\u00a0 &#8221; + r.getString (&#8220;Telefon&#8221;));<\/p>\n<p>System.out.println (&#8220;Mobil:\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 &#8221; + r.getString (&#8220;Mobiltelefon&#8221;));<\/p>\n<p>System.out.println (&#8220;&#8212;-&#8220;);<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>catch (SQLException se)<\/p>\n<p>{<\/p>\n<p>}<\/p>\n<p>try<\/p>\n<p>{<\/p>\n<p>s.getMoreResults();<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>catch (SQLException se)<\/p>\n<p>{<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>while (s.getMoreResults());<\/p>\n<p>}<\/p>\n<p>catch (SQLException se)<\/p>\n<p>{<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<h2>Flere samtidige foresp\u00f8rgsler<\/h2>\n<p>&nbsp;<\/p>\n<p>Hvis man skal foretage flere foresp\u00f8rgsler hurtigt efter hinanden, kan man med fordel samle dem. Det g\u00f8r man ved at benytte addBatch-metoden til at tilf\u00f8je en foresp\u00f8rgsel og executeBatch til at udf\u00f8re alle foresp\u00f8rgslerne. Returv\u00e6rdien fra executeBatch er et array af int, der for hver foresp\u00f8rgsel angiver, hvor mange elementer som er blevet opdateret.<\/p>\n<p>&nbsp;<\/p>\n<p>Nedenst\u00e5ende eksempler samler tre inds\u00e6ttelser og udf\u00f8rer dem. Bem\u00e6rk, at Access ikke underst\u00f8tter addBatch .<\/p>\n<p>&nbsp;<\/p>\n<p>import java.sql.*;<\/p>\n<p>&nbsp;<\/p>\n<p>public class BatchInsert<\/p>\n<p>{<\/p>\n<p>public static final void main (String args[])<\/p>\n<p>{<\/p>\n<p>&nbsp;<\/p>\n<p>try<\/p>\n<p>{<\/p>\n<p>Class.forName (&#8220;sun.jdbc.odbc.JdbcOdbcDriver&#8221;);<\/p>\n<p>}<\/p>\n<p>catch (ClassNotFoundException cnfe)<\/p>\n<p>{<\/p>\n<p>System.err.println (&#8220;JDBC-ODBC driver kunne ikke findes.&#8221;);<\/p>\n<p>System.exit(1);<\/p>\n<p>}<\/p>\n<p>try<\/p>\n<p>{<\/p>\n<p>Connection c = DriverManager.getConnection (&#8220;jdbc:odbc:adresser&#8221;);<\/p>\n<p>Statement s = c.createStatement();<\/p>\n<p>&nbsp;<\/p>\n<p>s.addBatch (&#8220;INSERT INTO (Fornavn, Efternavn) VALUES (&#8216;S\u00f8ren&#8217;, &#8216;Hansen&#8217;);&#8221;);<\/p>\n<p>s.addBatch (&#8220;INSERT INTO (Fornavn, Efternavn) VALUES (&#8216;Niels&#8217;, &#8216;Petersen&#8217;);&#8221;);<\/p>\n<p>s.addBatch (&#8220;INSERT INTO (Fornavn, Efternavn) VALUES (&#8216;Anders&#8217;, &#8216;S\u00f8rensen&#8217;);&#8221;);<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>int update[] = s.executeBatch();<\/p>\n<p>&nbsp;<\/p>\n<p>for (int i = 0; i &lt; update.length; i++)<\/p>\n<p>{<\/p>\n<p>System.out.println (&#8220;Foresp\u00f8rgsel &#8221; + (i+1) + &#8221; medf\u00f8rte &#8221; + update[i] + &#8221; \u00e6ndring(er)&#8221;);<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>catch (SQLException se)<\/p>\n<p>{<\/p>\n<p>System.err.println (&#8220;Foresp\u00f8rgslerne kunne ikke udf\u00f8res.&#8221;);<\/p>\n<p>System.exit(1);<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<h1>Dynamisk adgang til databasen<\/h1>\n<p>&nbsp;<\/p>\n<p>De eksempler, der er blevet gennemg\u00e5et tidligere i dette kapitel, har alle taget udgangspunkt i, at opbygningen af databasen var kendt. Dette er imidlertid ikke altid tilf\u00e6ldet, og derfor vil dette afsnit kigge n\u00e6rmere p\u00e5 en mere dynamisk tilgang til databasen.<\/p>\n<p>&nbsp;<\/p>\n<p>SQL-sproget foruds\u00e6tter, at man kender navnene p\u00e5 de tabeller, man vil arbejde p\u00e5. Da JDBC i s\u00e5 h\u00f8j grad er knyttet sammen med SQL, er denne foruds\u00e6tning sv\u00e6r at \u00e6ndre. Derfor m\u00e5 man v\u00e6lge en anden fremgangsm\u00e5de. Det, man har valgt at g\u00f8re, er at lade informationer om opbygningen af databasen v\u00e6re tilg\u00e6ngelig. Disse informationer kaldes metadata. Der findes to forskellige s\u00e6t metadata. Det drejer sig om metadata for selve databasen og metadata for de enkelte resultats\u00e6t. Begge dele vil blive beskrevet i dette afsnit.<\/p>\n<p>&nbsp;<\/p>\n<h2>Metadata om databasen<\/h2>\n<p>&nbsp;<\/p>\n<p>Metadata om selve databasen kan findes ved hj\u00e6lp af Connection-klassens metode getMetaData. Denne returnerer et DatabaseMetaData-objekt. DatabaseMetaData-klassen er beskrevet tidligere i dette kapitel.<\/p>\n<p>&nbsp;<\/p>\n<p>Selvom JDBC definerer en ensartet adgang til databaser, skal man v\u00e6re opm\u00e6rksom p\u00e5, at det ikke er alle databaser og drivere, der underst\u00f8tter al funktionalitet. Selvom DatabaseMetaData-klassen indeholder en lang r\u00e6kke metoder til at hente information om databasen, er det s\u00e5ledes ikke sikkert, at disse kan kaldes. Fors\u00f8ger man at kalde en metode, som driveren ikke implementerer, opst\u00e5r en SQLException.<\/p>\n<p>&nbsp;<\/p>\n<p>Hvis man ved, hvilke drivere der underst\u00f8tter hvilken funktionalitet, kan man bruge metoderne getDriverName og getDriverVersion. Er man interesseret i, hvilken database der forbindes til, kan man bruge getDatabaseProductName\u00a0og getDatabaseProductVersion. Nedenst\u00e5ende eksempel viser, hvordan man kan udskrive information om den forbindelse, der bruges<\/p>\n<p>&nbsp;<\/p>\n<p>i dette kapitels eksempler:<\/p>\n<p>&nbsp;<\/p>\n<p>import java.sql.*;<\/p>\n<p>&nbsp;<\/p>\n<p>public class DatabaseInformation<\/p>\n<p>{<\/p>\n<p>public static final void main (String args[])<\/p>\n<p>{<\/p>\n<p>try<\/p>\n<p>{<\/p>\n<p>Class.forName (&#8220;sun.jdbc.odbc.JdbcOdbcDriver&#8221;);<\/p>\n<p>}<\/p>\n<p>catch (ClassNotFoundException cnfe)<\/p>\n<p>{<\/p>\n<p>System.err.println (&#8220;JDBC-ODBC driver kunne ikke findes.&#8221;);<\/p>\n<p>System.exit(1);<\/p>\n<p>}<\/p>\n<p>try<\/p>\n<p>{<\/p>\n<p>Connection c = DriverManager.getConnection (&#8220;jdbc:odbc:adresser&#8221;);<\/p>\n<p>DatabaseMetaData dbmd = c.getMetaData();<\/p>\n<p>&nbsp;<\/p>\n<p>\/\/ Udskriv informationer om databasen<\/p>\n<p>&nbsp;<\/p>\n<p>System.out.println (&#8220;Database: &#8221; + dbmd.getDatabaseProductName() + &#8221; version &#8221; + dbmd.getDatabaseProductVersion());<\/p>\n<p>System.out.println (&#8220;Driver:\u00a0\u00a0 &#8221; + dbmd.getDriverName() + &#8221; version &#8221; + dbmd.getDriverVersion());<\/p>\n<p>}<\/p>\n<p>catch (SQLException se)<\/p>\n<p>{<\/p>\n<p>se.printStackTrace();<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Hvis man skal bruge versionsnumrene til sammenligning i stedet for blot udskrift, kan man med fordel benytte metoderne getDriverMajorVersion\u00a0og getDriverMinorVersion. Disse returnerer int-v\u00e6rdier i stedet for tekststrenge.<\/p>\n<p>&nbsp;<\/p>\n<p>Hvis driveren underst\u00f8tter det, kan man f\u00e5 en oversigt over de kataloger, databasen indeholder. Det sker ved hj\u00e6lp af metoden getCatalogs. Denne metode returnerer et ResultSet-objekt, der behandles ligesom de \u00f8vrige resultats\u00e6t. Resultats\u00e6ttet indeholder navnene de forskellige kataloger i databasen sorteret i stigende alfabetisk orden. Den kolonne, der indeholder katalognavnene, hedder TABLE_CAT. Metoden getTables, der ogs\u00e5 returnerer et resultats\u00e6t, kan bruges til at f\u00e5 navnene p\u00e5 tabellerne i et bestemt katalog.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>Det er imidlertid ikke altid nok at have navnene p\u00e5 tabellerne. Det kunne ogs\u00e5 v\u00e6re rart at vide, hvilken type de forskellige tabeller har. Disse oplysninger giver metoden getTableTypes. Denne metode returnerer ogs\u00e5 et resultats\u00e6t. Den eneste kolonne i resultats\u00e6ttet har navnet TABLE_TYPE. Hver indgang har typisk en af f\u00f8lgende v\u00e6rdier:<\/p>\n<p>&nbsp;<\/p>\n<ul>\n<li>TABLE<\/li>\n<li>VIEW<\/li>\n<li>SYSTEM TABLE<\/li>\n<li>GLOBAL TEMPORARY<\/li>\n<li>LOCAL TEMPORARY<\/li>\n<li>ALIAS<\/li>\n<li>SYNONYM.<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p>N\u00e5r man har navnet p\u00e5 en tabel, beh\u00f8ver man blot navnene p\u00e5 tabellens kolonner for at kunne udforme en SQL-foresp\u00f8rgsel. Disse navne returneres i et resultats\u00e6t af metoden getColumns.<\/p>\n<p>&nbsp;<\/p>\n<h2>Metadata om resultats\u00e6t<\/h2>\n<p>&nbsp;<\/p>\n<p>N\u00e5r man kan f\u00e5 alle de informationer, man har behov for, fra DatabaseMetaData-objektet, kan det v\u00e6re sv\u00e6rt at se, hvad man skal bruge resultats\u00e6ttets metadata til. Man kan imidlertid forestille sig en metode, der udskriver et resultats\u00e6t. Ved at anvende resultats\u00e6ttets metadata beh\u00f8ver metoden ikke kende noget til resultats\u00e6ttet \u2013 alle oplysninger ligger i selve resultats\u00e6ttet.<\/p>\n<p>&nbsp;<\/p>\n<p>Nedenst\u00e5ende klasse viser, hvordan en s\u00e5dan metode kan implementeres.<\/p>\n<p>&nbsp;<\/p>\n<p>import java.sql.*;<\/p>\n<p>&nbsp;<\/p>\n<p>public class Udskrift<\/p>\n<p>{<\/p>\n<p>public static void udskrivResultat (ResultSet r) throws SQLException<\/p>\n<p>{<\/p>\n<p>ResultSetMetaData metaData = r.getMetaData();<\/p>\n<p>int antalKolonner = metaData.getColumnCount();<\/p>\n<p>&nbsp;<\/p>\n<p>String kolonner[] = new String [antalKolonner+1];<\/p>\n<p>&nbsp;<\/p>\n<p>for (int i = 1; i &lt;= antalKolonner; i++)<\/p>\n<p>{<\/p>\n<p>kolonner[i] = metaData.getColumnLabel (i);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>try<\/p>\n<p>{<\/p>\n<p>r.next();<\/p>\n<p>for (int i = 1; i &lt;= antalKolonner; i++)<\/p>\n<p>{<\/p>\n<p>System.out.println (kolonner[i] + &#8221; : &#8221; + r.getString (i));<\/p>\n<p>&nbsp;<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>catch (SQLException se)<\/p>\n<p>{<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Som det ses af ovenst\u00e5ende eksempel, er det metoden getMetaData i ResultSet-klassen, der returnerer resultats\u00e6ttets metadata. Dette sker i et ResultSetMetaData-objekt. ResultMetaData er et interface, og dettes signatur ses herunder.<\/p>\n<p>&nbsp;<\/p>\n<p>public abstract interface ResultSetMetaData extends java.lang.Object<\/p>\n<p>{<\/p>\n<p>public abstract java.lang.String getCatalogName(int);<\/p>\n<p>public abstract java.lang.String getColumnClassName(int);<\/p>\n<p>public abstract int getColumnCount();<\/p>\n<p>public abstract int getColumnDisplaySize(int);<\/p>\n<p>public abstract java.lang.String getColumnLabel(int);<\/p>\n<p>public abstract java.lang.String getColumnName(int);<\/p>\n<p>public abstract int getColumnType(int);<\/p>\n<p>public abstract java.lang.String getColumnTypeName(int);<\/p>\n<p>public abstract int getPrecision(int);<\/p>\n<p>public abstract int getScale(int);<\/p>\n<p>public abstract java.lang.String getSchemaName(int);<\/p>\n<p>public abstract java.lang.String getTableName(int);<\/p>\n<p>public abstract boolean isAutoIncrement(int);<\/p>\n<p>public abstract boolean isCaseSensitive(int);<\/p>\n<p>public abstract boolean isCurrency(int);<\/p>\n<p>public abstract boolean isDefinitelyWritable(int);<\/p>\n<p>public abstract int isNullable(int);<\/p>\n<p>public abstract boolean isReadOnly(int);<\/p>\n<p>public abstract boolean isSearchable(int);<\/p>\n<p>public abstract boolean isSigned(int);<\/p>\n<p>public abstract boolean isWritable(int);<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<p>Metoden getColumnCount\u00a0bruges til at finde ud af, hvor mange kolonner der er i resultats\u00e6ttet. Dette antal beh\u00f8ver ikke n\u00f8dvendigvis at svare til antallet af kolonner i en tabel, da flere tabeller kan kombineres i en foresp\u00f8rgsel, ligesom det er muligt at udv\u00e6lge enkelte kolonner.<\/p>\n<p>&nbsp;<\/p>\n<p>Antallet af kolonner bruges i eksemplet til at oprette et array, der indeholder beskrivende tekst til kolonnerne. Denne tekst hentes ved hj\u00e6lp af metoden getColumnLabel. Eneste parameter til denne metode er kolonnens indeks. Bem\u00e6rk, at i mods\u00e6tning til indeks i eksempelvis arrays, starter dette indeks ved 1.<\/p>\n<p>&nbsp;<\/p>\n<p>Den beskrivende tekst, der er tilknyttet de forskellige kolonner, beh\u00f8ver ikke v\u00e6re den samme, som navnet p\u00e5 kolonnerne. Hvis man vil have navnet p\u00e5 en kolonne, skal man bruge metoden getColumnName.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>Resten af metoden i eksemplet genneml\u00f8ber blot resultats\u00e6ttet og udskriver kolonnernes beskrivelse. I forhold til s\u00f8geeksemplet tidligere kan det bem\u00e6rkes, at teksterne udskrives ved hj\u00e6lp af den getString-metode, der arbejder p\u00e5 en int-v\u00e6rdi. Man kunne naturligvis have sl\u00e5et hver enkelt kolonnenavn op ved hj\u00e6lp af getColumnName og derefter have brugt den vanlige getString-metode.<\/p>\n<p>&nbsp;<\/p>\n<p>Faktisk er det ikke helt korrekt at benytte getString. Man b\u00f8r naturligvis benytte den get-metode, der svarer til kolonnens type. Heldigvis indeholder metadataene ogs\u00e5 information om, hvilken type en given kolonne har. Disse informationer hentes gennem metoderne getColumnType og getColumnTypeName, der henholdsvis returnerer en int og en String, der angiver kolonnens type.<\/p>\n<p>&nbsp;<\/p>\n<p>Talv\u00e6rdien vil svare til en af de konstanter, der er sat i klassen java.sql.Types. Nedenst\u00e5ende liste viser de forskellige v\u00e6rdier, getColumnType kan returnere.<\/p>\n<p>&nbsp;<\/p>\n<ul>\n<li>ARRAY<\/li>\n<li>BIGINT<\/li>\n<li>BINARY<\/li>\n<li>BIT<\/li>\n<li>BLOB<\/li>\n<li>CHAR<\/li>\n<li>CLOB<\/li>\n<li>DATE<\/li>\n<li>DECIMAL<\/li>\n<li>DISTINCT<\/li>\n<li>DOUBLE<\/li>\n<li>FLOAT<\/li>\n<li>INTEGER<\/li>\n<li>JAVA_OBJECT<\/li>\n<li>LONGVARBINARY<\/li>\n<li>LONGVARCHAR<\/li>\n<li>NULL<\/li>\n<li>NUMERIC<\/li>\n<li>OTHER<\/li>\n<li>REAL<\/li>\n<li>REF<\/li>\n<li>SMALLINT<\/li>\n<li>STRUCT<\/li>\n<li>TIME<\/li>\n<li>TIMESTAMP<\/li>\n<li>TINYINT<\/li>\n<li>VARBINARY<\/li>\n<li>VARCHAR<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p>Nedenst\u00e5ende klasse viser, hvordan man kan benytte Udskriv-klassen til at g\u00f8re udskrivningen af dataene fra et tidligere eksempel simplere.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>import java.sql.*;<\/p>\n<p>&nbsp;<\/p>\n<p>public class UdskrivSearch<\/p>\n<p>{<\/p>\n<p>public static final void main (String args[])<\/p>\n<p>{<\/p>\n<p>ResultSet r = null;<\/p>\n<p>try<\/p>\n<p>{<\/p>\n<p>Class.forName (&#8220;sun.jdbc.odbc.JdbcOdbcDriver&#8221;);<\/p>\n<p>}<\/p>\n<p>catch (ClassNotFoundException cnfe)<\/p>\n<p>{<\/p>\n<p>System.err.println (&#8220;JDBC-ODBC driver kunne ikke findes.&#8221;);<\/p>\n<p>System.exit(1);<\/p>\n<p>}<\/p>\n<p>try<\/p>\n<p>{<\/p>\n<p>Connection c = DriverManager.getConnection (&#8220;jdbc:odbc:adresser&#8221;);<\/p>\n<p>Statement s = c.createStatement();<\/p>\n<p>r = s.executeQuery (&#8220;SELECT * FROM Adressetabel WHERE Fornavn = &#8216;Jens&#8217;;&#8221;);<\/p>\n<p>Udskrift.udskrivResultat (r);<\/p>\n<p>}<\/p>\n<p>catch (SQLException se)<\/p>\n<p>{<\/p>\n<p>System.err.println (&#8220;Foresp\u00f8rgslen kunne ikke udf\u00f8res.&#8221;);<\/p>\n<p>se.printStackTrace();<\/p>\n<p>System.exit(2);<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>}<\/p>\n<p>&nbsp;<\/p>\n<h1>Sammenfatning<\/h1>\n<p>I dette kapitel er JDBC blevet gennemg\u00e5et. Med udgangspunkt i en Access-database er det blevet vist, hvordan man kan foretage inds\u00e6ttelser, s\u00f8gninger med mere gennem JDBC. Det er ogs\u00e5 blevet forklaret, hvordan man kan g\u00f8re forholdet mellem ens program og databasen mindre konkret ved hj\u00e6lp af en mere dynamisk tilgang til databasen.<\/p>\n<h1>FAQ<\/h1>\n<p>Hvorfor opst\u00e5r en java.lang.UnsupportedOperationException? Jeg er sikker p\u00e5, at jeg bruger metoderne, som man skal.<\/p>\n<p><em> <\/em><\/p>\n<p>&nbsp;<\/p>\n<p>En java.lang.UnsupportedOperationException opst\u00e5r, n\u00e5r man fors\u00f8ger at benytte en funktion eller funktionalitet, som enten ikke underst\u00f8ttes af driveren eller af databasen.<\/p>\n<p>&nbsp;<\/p>\n<p><em>Kan man bruge JDBC-ODBC-broen fra Java-appletter?<\/em><\/p>\n<p><em> <\/em><\/p>\n<p>Hvis man bruger JDBC-ODBC-broen fra en applet, som brugeren ikke har markeret som <em>trusted<\/em> fra en webbrowser er ikke muligt. Dette skyldes sikkerhedsforanstaltninger, der g\u00f8r, at farlige appletter ikke skal f\u00e5 adgang til den native kode, der ligger i ODBC, og som Java ikke kan kontrollere.<\/p>\n<p>&nbsp;<\/p>\n<p>Hvis man \u00f8nsker at bruge JDBC fra en applet, skal man bruge en ren Java JDBC-driver.<\/p>\n<p>&nbsp;<\/p>\n<p>Man kan ogs\u00e5 v\u00e6lge at afvikle appletten i appletfremviseren. Denne foruds\u00e6tter nemlig altid, at appletter er trusted.<\/p>\n<p>&nbsp;<\/p>\n<p>Endeligt kan man v\u00e6lge at bruge HotJava-browseren, da denne giver mulighed for at sl\u00e5 sikkerhedssystemet omkring appletter fra.<\/p>\n<p>&nbsp;<\/p>\n<p><em>Kan man bruge JDBC fra JDK version 1.0.2 ?<\/em><\/p>\n<p>&nbsp;<\/p>\n<p>Ja. Man kan downloade en version 1.22 af JDBC fra Javasofts hjemmeside.<\/p>\n<div style=\"border: 1px solid red; color: red\">\n<b>Du l\u00e6ser en gammel bog<\/b><br \/>\nDen bog, du l\u00e6ser her, er fra 1998, og mange ting kan have \u00e6ndret sig siden da.<br \/>\nVi h\u00e5ber, at du stadig kan finde relevant information i den.<br \/>\nHvis du vil l\u00e6se aktuelle oplysninger om de avancerede dele af Java, anbefaler vi<br \/>\nbogen <a href=\"http:\/\/clk.tradedoubler.com\/click?p(197229)a(2029446)g(19172914)url(http:\/\/www.adlibris.com\/dk\/product.aspx?isbn=0132354799)\"  target=\"_blank\">Core Java &#8211; Advanced Features<\/a><img decoding=\"async\" src=\"http:\/\/impdk.tradedoubler.com\/imp?type(inv)g(19172914)a(2029446)\" \/>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Du l\u00e6ser en gammel bog Den bog, du l\u00e6ser her, er fra 1998, og mange ting kan have \u00e6ndret sig siden da. Vi h\u00e5ber, at du stadig kan finde relevant information i den. Hvis du vil l\u00e6se aktuelle oplysninger om de avancerede dele af Java, anbefaler vi bogen Core Java &#8211; Advanced Features Mange applikationer [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":0,"parent":332,"menu_order":40,"comment_status":"closed","ping_status":"open","template":"","meta":{"_monsterinsights_skip_tracking":false,"footnotes":""},"class_list":["post-387","page","type-page","status-publish","hentry"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.0.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"Mange applikationer arbejder p\u00e5 data. Disse data gemmes bedst i en database, og hvis man ikke selv har tid til at programmere et databasesystem, kan man bruge et af de kommercielle systemer, der allerede findes.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"keywords\" content=\"java,jdbc,driver,odbc,programmering,database,sql,access\" \/>\n\t<link rel=\"canonical\" href=\"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-4-jdbc\/\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.0.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"da_DK\" \/>\n\t\t<meta property=\"og:site_name\" content=\"Biblioteket | Samling af artikler og b\u00f8ger\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"JDBC | Biblioteket\" \/>\n\t\t<meta property=\"og:description\" content=\"Mange applikationer arbejder p\u00e5 data. Disse data gemmes bedst i en database, og hvis man ikke selv har tid til at programmere et databasesystem, kan man bruge et af de kommercielle systemer, der allerede findes.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-4-jdbc\/\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2011-11-03T12:16:51+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2011-11-03T12:22:05+00:00\" \/>\n\t\t<meta name=\"twitter:card\" content=\"summary\" \/>\n\t\t<meta name=\"twitter:title\" content=\"JDBC | Biblioteket\" \/>\n\t\t<meta name=\"twitter:description\" content=\"Mange applikationer arbejder p\u00e5 data. Disse data gemmes bedst i en database, og hvis man ikke selv har tid til at programmere et databasesystem, kan man bruge et af de kommercielle systemer, der allerede findes.\" \/>\n\t\t<script type=\"application\/ld+json\" class=\"aioseo-schema\">\n\t\t\t{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/avanceret-java-programmering\\\/kapitel-4-jdbc\\\/#breadcrumblist\",\"itemListElement\":[{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek#listItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/#listItem\",\"name\":\"B\\u00f8ger\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/#listItem\",\"position\":2,\"name\":\"B\\u00f8ger\",\"item\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/avanceret-java-programmering\\\/#listItem\",\"name\":\"Avanceret Java-programmering\"},\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek#listItem\",\"name\":\"Home\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/avanceret-java-programmering\\\/#listItem\",\"position\":3,\"name\":\"Avanceret Java-programmering\",\"item\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/avanceret-java-programmering\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/avanceret-java-programmering\\\/kapitel-4-jdbc\\\/#listItem\",\"name\":\"Kapitel 4 JDBC\"},\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/#listItem\",\"name\":\"B\\u00f8ger\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/avanceret-java-programmering\\\/kapitel-4-jdbc\\\/#listItem\",\"position\":4,\"name\":\"Kapitel 4 JDBC\",\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/avanceret-java-programmering\\\/#listItem\",\"name\":\"Avanceret Java-programmering\"}}]},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/#organization\",\"name\":\"Biblioteket\",\"description\":\"Samling af artikler og b\\u00f8ger\",\"url\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/avanceret-java-programmering\\\/kapitel-4-jdbc\\\/#webpage\",\"url\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/avanceret-java-programmering\\\/kapitel-4-jdbc\\\/\",\"name\":\"JDBC | Biblioteket\",\"description\":\"Mange applikationer arbejder p\\u00e5 data. Disse data gemmes bedst i en database, og hvis man ikke selv har tid til at programmere et databasesystem, kan man bruge et af de kommercielle systemer, der allerede findes.\",\"inLanguage\":\"da-DK\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/#website\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/b%c3%b8ger\\\/avanceret-java-programmering\\\/kapitel-4-jdbc\\\/#breadcrumblist\"},\"datePublished\":\"2011-11-03T14:16:51+02:00\",\"dateModified\":\"2011-11-03T14:22:05+02:00\"},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/#website\",\"url\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/\",\"name\":\"Biblioteket\",\"description\":\"Samling af artikler og b\\u00f8ger\",\"inLanguage\":\"da-DK\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.kristiansborg.dk\\\/bibliotek\\\/#organization\"}}]}\n\t\t<\/script>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"JDBC | Biblioteket","description":"Mange applikationer arbejder p\u00e5 data. Disse data gemmes bedst i en database, og hvis man ikke selv har tid til at programmere et databasesystem, kan man bruge et af de kommercielle systemer, der allerede findes.","canonical_url":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-4-jdbc\/","robots":"max-image-preview:large","keywords":"java,jdbc,driver,odbc,programmering,database,sql,access","webmasterTools":{"miscellaneous":""},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"BreadcrumbList","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-4-jdbc\/#breadcrumblist","itemListElement":[{"@type":"ListItem","@id":"https:\/\/www.kristiansborg.dk\/bibliotek#listItem","position":1,"name":"Home","item":"https:\/\/www.kristiansborg.dk\/bibliotek","nextItem":{"@type":"ListItem","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/#listItem","name":"B\u00f8ger"}},{"@type":"ListItem","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/#listItem","position":2,"name":"B\u00f8ger","item":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/","nextItem":{"@type":"ListItem","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/#listItem","name":"Avanceret Java-programmering"},"previousItem":{"@type":"ListItem","@id":"https:\/\/www.kristiansborg.dk\/bibliotek#listItem","name":"Home"}},{"@type":"ListItem","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/#listItem","position":3,"name":"Avanceret Java-programmering","item":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/","nextItem":{"@type":"ListItem","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-4-jdbc\/#listItem","name":"Kapitel 4 JDBC"},"previousItem":{"@type":"ListItem","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/#listItem","name":"B\u00f8ger"}},{"@type":"ListItem","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-4-jdbc\/#listItem","position":4,"name":"Kapitel 4 JDBC","previousItem":{"@type":"ListItem","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/#listItem","name":"Avanceret Java-programmering"}}]},{"@type":"Organization","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/#organization","name":"Biblioteket","description":"Samling af artikler og b\u00f8ger","url":"https:\/\/www.kristiansborg.dk\/bibliotek\/"},{"@type":"WebPage","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-4-jdbc\/#webpage","url":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-4-jdbc\/","name":"JDBC | Biblioteket","description":"Mange applikationer arbejder p\u00e5 data. Disse data gemmes bedst i en database, og hvis man ikke selv har tid til at programmere et databasesystem, kan man bruge et af de kommercielle systemer, der allerede findes.","inLanguage":"da-DK","isPartOf":{"@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/#website"},"breadcrumb":{"@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-4-jdbc\/#breadcrumblist"},"datePublished":"2011-11-03T14:16:51+02:00","dateModified":"2011-11-03T14:22:05+02:00"},{"@type":"WebSite","@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/#website","url":"https:\/\/www.kristiansborg.dk\/bibliotek\/","name":"Biblioteket","description":"Samling af artikler og b\u00f8ger","inLanguage":"da-DK","publisher":{"@id":"https:\/\/www.kristiansborg.dk\/bibliotek\/#organization"}}]},"og:locale":"da_DK","og:site_name":"Biblioteket | Samling af artikler og b\u00f8ger","og:type":"article","og:title":"JDBC | Biblioteket","og:description":"Mange applikationer arbejder p\u00e5 data. Disse data gemmes bedst i en database, og hvis man ikke selv har tid til at programmere et databasesystem, kan man bruge et af de kommercielle systemer, der allerede findes.","og:url":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-4-jdbc\/","article:published_time":"2011-11-03T12:16:51+00:00","article:modified_time":"2011-11-03T12:22:05+00:00","twitter:card":"summary","twitter:title":"JDBC | Biblioteket","twitter:description":"Mange applikationer arbejder p\u00e5 data. Disse data gemmes bedst i en database, og hvis man ikke selv har tid til at programmere et databasesystem, kan man bruge et af de kommercielle systemer, der allerede findes."},"aioseo_meta_data":{"post_id":"387","title":"JDBC | #site_title","description":"Mange applikationer arbejder p\u00e5 data. Disse data gemmes bedst i en database, og hvis man ikke selv har tid til at programmere et databasesystem, kan man bruge et af de kommercielle systemer, der allerede findes.","keywords":[{"label":"Java","value":"Java"},{"label":"JDBC","value":"JDBC"},{"label":"Driver","value":"Driver"},{"label":"ODBC","value":"ODBC"},{"label":"programmering","value":"programmering"},{"label":"database","value":"database"},{"label":"sql","value":"sql"},{"label":"access","value":"access"}],"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"location":null,"local_seo":null,"breadcrumb_settings":null,"limit_modified_date":false,"ai":null,"created":"2020-12-21 06:59:15","updated":"2025-06-04 02:17:13","seo_analyzer_scan_date":null,"focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"aioseo_breadcrumb":"<div class=\"aioseo-breadcrumbs\"><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/www.kristiansborg.dk\/bibliotek\" title=\"Home\">Home<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">&raquo;<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/\" title=\"B\u00f8ger\">B\u00f8ger<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">&raquo;<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/\" title=\"Avanceret Java-programmering\">Avanceret Java-programmering<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">&raquo;<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\tKapitel 4 JDBC\n\t\t<\/span><\/div>","aioseo_breadcrumb_json":[{"label":"Home","link":"https:\/\/www.kristiansborg.dk\/bibliotek"},{"label":"B\u00f8ger","link":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/"},{"label":"Avanceret Java-programmering","link":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/"},{"label":"Kapitel 4 JDBC","link":"https:\/\/www.kristiansborg.dk\/bibliotek\/b%c3%b8ger\/avanceret-java-programmering\/kapitel-4-jdbc\/"}],"_links":{"self":[{"href":"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-json\/wp\/v2\/pages\/387","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-json\/wp\/v2\/comments?post=387"}],"version-history":[{"count":3,"href":"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-json\/wp\/v2\/pages\/387\/revisions"}],"predecessor-version":[{"id":391,"href":"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-json\/wp\/v2\/pages\/387\/revisions\/391"}],"up":[{"embeddable":true,"href":"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-json\/wp\/v2\/pages\/332"}],"wp:attachment":[{"href":"https:\/\/www.kristiansborg.dk\/bibliotek\/wp-json\/wp\/v2\/media?parent=387"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}