package app.model;
//# Jon: Jeg mener fremdeles at denne klassen er en kontrollerklasse og hører
// hjemme i pakken app.controller. :-)
import java.sql.*;
/**
* DatabaseTilkobling.java
*
* Tilkobling til databasen.
* Har brukt lokal database på macen.
*
* Tabellen min i databasen bruker autoinkrement for oppretting av lånenr
* Et lånenr kan aldri gjenbrukes. Dvs. hvis det slettes, så slettes det
* ingen ta over dette nummeret senere.
//# Jon: Det er ok. Som regel er det slik man gjør det i databaser. Dvs.
// "ledige" primærnøkler gjenbrukes ikke.
*
* @author Hilde Vestøl (106288)
* @version 0.9
*/
public class DatabaseTilkobling {
private static final String dbDriver = "org.apache.derby.jdbc.ClientDriver";
private static final String URL = "jdbc:derby://localhost:1527/laneapp;user=app;password=app";
private static Connection forbindelse = null;
/**
*
*/
public DatabaseTilkobling() {
}
/**
* Etablerer databaseforbindelsen
* @return true/false
*/
public static boolean openDB() {
try {
Class.forName(dbDriver);
forbindelse = DriverManager.getConnection(URL);
if (forbindelse != null) {
return true;
} else {
System.out.println("openDB(): Fikk ikke etablert forbindelse");
return false;
}
} catch (ClassNotFoundException cnfe) {
System.out.println("openDB(): Klarte ikke å laste JDBC driver. " + cnfe);
return false;
} catch (SQLException sqle) {
System.out.println("openDB(): Klarte ikke å åpne databasen: " + sqle);
return false;
}
} // end openDB()
/**
* Lagrer lånet i databasen.
* Hvis ikke lånet finnes, skal det settes inn i databasen,
* hvis det finnes, skal det oppdateres.
*
* @param lån
* @return Loan lån
* @throws SQLException
* @throws LoanException
*/
public static Loan saveToDB( Loan lån ) throws SQLException, LoanException {
//# Jon: Jeg tror jeg ville ha valgt å behandle unntakene i denne metoden...
//#Jon: if og else grenene nedenfor inneholder mange identiske kodelinjer.
// Se om du kan "refaktorere" slik at du blir kvitt noen av dem. :-)
if ( lån.getLåneNR() != 0 ) {
//# Jon: Ok å sjekke at lånenr !=0, men dette gir deg strengt tatt
// ingen garanti for at lånet finnes i databasen. Hvis ikke vil
// UPDATE setningen ikke gjøre noe. Du bør altså sjekke med en
// SELECT om lånenummeret finnes i basen.
String sqlSetning = "UPDATE LAAN2 SET LOAN_AMOUNT = ?, LOAN_TIME = ?, LOAN_TERMIN = ?, LOAN_RENTE = ?, LOAN_TYPE = ? WHERE ID = ?";
//# Jon: PreparedStatement er unødvendig tungvidt her og gir heller ingen gevinst her.
// Det bruker vi bare når vi skal kjøre mange "like" SQL setninger etterhverandre for å unngå
// at DBMSet optimaliserer spørringen hver gang. I dette tilfellet oppnår du ikke det siden
// du kun gjør èn UPDATE for hvert PreparedStatement.
PreparedStatement setning = forbindelse.prepareStatement(sqlSetning);
setning.setInt(1, lån.getLånebeløp()); //Beløp
setning.setInt(2, lån.getLøpetid()); //Løpetid
setning.setInt(3, lån.getÅrligeTerminer()); //Termin
setning.setDouble(4, lån.getRentesats()); //Rente
setning.setInt(5, lån.getLånetype()); //Type lån
setning.setInt(6, lån.getLåneNR());
setning.executeUpdate();
//# Jon: Du bør alltid sjekke returverdien fra executeUpdate() for å være sikker på
// at den faktisk oppdaterte det antall rader du forventet.
// Dessuten bør setning helst lukkes etter bruk.
return lån;
} else {
String sqlSetning = "INSERT INTO LAAN2 (LOAN_AMOUNT, LOAN_TIME, LOAN_TERMIN, LOAN_RENTE, LOAN_TYPE) VALUES (?, ?, ?, ?, ?)";
PreparedStatement setning = forbindelse.prepareStatement(sqlSetning);
setning.setInt(1, lån.getLånebeløp()); //Beløp
setning.setInt(2, lån.getLøpetid()); //Løpetid
setning.setInt(3, lån.getÅrligeTerminer()); //Termin
setning.setDouble(4, lån.getRentesats()); //Rente
setning.setInt(5, lån.getLånetype()); //Type lån
setning.executeUpdate();
//# Jon: Du bør alltid sjekke returverdien fra executeUpdate() for å være sikker på
// at den faktisk oppdaterte det antall rader du forventet.
// Dessuten bør setning helst lukkes etter bruk.
//#Jon: Bra at du har funnet ut hvordan du får tak i den automatisk genererte IDen!
Statement stm = forbindelse.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
stm.setMaxRows(1);
ResultSet res = stm.executeQuery("SELECT ID FROM LAAN2 ORDER BY ID DESC");
if (res.next() )
{
lån.setLåneNr(res.getInt("ID") );
}
return lån;
}
}
/**
* Finner et lån fra databasen.
*
* @param låneNr
* @param lån
* @return
* @throws SQLException
* @throws LoanException
*/
public static Loan findFromDB(int låneNr, Loan lån) throws SQLException, LoanException {
//#Jon: Du behøver vel ikke lån som parameter her så lenge metoden skal returnere
// lånet som er funnet? Du kan vel bare bygget et nytt Loan objekt?
Statement stm = forbindelse.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
stm.setMaxRows(1);
ResultSet res = stm.executeQuery("SELECT * FROM LAAN2 WHERE ID =" + låneNr);
if (res.next() ){
lån.setLåneNr(res.getInt("ID") );
lån.setLånebeløp(res.getInt("LOAN_AMOUNT") );
lån.setLøpetid(res.getInt("LOAN_TIME"));
lån.setÅrligeTerminer(res.getInt ("LOAN_TERMIN"));
lån.setRentesats(res.getDouble("LOAN_RENTE"));
lån.setLånetype(res.getInt("LOAN_TYPE"));
return lån;
} else {
throw new LoanException("Fant ikke låneID");
}
}
/**
* Sletter et lån med gitt lånenr fra databasen.
* @param låneNr
* @return
* @throws SQLException
*/
public static boolean deleteFromDB(int låneNr) throws SQLException {
String sql = "DELETE FROM LAAN2 WHERE ID = " + låneNr;
PreparedStatement setning = forbindelse.prepareStatement(sql);
setning.execute();
if (setning.getUpdateCount() > 0)
return true;
throw new SQLException();
}
/**
* Lukker databaseforbindelsen
* @return boolean
*/
public static boolean closeDB() {
try {
forbindelse.close();
return true;
} catch (SQLException sqle) {
System.out.println("closeDB(): Klarte ikke å lukke databasen. " + sqle);
return false;
}
}
}
//# Jon: Jeg mener fremdeles at denne klassen er en kontrollerklasse og hører
// hjemme i pakken app.controller. :-)
import java.sql.*;
/**
* DatabaseTilkobling.java
*
* Tilkobling til databasen.
* Har brukt lokal database på macen.
*
* Tabellen min i databasen bruker autoinkrement for oppretting av lånenr
* Et lånenr kan aldri gjenbrukes. Dvs. hvis det slettes, så slettes det
* ingen ta over dette nummeret senere.
//# Jon: Det er ok. Som regel er det slik man gjør det i databaser. Dvs.
// "ledige" primærnøkler gjenbrukes ikke.
*
* @author Hilde Vestøl (106288)
* @version 0.9
*/
public class DatabaseTilkobling {
private static final String dbDriver = "org.apache.derby.jdbc.ClientDriver";
private static final String URL = "jdbc:derby://localhost:1527/laneapp;user=app;password=app";
private static Connection forbindelse = null;
/**
*
*/
public DatabaseTilkobling() {
}
/**
* Etablerer databaseforbindelsen
* @return true/false
*/
public static boolean openDB() {
try {
Class.forName(dbDriver);
forbindelse = DriverManager.getConnection(URL);
if (forbindelse != null) {
return true;
} else {
System.out.println("openDB(): Fikk ikke etablert forbindelse");
return false;
}
} catch (ClassNotFoundException cnfe) {
System.out.println("openDB(): Klarte ikke å laste JDBC driver. " + cnfe);
return false;
} catch (SQLException sqle) {
System.out.println("openDB(): Klarte ikke å åpne databasen: " + sqle);
return false;
}
} // end openDB()
/**
* Lagrer lånet i databasen.
* Hvis ikke lånet finnes, skal det settes inn i databasen,
* hvis det finnes, skal det oppdateres.
*
* @param lån
* @return Loan lån
* @throws SQLException
* @throws LoanException
*/
public static Loan saveToDB( Loan lån ) throws SQLException, LoanException {
//# Jon: Jeg tror jeg ville ha valgt å behandle unntakene i denne metoden...
//#Jon: if og else grenene nedenfor inneholder mange identiske kodelinjer.
// Se om du kan "refaktorere" slik at du blir kvitt noen av dem. :-)
if ( lån.getLåneNR() != 0 ) {
//# Jon: Ok å sjekke at lånenr !=0, men dette gir deg strengt tatt
// ingen garanti for at lånet finnes i databasen. Hvis ikke vil
// UPDATE setningen ikke gjøre noe. Du bør altså sjekke med en
// SELECT om lånenummeret finnes i basen.
String sqlSetning = "UPDATE LAAN2 SET LOAN_AMOUNT = ?, LOAN_TIME = ?, LOAN_TERMIN = ?, LOAN_RENTE = ?, LOAN_TYPE = ? WHERE ID = ?";
//# Jon: PreparedStatement er unødvendig tungvidt her og gir heller ingen gevinst her.
// Det bruker vi bare når vi skal kjøre mange "like" SQL setninger etterhverandre for å unngå
// at DBMSet optimaliserer spørringen hver gang. I dette tilfellet oppnår du ikke det siden
// du kun gjør èn UPDATE for hvert PreparedStatement.
PreparedStatement setning = forbindelse.prepareStatement(sqlSetning);
setning.setInt(1, lån.getLånebeløp()); //Beløp
setning.setInt(2, lån.getLøpetid()); //Løpetid
setning.setInt(3, lån.getÅrligeTerminer()); //Termin
setning.setDouble(4, lån.getRentesats()); //Rente
setning.setInt(5, lån.getLånetype()); //Type lån
setning.setInt(6, lån.getLåneNR());
setning.executeUpdate();
//# Jon: Du bør alltid sjekke returverdien fra executeUpdate() for å være sikker på
// at den faktisk oppdaterte det antall rader du forventet.
// Dessuten bør setning helst lukkes etter bruk.
return lån;
} else {
String sqlSetning = "INSERT INTO LAAN2 (LOAN_AMOUNT, LOAN_TIME, LOAN_TERMIN, LOAN_RENTE, LOAN_TYPE) VALUES (?, ?, ?, ?, ?)";
PreparedStatement setning = forbindelse.prepareStatement(sqlSetning);
setning.setInt(1, lån.getLånebeløp()); //Beløp
setning.setInt(2, lån.getLøpetid()); //Løpetid
setning.setInt(3, lån.getÅrligeTerminer()); //Termin
setning.setDouble(4, lån.getRentesats()); //Rente
setning.setInt(5, lån.getLånetype()); //Type lån
setning.executeUpdate();
//# Jon: Du bør alltid sjekke returverdien fra executeUpdate() for å være sikker på
// at den faktisk oppdaterte det antall rader du forventet.
// Dessuten bør setning helst lukkes etter bruk.
//#Jon: Bra at du har funnet ut hvordan du får tak i den automatisk genererte IDen!
Statement stm = forbindelse.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
stm.setMaxRows(1);
ResultSet res = stm.executeQuery("SELECT ID FROM LAAN2 ORDER BY ID DESC");
if (res.next() )
{
lån.setLåneNr(res.getInt("ID") );
}
return lån;
}
}
/**
* Finner et lån fra databasen.
*
* @param låneNr
* @param lån
* @return
* @throws SQLException
* @throws LoanException
*/
public static Loan findFromDB(int låneNr, Loan lån) throws SQLException, LoanException {
//#Jon: Du behøver vel ikke lån som parameter her så lenge metoden skal returnere
// lånet som er funnet? Du kan vel bare bygget et nytt Loan objekt?
Statement stm = forbindelse.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
stm.setMaxRows(1);
ResultSet res = stm.executeQuery("SELECT * FROM LAAN2 WHERE ID =" + låneNr);
if (res.next() ){
lån.setLåneNr(res.getInt("ID") );
lån.setLånebeløp(res.getInt("LOAN_AMOUNT") );
lån.setLøpetid(res.getInt("LOAN_TIME"));
lån.setÅrligeTerminer(res.getInt ("LOAN_TERMIN"));
lån.setRentesats(res.getDouble("LOAN_RENTE"));
lån.setLånetype(res.getInt("LOAN_TYPE"));
return lån;
} else {
throw new LoanException("Fant ikke låneID");
}
}
/**
* Sletter et lån med gitt lånenr fra databasen.
* @param låneNr
* @return
* @throws SQLException
*/
public static boolean deleteFromDB(int låneNr) throws SQLException {
String sql = "DELETE FROM LAAN2 WHERE ID = " + låneNr;
PreparedStatement setning = forbindelse.prepareStatement(sql);
setning.execute();
if (setning.getUpdateCount() > 0)
return true;
throw new SQLException();
}
/**
* Lukker databaseforbindelsen
* @return boolean
*/
public static boolean closeDB() {
try {
forbindelse.close();
return true;
} catch (SQLException sqle) {
System.out.println("closeDB(): Klarte ikke å lukke databasen. " + sqle);
return false;
}
}
}