Erster Teil Zweiter Teil
Java-Anwendung
3-stufige Organisation
Kehren wir zur Java-Anwendung zurück. Die Version aus dem vorherigen Teil wurde im HelloWorld- Stil erstellt, um die Richtigkeit der ersten Aktionen zu kontrollieren. Wir implementieren eine dreischichtige (dreischichtige) Architektur, die in der englischsprachigen Literatur oft als 3tier/3layer bezeichnet wird . Sein kurzer Kern ist wie folgt:- Alle Entitäten sind als Modelle konzipiert. Dies sind Objekte, die Folgendes enthalten:
- Eine Reihe von Attributen (private Felder der Klasse).
- Konstrukteur(en).
- Setter und Getter zum Setzen/Lesen von Attributen.
- Es ist wichtig, dass sie außer dem oben genannten keinen weiteren Code enthalten. Solche Objekte werden oft POJO (Plain Old Java Object) genannt.
- Die gesamte Logik für die Arbeit mit Modellen wird von der Serviceschicht implementiert. Es generiert Geschäftsregeln für Modelle. Beispielsweise die Verarbeitung von Anfragen einer Java-Anwendung. Abfrageargumente und zurückgegebene Ergebnisse umfassen häufig Modelle (oder Sammlungen davon).
- Die Repository-Schicht ist ein „Vermittler“ zwischen dem DBMS und dem Dienst, arbeitet direkt mit der Datenbank und ist für die Interaktion mit dieser verantwortlich.
Modell
Alle unsere Entitäten (Aktien, Händler, Kurse und Händleraktionen) und ihre Tabellenäquivalente haben ein gemeinsames Merkmal – einen künstlichen Primärschlüssel. Erstellen wir daher eine BasisklasseBaseModel
. Alle Modelle erben davon.
package sql.demo.model;
import java.util.Objects;
// Базовый класс модели, имеющий ключ id
public class BaseModel {
protected long id;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public BaseModel() {}
public BaseModel(long id) {
this.id = id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BaseModel baseModel = (BaseModel) o;
return id == baseModel.id;
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
Unten finden Sie ein Beispiel für ein Aktienmodell. Sie können die restlichen Modelllisten sehen, indem Sie dem Link zum Github-Repository am Ende des Artikels folgen.
package sql.demo.model;
import java.math.BigDecimal;
// Модель акции
public class Share extends BaseModel{
// поля SQL таблицы и соответствующие им поля модели
// типы данных SQL
private String name; // Наименование
private BigDecimal startPrice; // Начальная цена
private int changeProbability; // Вероятность смены курса (в процентах)
private int delta; // Максимальное колебание (в процентах)стоимости акции в результате торгов
public Share() {
}
public Share(long id, String name, BigDecimal startPrice, int changeProbability, int delta) {
super(id);
this.name = name;
this.startPrice = startPrice;
this.changeProbability = changeProbability;
this.delta = delta;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
... оставшиеся сеттеры/геттеры
}
JDBC
Im ersten Teil haben wir gelernt, wie man eine Verbindung zur Datenbank herstellt und diese schließt. Jetzt lasst uns weitermachen. Die Phasen der Arbeit mit JDBC werden im folgenden Diagramm dargestellt:Class.forName()
lädt die Klasse und registriert sie bei DriverManager;DriverManager.getConnection()
wird zurückkommenConnection
– eine Verbindung zu der im Methodenargument angegebenen Datenbank und unter Verwendung des entsprechenden JDBC-Treibers (der mit geladen wurdeClass.forName()
).createStatement()
wird unsStatement
ein Objekt zurücksenden, auf dessen Grundlage wir Abfragen an die Datenbank stellen können. Es gibt auch:PreparedStatement
Erleichterung der Erstellung parametrisierter und Batch-Abfragen.
CallableStatement
um die eigenen SQL-Funktionen und -Prozeduren des DBMS aufzurufen (sie werden als gespeichert bezeichnet).- Wenn Sie „in der Hand“ haben,
statement
könnenexecute()
Sie eine Anfrage in Form eines SQL-Abfragesprachenbefehls direkt an die DBMS-Ausführung senden und eine Antwort in Form von zurückgebenResultSet
. Der Einfachheit halber gibt es:executeQuery()
– zum Lesen von Daten aus dem DBMS.
executeUpdate()
– um Daten im DBMS zu ändern. - Die Serverantwort selbst
ResultSet
kann im Formular verarbeitet werden, indem ,first()
usw. durchlaufen werden. Wir können einzelne Ergebnisfelder durch Getter erhalten: , ...last()
next()
getInteger()
getString()
ResultSet
und Ressourcen Statement
zu Connection
sparen. Denken Sie daran, dass Sie beim Schließen eines Objekts, das in der Reihenfolge im Diagramm weiter oben steht, alle Objekte schließen, die bei der Arbeit damit generiert wurden. Das Schließen einer Verbindung führt also zum Schließen aller Verbindungen Statement
und aller ResultSet
mit ihrer Hilfe empfangenen Verbindungen.
Implementierung des Repositorys
Nach dem theoretischen JDBC-Teil fahren wir mit der Implementierung des Repositorys fort. Wir setzen es architektonisch wie folgt um:- Wir werden die allgemeinsten Teile der Arbeit mit einem DBMS in einen gemeinsamen Vorfahren verschieben –
BaseTable
; - Die logischen Operationen, die wir ausführen werden, werden in der Schnittstelle deklariert
TableOperation
;
BaseTable
und implementiert die Schnittstelle TableOperation
. Daher müssen wir die Implementierung der in der Schnittstelle deklarierten Methoden schreiben TableOperation
. In diesem Fall können wir die Methoden der übergeordneten Klasse verwenden BaseTable
. Derzeit deklariert die Schnittstelle Methoden zum Erstellen von Tabellen:
package sql.demo.repository;
import java.sql.SQLException;
// Операции с Tischми
public interface TableOperations {
void createTable() throws SQLException; // создание таблицы
void createForeignKeys() throws SQLException; // создание связей между Tischми
void createExtraConstraints() throws SQLException; // создание дополнительных правил для значений полей таблиц
}
Während Sie das Material studieren, wird die Liste der Methodendeklarationen erweitert ( read()
, update()
...). Wir werden neue Funktionen in zwei Schritten implementieren:
- Fügen wir eine weitere Möglichkeit zum Arbeiten mit einer Tabelle in Form einer neuen Schnittstellenmethode hinzu.
- Als nächstes beschreiben wir in den Klassen, die die Schnittstelle implementieren, die Softwareimplementierung in neuen Methoden, die von der Schnittstelle generiert werden.
Share
(Aktien). Die Hauptlogik liegt in den Befehlen zum Erstellen von Tabellen, zum Festlegen von SQL-Datentypen für Felder und zum Hinzufügen von Einschränkungen:
package sql.demo.repository;
import java.sql.SQLException;
public class Shares extends BaseTable implements TableOperations{
public Shares() throws SQLException {
super("shares");
}
@Override
public void createTable() throws SQLException {
super.executeSqlStatement("CREATE TABLE shares(" +
"id BIGINT AUTO_INCREMENT PRIMARY KEY," +
"name VARCHAR(255) NOT NULL," +
"startPrice DECIMAL(15,2) NOT NULL DEFAULT 10," +
"changeProbability INTEGER NOT NULL DEFAULT 25,"+
"delta INTEGER NOT NULL DEFAULT 15)", "Создана Tisch " + tableName);
}
@Override
public void createForeignKeys() throws SQLException {
}
@Override
public void createExtraConstraints() throws SQLException {
super.executeSqlStatement(
" ALTER TABLE shares ADD CONSTRAINT check_shares_delta CHECK(delta <= 100 and delta > 0)",
"Cоздано ограничение для shares, поле delta = [1,100]");
super.executeSqlStatement(
" ALTER TABLE shares ADD CONSTRAINT check_shares_changeProbability " +
"CHECK(changeProbability <= 100 and changeProbability > 0)",
"Cоздано ограничение для shares, поле changeProbability = 1..100");
}
}
Auflistungen anderer Repositorys und der übergeordneten Klasse sind über den Link zum Github-Repository am Ende des Artikels verfügbar. Natürlich können Sie einen anderen Programmentwurf oder eine gründlichere Umgestaltung des Programms vornehmen: Gemeinsame Teile in eine übergeordnete Klasse verschieben, gemeinsame Methoden hervorheben und so weiter. Das Hauptziel der Artikelserie besteht jedoch darin, direkt mit der Datenbank zu arbeiten. Wenn Sie möchten, können Sie das Programm usw. auch selbst entwerfen. Aktuelle Projektstruktur: Zusätzlich zu Repositories und Modellen haben wir zusätzlich eine Klasse StockExchangeDB
zur allgemeinen Verwaltung unserer Emulation erstellt. In dieser Phase verwalten wir Repositories (in den nächsten Teilen werden wir zu Diensten übergehen). Wir deklarieren sie und beginnen mit der Erstellung von Tabellen:
package sql.demo;
import org.h2.tools.DeleteDbFiles;
import sql.demo.repository.*;
import java.sql.*;
public class StockExchangeDB {
// Блок объявления констант
public static final String DB_DIR = "c:/JavaPrj/SQLDemo/db";
public static final String DB_FILE = "stockExchange";
public static final String DB_URL = "jdbc:h2:/" + DB_DIR + "/" + DB_FILE;
public static final String DB_Driver = "org.h2.Driver";
// Таблицы СУБД
Traiders traiders;
ShareRates shareRates;
Shares shares;
TraiderShareActions traiderShareActions;
// Получить новое соединение с БД
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(DB_URL);
}
// Инициализация
public StockExchangeDB(boolean renew) throws SQLException, ClassNotFoundException {
if (renew)
DeleteDbFiles.execute(DB_DIR, DB_FILE, false);
Class.forName(DB_Driver);
// Инициализируем таблицы
traiders = new Traiders();
shares = new Shares();
shareRates = new ShareRates();
traiderShareActions = new TraiderShareActions();
}
// Инициализация по умолчанию, без удаления Datei БД
public StockExchangeDB() throws SQLException, ClassNotFoundException {
this(false);
}
// Schaffung всех таблиц и внешних ключей
public void createTablesAndForeignKeys() throws SQLException {
shares.createTable();
shareRates.createTable();
traiders.createTable();
traiderShareActions.createTable();
// Schaffung ограничений на поля таблиц
traiderShareActions.createExtraConstraints();
shares.createExtraConstraints();
// Schaffung внешних ключей (связи между Tischми)
shareRates.createForeignKeys();
traiderShareActions.createForeignKeys();
}
public static void main(String[] args) {
try{
StockExchangeDB stockExchangeDB = new StockExchangeDB(true);
stockExchangeDB.createTablesAndForeignKeys();
} catch (SQLException e) {
e.printStackTrace();
System.out.println("Ошибка SQL !");
} catch (ClassNotFoundException e) {
System.out.println("JDBC драйвер для СУБД не найден!");
}
}
}
Ausführungsergebnis:
Zusammenfassung
Im zweiten und dritten Teil des Artikels haben wir gelernt:- SQL-Datentypen.
- Datenbanktabellen.
- Entwerfen einer Datenbank: Tabellenstrukturen und Beziehungen zwischen ihnen.
- SQL-Abfragesprache im Hinblick auf die Erstellung von Datenbanktabellen, das Festlegen von Einschränkungen für Felder und Beziehungen zwischen Tabellen.
- Mehr zur Interaktion mit JDBC.
- Dreistufige (dreischichtige) Modell-/Repository-/Dienstarchitektur einer Datenverarbeitungsanwendung.
GO TO FULL VERSION