Aangezien we aan het leren zijn om data op te slaan, kunen we net zo goed gebruik maken van een daadwerkelijke database. Je hebt geleerd om een database te bevragen met behulpt van SQL. De applicatie die je gebruikt om, in de rol van database ontwerper, queries te uit te voeren heet meestal “de administrator”. (pgAdmin, phpMyAdmin, etc.) Zulke applicaties zijn vaak stand-alone of leven in een browser. De daadwerkelijke database draait in een apart proces, of zelfs op een andere machine.
In plaats van queries runnen vanuit de administrator, leert dit theorie segment je hoe je vanuit een Java applicatie, zulke queries direct naar de server kunnen sturen.
Merk op dat je gebruikelijk mee kunt programmeren. In dit geval gebruik ik een verbinding naar een database die jij misschien niet hebt op jouw systeem. Dus je zult je eigen queries moeten ontwerpen voor jouw database.
Om te communiceren met de daadwerkelijke database server gebruiken we een Connection
. We gaan een verbinding opzetten met een postgres systeem, maar een andere database werkt ongeveer hetzelfde.
Na de installatie kun je de connectie naar postgres zo configureren:
String url = "jdbc:postgresql://localhost:5432/test?user=adm&password=adm&ssl=true";
Connection conn = DriverManager.getConnection(url);
De meeste complexiteit zit in de connectie url:
jdbc:
- We willen verbinden met het JDBC protocol.postgresql
- We zullen verbinden met een postgres database.://
- Lijkt op en web url.localhost
- De naam van de machine waarmee we willen verbinden.:5432
- De standaard Postgres server poort. (Check even of je deze niet hebt aangepast.)/test
- Naam van de database die we willen gebruiken.?
- Specifieke parameters volgen na het vraagteken.user=adm
- Gebruikersnaam&
- Meer parameterspassword=adm@saxion.nl
- Wachtwoord&
- Meer parametersssl=true
- Gebruik en beveiligde verbinding. (Optioneel!)Om te verbinden met een mysql Database op mijn server thuis, zou de url er ongeveer zo uit zien:
String url = "jdbc:mysql://192.168.1.1:3306/energy?user=frederik&password=Secret1234&ssl=true";
Connection conn = DriverManager.getConnection(url);
Voor veilidheidsdoeleinden kun je de username/wachtwoord combinatie ook apart meegeven:
String url = "jdbc:mysql://192.168.1.1:3306/energy";
Connection conn = DriverManager.getConnection(url, "frederik", "Secret1234");
Note: Wanneer je klaar bent met je verbinding is het netjes om hem ook weer af te sluiten:
conn.close();
Versturen van een query gebeurt in drie stappen.
String query = "SELECT * FROM students WHERE number=?";
PreparedStatement statement = conn.prepareStatement(query);
Merk op dat de query een vraagteken. Deze plek markeert de locatie waar je een waarde kunt invullen in stap twee:
statement.setInteger(1, 123456);
Note: In dit beval binden we een integer waarde aan de eeste parameter in de query. We tellen vanaf 1, niet 0.
Voor tekst waarden hadden we het volgende kunnen doen:
stamement.setString(1, "Hello");
Dit is het enige verschil, de tekst van de query zonder de aanhalingstekens blijft hetzelfde!
Uiteindelijk kun je de query uitvoeren, met de ingevulde data:
ResultSet resultSet = statement.execute();
Wanneer je vergeet om een parameter te verbinden aan een waarde, wordt je door het systeem een mooie exceptie aangeboden.
Note: De reden om dit in drie stappen te doen, in plaats van de waarden gewoon op te nemen in de query tekst, is de volgende: Deze methode voorkomt iedere vorm van SQL injection. De geprepareerde query wordt geanalyseerd als SQL, de data wordt NOOIT gezien als SQL. Dus deze situatie kan niet voorkomen omdat “bobby tables” als data wordt gezien, niet als instructies.
Wanneer jouw query een aantal records oplevert, wat natuurlijk vaak gebeurt met een “SELECT” query, dan kun je het resultaat van de .execute()
methode opslaan in een ResultSet
variable.
Het lezen van een ResultSet
lijkt erg veel op het gebruik van de CSVReader. Dat is hoe deze code werkt:
while (resultSet.next()) {
String firstName = resultSet.getString("first_name");
String lastName = resultSet.getString("last_name");
int age = resultSet.getInteger("age");
Date date = resultSet.getDate("birthdate");
int number = resultSet.getInteger("number");
// Do something with this data...
Student result = new Student(number, firstName, lastName, age, birthdate);
// Add to a list or something...
}
Wanneer je klaar ben met jouw statement, sluit deze dan ook, zodat andere gebruikers de tabel kunnen lezen:
statement.close();
Om te bevestigen dat er geen fouten zijn, staat hier onder het code segment dat alle data uit mijn persoonlijke test database (MySQL) leest.
package nl.saxion.sdp.exercises.serialisation;
import java.sql.*;
public class Main {
public static void main(String[] args) throws SQLException {
String url = "jdbc:mysql://192.168.1.1:3306/students?user=frederik&password=Frederik&ssl=true";
Connection conn = DriverManager.getConnection(url);
String query = "SELECT * FROM student WHERE first_name LIKE ?";
PreparedStatement stmt = conn.prepareStatement(query);
stmt.setString(1, "%er%");
ResultSet result = stmt.executeQuery();
while (result.next()) {
int number = result.getInt("number");
String firstName = result.getString("first_name");
String lastName = result.getString("last_name");
Date birthdate = result.getDate("birthdate");
System.out.println(number+" : "+firstName+" "+lastName+" "+birthdate);
}
result.close();
stmt.close();
conn.close();
}
}
Het uitvoeren van dit code segment levert de volgende uitvoer op:
Note: Verbinden met de database staat je toe om individuele tabellen te bevragen, of door te joinen meerdere tabellen. De manier waarop deze tabellen met elkaar verbinden door foreign keys is iets wat je zelf moet afhandelen via iedere query. Maar wanneer je sommige tabellen een weerslag hebben in jouw datamodel, bijvoorbeeld studenten die bij een bepaalde groep horen, dan moet je eerst de studenten inladen en dan ieder student toevoegen aan het juiste “klas” object…
De complete klas (met studenten) structuur kan ineens gelezen worden door een bestand te deserialiseren van een JSON structuur. Wanneer je gebruik maakt van een database zul je zelf jouw “StudentGroup” moeten opvullen uit de database.