Primeira parte Segunda parte
Aplicativo Java
Organização de 3 níveis
Voltemos ao aplicativo Java. A versão da parte anterior foi criada no estilo HelloWorld para controlar a correção das ações iniciais. Implementamos uma arquitetura de três camadas (três camadas), que na literatura de língua inglesa é frequentemente chamada de 3tier/3layer . Sua breve essência é a seguinte:- Todas as entidades são projetadas como modelos. Estes são objetos que contêm:
- Um conjunto de atributos (campos privados da classe).
- Construtor(es).
- Setters e getters para configuração/leitura de atributos.
- É importante que não contenham nenhum outro código além do acima. Esses objetos são frequentemente chamados de POJO (Plain Old Java Object).
- Toda a lógica para trabalhar com modelos é implementada pela camada de Serviço. Ele gera regras de negócios para modelos. Por exemplo, processar solicitações de um aplicativo Java. Os argumentos de consulta e os resultados retornados geralmente incluem modelos (ou coleções deles).
- A camada Repositório é um “intermediário” entre o SGBD e o Serviço, trabalhando diretamente com o banco de dados e responsável pela interação com ele.
Modelo
Todas as nossas entidades (ações, traders, taxas e ações de traders) e seus equivalentes de tabela têm uma característica comum - uma chave primária artificial. Portanto, vamos criar uma classe baseBaseModel
. Todos os modelos herdarão dele.
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);
}
}
Abaixo está um exemplo de modelo de estoque. Você pode ver o restante das listagens de modelos seguindo o link para o repositório do github no final do artigo.
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
Na primeira parte aprendemos como estabelecer uma conexão com o banco de dados e fechá-lo. Agora vamos seguir em frente. As etapas de trabalho com JDBC são mostradas no diagrama a seguir:Class.forName()
carrega a classe e a registra no DriverManager;DriverManager.getConnection()
retornaráConnection
– uma conexão com o banco de dados especificado no argumento do método e usando o driver JDBC correspondente (que foi carregado usandoClass.forName()
).createStatement()
nos retornaráStatement
um objeto com base no qual podemos fazer consultas ao banco de dados. Há também:PreparedStatement
facilitando a criação de consultas parametrizadas e em lote.
CallableStatement
para chamar as funções e procedimentos SQL do próprio SGBD (eles são chamados de armazenados).- Ter “em mãos”
statement
permitiráexecute()
enviar uma solicitação na forma de um comando de linguagem de consulta SQL diretamente para a execução do SGBD e retornar uma resposta na forma deResultSet
. Por conveniência, existem:executeQuery()
– para leitura de dados do SGBD.
executeUpdate()
– para modificar dados no SGBD. - A própria resposta do servidor
ResultSet
pode ser processada no formato, iterando por meio de ,first()
e assim por diante. Podemos obter campos de resultados individuais através de getters: , ...last()
next()
getInteger()
getString()
ResultSet
e economizar recursos. Lembre-se, ao fechar um objeto que está acima na sequência do diagrama, você fechará em cascata todos os objetos gerados no processo de trabalhar com ele. Assim, fechar uma conexão levará ao fechamento de toda ela e de tudo recebido com a ajuda deles. Statement
Connection
Statement
ResultSet
Implementação do Repositório
Após a parte teórica do JDBC, vamos passar para a implementação do repositório. Nós o implementamos arquitetonicamente da seguinte forma:- Moveremos as partes mais gerais do trabalho com um SGBD para um ancestral comum -
BaseTable
; - As operações lógicas que realizaremos serão declaradas na interface
TableOperation
;
BaseTable
e implementará a interface TableOperation
. Assim, precisamos escrever a implementação dos métodos declarados na interface TableOperation
. Neste caso, podemos usar os métodos da classe pai BaseTable
. No momento, a interface declara métodos para criação de tabelas:
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; // создание дополнительных правил для значений полей таблиц
}
À medida que você estuda o material, a lista de declarações de métodos se expandirá ( read()
, update()
….). Implementaremos novos recursos em duas etapas:
- Vamos adicionar outra capacidade de trabalhar com uma tabela na forma de um novo método de interface.
- A seguir, nas classes que implementam a interface, descreveremos a implementação do software em novos métodos gerados pela interface.
Share
(ações). A lógica principal está nos comandos para criar tabelas, especificar tipos de dados SQL para campos e adicionar restrições:
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");
}
}
Listagens de outros repositórios e da classe pai estão disponíveis através do link para o repositório github no final do artigo. Claro, você pode fazer um design de programa diferente ou uma refatoração mais completa do programa: mover partes comuns para uma classe pai, destacar métodos comuns e assim por diante. Mas o objetivo principal da série de artigos é trabalhar diretamente com o banco de dados, então se desejar, você pode projetar o programa e assim por diante, você mesmo pode fazer isso. Estrutura atual do projeto: Além de repositórios e modelos, criamos adicionalmente uma classe StockExchangeDB
para gerenciamento geral de nossa emulação. Nesta fase gerenciamos os repositórios (nas próximas partes passaremos aos serviços). Nós os declaramos e começamos a criar tabelas:
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 драйвер для СУБД не найден!");
}
}
}
Resultado da execução:
Resumo
Na segunda e terceira partes do artigo aprendemos:- Tipos de dados SQL.
- Tabelas de banco de dados.
- Projetando um banco de dados: estruturas de tabelas e relacionamentos entre elas.
- Linguagem de consulta SQL em termos de criação de tabelas de banco de dados, definição de restrições em campos e relacionamentos entre tabelas.
- Mais sobre interação com JDBC.
- Arquitetura de modelo/repositório/serviço de três camadas (três camadas) de um aplicativo de processamento de dados.
GO TO FULL VERSION