JDBC: Java DataBase connectivity - martenserver.com

advertisement
JDBC: Java DataBase connectivity
1.1
Wat is JDBC?
=> Biedt toegang tot relationele data vanuit Java
=> Via SQL-compatibele relationele gegevensbanken
=> Een API om SQL-statements uit te voeren en de verkregen resultaten te verwerken
1.1.1 Verschillende versies
JDBC 1.0 :
bevat de basisklassen en interfaces om een verbinding te maken met een gegevensbank, een aantal
SQL-opdrachten uit te voeren op die gegevensbank en de resultaten van die opdrachten te
verwerken.
JDBC 2.0:
Bestaat uit 2 delen: een basispakket en een optioneel pakket. Het basispakket omvat JDBC
1.0
en voegt er een aantal nieuwe functionaliteiten aan toe (o.a. results sets, wijzigingen via batch,
programmatorisch aanpaasen v/d gegevensbank, ondersteuning v/d SQL3)
JDBC 3.0:
Is een uitbreiding van 2.0 en bevat alle extensies, kan ook andere gegevenstructuren in tabelvorm
aan.
1.2 JDBC-drivers
Om client-applicaties toegang te geven tot een databankserver voorzien poducten een stel
productafhankelijke API's. De JDBC API biedt een alternatief voor deze productafhankelijke API's,
namelijk een API die voor elke SQL-compatibele relationele gegevensbank gebruikt kan worden.
De opdrachten van de JDBC API moeten nog vertaald worden naar opdrachten in de
productueafhankelijke API, deze implementatie wordt voorzien door de driver. Deze drivers
vertalen de algemene JDBC-opdrachten naar de productafhankelijke.
1.2.1 verschillende types JDBC-drivers
Er bestaan 4 soorten: “JDBC/ODBC”, ”deels Java,deels productafhankelijk”, “JDBC-Net” en “Pure
java”.
JDBC/ODBC:
Open DataBase Connectivityis de Microsoft's algemene API, de ODBC API voorziet een aantal
methodes. Deze methodes worden op zich geimplementeerd door de ODBC-driver. De
JDBC/ODBC-brug zorgt voor de vertaling van JDBC- naar ODBC-opdrachten, die op hun beurt
door de ODBC-laag vertaald worden naar de gegevensbankenopdrachten.
=> inefficïent, niet-performant, functionaliteit beperkt tot die van ODBC-driver
JDBC Samenvatting 1.0 Jelle De Weerdt
Deels Java, deels productafhankelijk:
Deze vertalen de methoden uit de JDBC API naar methoden vd/ productafhankelijke API
=> volledige functionaliteit v/d API
JDBC-Net:
Maken gebruik v/e tussenliggende gegevensbankserver. De JDBC-opdracht v/d Java-applicatie
wordt nu via de JDBC-driver doorgestuurd naar de tussenliggende server, die de aanvraag dan
verder afhandelt.
=>geschikt voor applicatie met verschillende gegevensbanken
Pure Java:
Volledig in java geschreven, hierbij wordt gebruik gemaakt van productafhankelijke
netwerkprotocols
=> meeste efficïente qua performantie, tijd en installatie
1.2.2 Laden v/d driver
Import java.sql.*;
...
private final static String PAR_DRIVER=”org.postgresql.Driver”;
...
try{
Class.forName(PAR_DRIVER);
}
catch(ClassNotFoundException e){
....//driver niet gevonden
}
Constante PAR_DRIVER stelt de volledige klassenaam vd JDBC-driver, elke driver implementeert
java.sql.Driver-interface. De methode forName laadt de driverklasse in de virtuele machine
1.3 Verbindingen met een gegevensbank
Eeenmaal de gepaste JDBC-driver is ingeladen, kan je een verbinding met een gegevensbank
opzetten. Een dergelijke verbinding wordt voorgesteld door een object v/h type Connection
private final static String PAR_JDBC_URL=”jdbc:postgresql:voorbeelden”;
private final static String PAR_LOGIN=”iii4”;
private final static String PAR_PASWOORD=”iii4pwd”;
Try{
Connection conn = DriverManager.getConnection( PAR_JDBC_URL, PAR_LOGIN,
PAR_PASWOORD);
Try{
...//gegevens ophalne,toevoegen,...
}
finally{
conn.close();
}
}
catch (SQLException e){ .....//gegevensbankproblemen }
verbinding aanmaken => getConnection van DriverManager met 3 argumenten: JDBC-URL,
username en passwoord
JDBC Samenvatting 1.0 Jelle De Weerdt
verbinding verbreken => close(van Connection)
een JDBC-URL bestaat uit 3 stukken:
- het protocol: altijd “jdbc”
- het subprotocol: identificeert de gegevensbankproducent: vb “postgresql”
- de subname: identificeert de gebruikte gegevensbank: bijv naam van gegevnsbank, of
server
uitzondering => SQLException
1.4 SQL-opdrachten
Eens er verbinding is, kan je de gegevensbank vanuit Java-programma een aantal SQL-opdrachten
laten uitvoeren. Hiervoor heb je een Statement nodig, dit object stuurt SQL-opdrachten naar de
gegevensbank en haalt de resultaten ervan op. Statement is een interface, een statement object wordt
op volgende wijze aangemaakt en terug afgesloten:
try{
Statement stmt=conn.createstatement();
try{ ...//SQL-opdrachten uitvoeren
finally{
stmt.close();
}
}
catch (SQLException e){
...
}
}
het object conn is v/h type Connection
1.4.1. DDL-opdrachten, insert, delete en update
Niet-zoek opdrachten zijn opdrachten die deel uitmaken v/d Data Definition Language (DDL) en
opdrachten die rijen in de gegevensbanken toevoegen, verwijderen of aanpassen via de INSERT,
DELETE en UPDATE SQL-opdrachten uit de DDL. In beide gevallen wordt de methode
executeUpdate van Statement aangeroepen.
public int executeUpdate(String sqlopdracht) throws SQLException;
1.4.2 Zoekodprachten
1.4.2.1 ResultSet bepalen
Zoekopdracht zijn SELECT-opdrachten die gegevens selecteren uit 1 of meerdere tabellen in de
gegevensbank en hun resultaat teruggeven als een aantal rijen met gegevens in 1 of meerdere
kolommen. Via executeQuery van statement worden deze uitgevoerd. Het resultaat is een object v/h
type ResultSet, je kan dan de inhoud ervan opvragen via:
public ResultSet executeQuery (String sqlOpdracht) throws SQLException;
JDBC Samenvatting 1.0 Jelle De Weerdt
1.4.2.2 Het ResultSet-object overlopen
elke ResultSet-object bevat een wijzer (cursor), deze wijzer staat na het aanmaken van het object
voor de eerste rij. Met deze wijzer wordt het Resultset-object rij na rij overlopen.
Next => cursor 1 rij naar beneden schuiven
ResultSet res= stmt.executeQuery(...);
while(res.next()){
...//haal de gegevens van de huidige rij op
}
1.4.2.3. Data ophalen
Uit de rij waar de cursor naar wijst, kunnen gegevens opgevraagd worden. De interface ResultSet
biedt verschillende getter-methoden om de gegevens op te vragen bijv:
public boolean getBoolean (int columnIndex) throws SQLException;
public boolean getDouble (int columnIndex) throws SQLException;
public boolean getString (int columnIndex) throws SQLException;
...
de methode getXxx geeft de waarde v/d kolom met volgnummer columnIndex terug als een object
of variable v/h tye xxx.
Er bestaan ook methoden waarbij je de gewenste kolom mag aanduiden met behulp van zijn naam
bijv:
public boolean getBoolean (String columnName) throws SQLException;
public boolean getDouble (String columnName) throws SQLException;
public boolean getString (String columnName) throws SQLException;
1.4.2.4 Voorbeeld
Voorbeeldje pg 103
1.4.2.5 Sluiten van een ResultSet-object
=> wordt automatisch afgesloten door het statement -object wanneer dit gesloten wordt of gerestart
1.5 Prepared Statements
PreparedStatement => is een interface afgeleid v/d interface Statement
Tijdens het aanmaken v/e prepared statement wordt reeds een SQL-opdracht meegegeven. Wanneer
de driver dit ondersteunt wordt deze opdracht onmiddelijk naar de gegevensbank doorgestuurd en
daar gecompileerd. Dit zorgt ervoor dat de SQL-opdracht sneller zal worden uitgevoerd.
1.5.1 Aanmaken van een prepared statement
=> prepareStatement v/e Connection-object opgeroepen, het argument is de SQL-opdracht
JDBC Samenvatting 1.0 Jelle De Weerdt
1.5.2. Parameters toekennen
Vooraleer je het aangemaakte prepared statement kan uitvoeren moet je de waarden van de
parameters toekennen. De methoden executeUpdate en executeQuery voeren de opdracht dan uit
1.5.3. Gegevensconversie
=> via PreparedStatement
1.5.4 SQL-injectie
Kan bijv voorkomen als een gebruiker via een webapplicatie parameters kan ingeven die gebruikt
worden in een SQL-opdracht( misbruik).
Voorbeeld pg 107
=> het gebruik van prepared statements voorkomt SQL-injecties
1.6 Callable Statements
Dienen om stored procedures v/e gegevesbanksysteem uit te voeren. Een stored procedure is een
functie of procedure die bewaard wordt in een gegevensbank en die door clientapplicaties kan
opgeroepen worden, ze halen informatie op uit de gegevensbank of manipuleert zijn data.
1.6.1 Aanmaken callable statement
Om een stored procedure te kunnen oproepen moet je zijn naam en eventuele parameters kennen.
Stored procedure zonder parameters uitvoeren:
=> CallableStatement-object aanmaken, met hulp van een Connection-object
=> Deze bevat een oproep van de te gebruiken procedure
=> prepareCall
static final String SELECTEER_BLA_OPDRACHT=”{call SELECTEER_BLA}”;
try{ CallableStatement stmt=conn.prepareCall(SELECTEER_BLA_OPDRACHT); }
- stored procedure is afgeleid van PreparedStatement
- SELECTEER_BLA = escae-syntax (moet tussen accolades)
1.6.2. Invoerparameters
invoerparameters zijn de argumenten van de procedure en zijn ?
Public void setXxx(int indexParameter, xxx waardeParameter) throws SQLException;
1.6.3 Uitvoerparameters
Na het oproepen van de procedure kan dan de warde opgevraagd worden van de bewuste
uitvoerparameter. Zien er ook uit als ? in de escape-syntax. Vooraleer het callable statement
JDBC Samenvatting 1.0 Jelle De Weerdt
uitgevoerd kan worden moet de uitvoerparameter geregistreerd worden met de methode
registerOutParameter
public void registerOutParameter(int parameterIndex, int sqlType) throws SQLException
=> parameterIndex is het volgnummer
=> sqlType staat voor het generieke SQL-type v/d parameter, te vinden in Types in java.sql
=> indien DECIMAL of NUMERIC komt er een 3de parameter bij: int schaal = aantal cijfers na
komma
Na uitvoeringen kunnen de waarden van de uitvoerparameters opgevraagd worden via getters:
public xxx getXxx(int parameterIndex) throws SQLException
vb:
final static String SELECT_BLA_OPDR=”{ ? = call SELECTEER_BLA}”;
CallacleStatement cstmt= conn.prepareCall(SELECTEER_BLA_OPDR);
try{
cstmt registerOutParameter(1,java.sql.Types.INTEGER); //uitvoerparameter
cstmt.setString(2,blaCode);
//invoerparameter
ResultSet rs= cstmt.executeQuery();
...
// bla uit ResultSet halen
int aantalbla=cstmt.getInt(1);
//waarde ophalen uitvoerpar.
}
1.6.4. Invoer- en uitvoerparameters
Sommige zijn beide.
=> de parameter krijgt een waarde wia setter-methode
=> wordt dan geregistreerd met de emthode registerOutParameter
=> na oproepen kan de waarde afgehaald worden
vb:
final static String DOE_BLA_OPDR=”{ call DOE_BLA(?,?)}”;
CallacleStatement cstmt= conn.prepareCall(DOE_BLA_OPDR);
try{
cstmt.setString(1,blaCode);
//invoerparameter
cstmt.setInt(2,blaCodeInt);
//in- uitvoerparameter
cstmt.registerOutParameter(2,jav.sql.Types.INTEGER); //uitvoerpar registreren
cstmt.executeUpdate();
//procedure oproepen
int aantalbla=cstmt.getInt(2);
//waarde ophalen uitvoerpar.
}
1.7 Transacties
Een transactie is een reeks opdrachten die tesamen uitgevoerd moeten worden.
Sommige applicatie evreisen dat er een reeks SQLopdrachten succesvol uitgevoerd worden, indien
1 or meerdere niet lukken moet alles ongedaan worden. Indien alles gelukt is wordt alles permant
uitgevoerd (commit), indien 1 er 1 niet lukt wordt alles ongedaan gemaakt (rollback).
De interface Connection voorziet volgende methoden:
public void setAutoCommit(boolean autoCommit) throws SQLException);
public void commit() throws SQLException;
JDBC Samenvatting 1.0 Jelle De Weerdt
public void rollback() throws SQLException;
=> een Connection-object wordt aangemaakt in de auto-commit
=> voor meerdere opdrachten samen te kunnen uitvoeren moet auto-commit uitgeschakeld worden
via setAutocommit
=> methode rollback maakt alles ongedaan sinds de laatste commit
try{
conn.setAutoCommit(false);
...// vanalles
conn.commit();
}
catch( SQLException e){
conn.rollback();
finally{
conn.setAutoCommit(true);
}
}
=> andere gebruikers v/d gegevensbank zien het resultaat pas als de methode commit is uitgevoerd
=> bij gelijktijdige transacties heeft elke transactie een ander Connection-object nodig
1.8 Programmatorisch aanpassen v/d gegevensbank
=> sinds JDBC2.0 mogelijk gegevens aantepassen in de ResultSet via javamethodes (aanpassen,
toevoegen of verwijderen)
1.8.1 Scrollable ResultSet
=> de cursor verplaatsen in andere richting dan van boven naar beneden, of de cursor naar een
welbepaalde rij te verplaatsen of de positie v/d cursor te bepalen
hoe?
=> extra opties meegeven bij het aanmaken van het Statement-object
=> Connection heeft volgende methode:
public Statement createStatement(int resultSetType, int resultsetConcurrency)
throws SQLException;
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
throws SQLException;
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency)
throws SQLException;
met resultSetType: - TYPE_FORWARD_ONLY (=eentje naar beneden)
- TYPE_SCROLL_INSENSITIVE (=op willekeurige wijze verplaatst worden,
onzichtbaar in ResultSet-object)
- TYPE_SCROLL_SENSITIVE (=op willekeurige wijze verplaats worden,
zichtbaar in Resultset-object)
Of ResultSet-object aanpasbaar is, wordt bepaald door de parameter resultSetConcurrency met
waarden ResultSet.CONCUR_READ_ONLY of ResultSet.CONCUR_UPDATABLE
vb:
Statement stmt = conn.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
ResultSet rs = stmt.executeQuery(SQLZoekopdracht);
JDBC Samenvatting 1.0 Jelle De Weerdt
=> met SQLZoekOpdracht is een string die een SELEC-opdracht in SQL voorstelt.
=> de ResultSet kan van onder naarr boven doorlopen via afterLast en previous
Er zijn nog veel andere methodes zoals:
isLast (=true als cursor naar laatste rij wijst)
getRow (=geeft het rijnummer weer naarwaar cursor verwijst)
1.8.2 Aanmaken v/e aanpasbaar ResultSet-object
vb:
String SQLZoekopdracht=”select id, titel, code from tabel”;
Statement stmt = conn.createStatement( ResulstSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ResultSet uprs= stmt.executeQuery(SQLZoekopdracht);
1.8.3 een rij aanpassen
=> iets aanpassen: via preparedstatement
String PasXAan=”update tabel set x=? where id=?”;
PreparedStatement stmt = conn.prepareStatement(PasXAan);
stmt.setString(1,x);
stmt.setString(2,id);
stmt.executeUpdate();
via JDBC2.0 API:
variabale rijNr= rijnummer v/h aantepassen object
x= nieuwe waarde
uprs= de hierboven aangemaak ResultSet
TITEL= naam v/d kolom
static final String TITEL=”kolom van x”;
...
uprs.absolute(rijNr);
//verplaats de cursor naar de rij in het Resultset-object
uprs.updateString(TITEL,x);
uprs.updateRow();
//voert de veranderingen door in de gegevensbank
De rij waar de cursor naar wijst kan aangepast worden met methodes v/d vorm:
public void updateXxx(String kolomnaam of int kolomnr, xxx waarde) hrows SQLException;
Om alle veranderingen ongedaan te maken: cancelRowUpdates
1.8.4 Een rij toevoegen
=> met preparedStatement
bij start wordt een PreparedStatement-object aangemaakt:
String voegXToe=”insert into tabel values(?,?)”;
PreparedStatement stmt = conn.prepareStatement(voegXToe);
stmt.setString(1,id);
JDBC Samenvatting 1.0 Jelle De Weerdt
stmt.setString(2,titel);
stmt.executeUpdate();
via JDBC2.0:
uprs.moveToInsertRow();
//beweeg de cursor naar de invoegrij
uprs.updateString(ID,id);
//via updateXxx kan je de waarden wijzigen
uprs.updateString(TITEL,titel);
uprs.insertRow();
//voert de wijzigen effetief door op de gegevensbank
met uprs het ResultSet-object uit 1.8.2 en ID en TITEL zijn ergens anders in de applicatie
gedeclareerd en stellen de kolomnamen in de result set voor, er mogen ook kolomnummers gebruikt
worden. Met moveToCurrentRow verplaatsen we de cursor naar de laatste rij voor
moveToInsertRow() aageroepen werd.
1.8.5 Een rij verwijderen
=> verplaats de cursor naar de te verwijderen rij en verwijder dan met deleteRow
uprs.absolute(rijNr);
uprs.deleteRow();
1.8.6 Welke zoekopdrachten?
Er zijn een aantal criteria die normaal gezien voor een aanpasbare result set moeten zorgen:
1. De zoekopdracht verwijst naar 1 tabel
2. De zoekopdracht bevat geen “joins”-of GROUP BY-clausule
3. De zoekopdracht selecteert de primaire sleutel v/d tabel
4. de gebruiker heeft lees- en schijfpermissies op de tabel in de gegevensbank
bij het toevoegen v/e rij meoten volgende waarden vervult zijn:
1. De zoekopdracht selecteert alle kolommen die neit leeg mogen zijn
2. de zoekopdracht selecteert alle kolommen zonder standaardwaarde.
JDBC Samenvatting 1.0 Jelle De Weerdt
Download