JavaRush /Blog Java /Random-FR /Partie 3. Nous créons le squelette de notre base de donné...
Marat Sadykov
Niveau 41

Partie 3. Nous créons le squelette de notre base de données, les premières commandes SQL à l'aide d'exemples java.sql.

Publié dans le groupe Random-FR
Première partie Deuxième partie
Partie 3. Nous créons le squelette de notre base de données, les premières commandes SQL à l'aide d'exemples java.sql.  - 1

Application Java

Organisation à 3 niveaux

Revenons à l'application Java. La version de la partie précédente a été créée dans le style HelloWorld pour contrôler l'exactitude des actions initiales. Nous implémentons une architecture à trois niveaux (trois couches), souvent appelée dans la littérature anglophone 3tier/3layer . Sa brève essence est la suivante :
  • Toutes les entités sont conçues comme des modèles. Ce sont des objets qui contiennent :
    • Un ensemble d'attributs (champs privés de la classe).
    • Constructeur(s).
    • Setters et getters pour la définition/lecture des attributs.
    • Il est important qu’ils ne contiennent aucun autre code que celui ci-dessus. De tels objets sont souvent appelés POJO (Plain Old Java Object).
  • Toute la logique permettant de travailler avec des modèles est implémentée par la couche Service. Il génère des règles métier pour les modèles. Par exemple, traiter les requêtes d'une application Java. Les arguments de requête et les résultats renvoyés incluent souvent des modèles (ou des collections de ceux-ci).
  • La couche Repository est un « intermédiaire » entre le SGBD et le Service, travaillant directement avec la base de données et responsable de l'interaction avec elle.
Partie 3. Nous créons le squelette de notre base de données, les premières commandes SQL à l'aide d'exemples java.sql.  - 2 Pourquoi avons-nous même besoin de former un tel conglomérat ? Le fait est que chaque couche est isolée au maximum des autres. Si au lieu d'une base de données nous avons un ensemble de fichiers texte, il nous suffit alors de modifier l'implémentation du Repository sans toucher au reste du code. De même, nous pouvons connecter/ajouter un autre service avec des modifications minimes. Pour les grands systèmes, nous pouvons confier la mise en œuvre de différentes couches à différentes personnes ou expérimenter en combinant des implémentations optimales de différentes couches. Créons des packages modèle , référentiel , service pour notre application, où se trouveront les classes correspondantes. Nous reviendrons sur la couche Service dans les parties suivantes, mais pour l'instant nous ferons attention aux modèles et aux référentiels. Partie 3. Nous créons le squelette de notre base de données, les premières commandes SQL à l'aide d'exemples java.sql.  - 3

Modèle

Toutes nos entités (actions, traders, taux et actions des traders) et leurs équivalents de table ont une caractéristique commune : une clé primaire artificielle. Alors créons une classe de base BaseModel. Tous les modèles en hériteront.
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);
    }
}
Vous trouverez ci-dessous un exemple de modèle de stock. Vous pouvez voir le reste des listes de modèles en suivant le lien vers le référentiel github à la fin de l'article.
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

Dans la première partie, nous avons appris comment établir une connexion à la base de données et la fermer. Passons maintenant à autre chose. Les étapes de travail avec JDBC sont présentées dans le schéma suivant : Partie 3. Nous créons le squelette de notre base de données, les premières commandes SQL à l'aide d'exemples java.sql.  - 4
  • Class.forName()charge la classe et l'enregistre auprès de DriverManager ;
  • DriverManager.getConnection()renverra Connection– une connexion à la base de données spécifiée dans l’argument de la méthode et utilisant le pilote JDBC correspondant (qui a été chargé à l’aide de Class.forName()).
  • createStatement()nous renverra Statementun objet sur la base duquel nous pourrons former des requêtes vers la base de données. Il y a aussi:
      CallableStatementpour appeler les propres fonctions et procédures SQL du SGBD (on les appelle stockées).
    • PreparedStatementfaciliter la création de requêtes paramétrées et batch.
  • Avoir « en main » vous statementpermettra execute()d'envoyer une requête sous la forme d'une commande du langage de requête SQL directement à l'exécution du SGBD et de renvoyer une réponse sous la forme de ResultSet. Pour plus de commodité, il y a :
    • executeQuery()– pour lire les données du SGBD.
    • executeUpdate()– de modifier les données dans le SGBD.
  • La réponse du serveur elle-même ResultSetpeut être traitée sous la forme en itérant sur first(), last(), next()etc. Nous pouvons obtenir des champs de résultats individuels via des getters : getInteger(), getString()...
Il faut garder à l'esprit qu'après avoir travaillé avec le SGBD, afin d'économiser des ressources, il est conseillé de fermer les objets derrière vous (dans le bon ordre !) ResultSet, Statementet Connectiond'économiser des ressources. N'oubliez pas que lorsque vous fermez un objet situé plus haut dans la séquence du diagramme, vous fermerez en cascade tous les objets générés au cours du processus de travail avec lui. Ainsi, la fermeture d'une connexion entraînera la fermeture de l'ensemble de celle-ci Statementet de tout ce ResultSetqui a été reçu avec leur aide.

Implémentation du référentiel

Après la partie théorique JDBC, passons à la mise en œuvre du référentiel. Nous l'implémentons architecturalement comme suit :
  • Nous déplacerons les parties les plus générales du travail avec un SGBD vers un ancêtre commun -BaseTable ;
  • Les opérations logiques que nous effectuerons seront déclarées dans l'interface TableOperation;
Partie 3. Nous créons le squelette de notre base de données, les premières commandes SQL à l'aide d'exemples java.sql.  - 5 Le nouveau référentiel héritera de la classe BaseTableet implémentera l'interface TableOperation. Nous devons donc écrire l'implémentation des méthodes déclarées dans l'interface TableOperation. Dans ce cas, nous pouvons utiliser les méthodes de la classe parent BaseTable. Pour le moment, l'interface déclare les méthodes de création de tables :
package sql.demo.repository;
import java.sql.SQLException;

// Операции с tableми
public interface TableOperations {
    void createTable() throws SQLException; // создание таблицы
    void createForeignKeys() throws SQLException; // создание связей между tableми
    void createExtraConstraints() throws SQLException; // создание дополнительных правил для значений полей таблиц
}
Au fur et à mesure que vous étudiez le matériel, la liste des déclarations de méthode s'allongera ( read(), update()….). Nous implémenterons les nouvelles fonctionnalités en deux étapes :
  1. Ajoutons une autre possibilité de travailler avec un tableau sous la forme d'une nouvelle méthode d'interface.
  2. Ensuite, dans les classes implémentant l'interface, nous décrirons l'implémentation logicielle dans les nouvelles méthodes générées par l'interface.
Exemple de référentiel pour Share(stocks). La logique principale réside dans les commandes permettant de créer des tables, de spécifier les types de données SQL pour les champs et d'ajouter des restrictions :
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)", "Создана table " + 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");

    }
}
Les listes d'autres référentiels et de la classe parent sont disponibles via le lien vers le référentiel github à la fin de l'article. Bien sûr, vous pouvez concevoir un programme différent ou refactoriser le programme plus en profondeur : déplacer les parties communes dans une classe parent, mettre en évidence les méthodes communes, etc. Mais l'objectif principal de la série d'articles est de travailler directement avec la base de données, donc si vous le souhaitez, vous pouvez concevoir un programme, etc., vous pouvez le faire vous-même. Structure actuelle du projet : Partie 3. Nous créons le squelette de notre base de données, les premières commandes SQL à l'aide d'exemples java.sql.  - 6 En plus des référentiels et des modèles, nous avons également créé une classe StockExchangeDBpour la gestion générale de notre émulation. A ce stade, nous gérons les référentiels (dans les prochaines parties, nous passerons aux services). Nous les déclarons et commençons à créer des tables :
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();
    }

    // Инициализация по умолчанию, без удаления file БД
    public StockExchangeDB() throws SQLException, ClassNotFoundException {
        this(false);
    }

    // Creation всех таблиц и внешних ключей
    public void createTablesAndForeignKeys() throws SQLException {
        shares.createTable();
        shareRates.createTable();
        traiders.createTable();
        traiderShareActions.createTable();
        // Creation ограничений на поля таблиц
        traiderShareActions.createExtraConstraints();
        shares.createExtraConstraints();
        // Creation внешних ключей (связи между tableми)
        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 драйвер для СУБД не найден!");
        }
    }
}
Résultat de l'exécution : Partie 3. Nous créons le squelette de notre base de données, les premières commandes SQL à l'aide d'exemples java.sql.  - 7

Résumé

Dans les deuxième et troisième parties de l'article, nous avons appris :
  • Types de données SQL.
  • Tableaux de base de données.
  • Conception d'une base de données : structures de tables et relations entre elles.
  • Langage de requête SQL en termes de création de tables de base de données, de définition de restrictions sur les champs et de relations entre les tables.
  • En savoir plus sur l'interaction avec JDBC.
  • Architecture modèle/référentiel/service à trois niveaux (trois couches) d'une application de traitement de données.

Liens utiles

Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION