第一部分 第二部分
Java应用程序
三层组织
让我们回到 Java 应用程序。上一部分的版本是以HelloWorld风格创建的,以控制初始操作的正确性。我们实现了三层(三层)架构,在英语文献中通常称为3tier/3layer。其简要实质如下:- 所有实体都被设计为模型。这些对象包含:
- 一组属性(类的私有字段)。
- 构造函数。
- 用于设置/读取属性的 Setter 和 getter。
- 重要的是它们不包含除上述代码之外的任何其他代码。此类对象通常称为POJO(普通旧 Java 对象)。
- 使用模型的所有逻辑均由服务层实现。它为模型生成业务规则。例如,处理来自 Java 应用程序的请求。查询参数和返回的结果通常包括模型(或其集合)。
- Repository层是DBMS和Service之间的“中介”,直接与数据库合作并负责与其交互。
模型
我们所有的实体(股票、交易者、利率和交易者的行为)及其对应的表都有一个共同的特征——人工主键。因此,让我们创建一个基类BaseModel
。所有模型都将从它继承。
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);
}
}
以下是库存模型示例。您可以通过本文末尾的 github 存储库链接查看模型列表的其余部分。
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 的各个阶段如下图所示:Class.forName()
加载该类并将其注册到DriverManager;DriverManager.getConnection()
将返回Connection
– 与方法参数中指定的数据库的连接,并使用相应的 JDBC 驱动程序(使用 加载Class.forName()
)。createStatement()
将返回给我们Statement
一个对象,我们可以根据该对象对数据库进行查询。还有:PreparedStatement
促进参数化和批量查询的创建。
CallableStatement
调用 DBMS 自己的 SQL 函数和过程(它们称为存储)。- 拥有“手中”
statement
将execute()
允许您以 SQL 查询语言命令的形式直接向 DBMS 执行发送请求,并以ResultSet
. 为了方便起见,有:executeQuery()
– 用于从 DBMS 读取数据。
executeUpdate()
– 修改 DBMS 中的数据。 - 服务器响应本身
ResultSet
可以通过迭代first()
、last()
、next()
等形式进行处理。我们可以通过 getter 获取各个结果字段:getInteger()
,getString()
...
ResultSet
,Statement
以Connection
节省资源。请记住,当关闭图中顺序较高的对象时,您将级联关闭在使用该对象的过程中生成的所有对象。因此,关闭连接将导致所有连接Statement
以及ResultSet
在他们的帮助下收到的所有连接的关闭。
存储库的实施
在理论 JDBC 部分之后,让我们继续讨论存储库的实现。我们在架构上实现如下:- 我们将把使用 DBMS 的最通用的部分转移到一个共同的祖先中 -
BaseTable
; - 我们将执行的逻辑操作将在接口中声明
TableOperation
;
BaseTable
并实现该接口TableOperation
。因此,我们需要编写接口中声明的方法的实现TableOperation
。这种情况下,我们可以使用父类的方法BaseTable
。目前,该接口声明了创建表的方法:
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; // создание дополнительных правил для значений полей таблиц
}
当您学习材料时,方法声明列表将会扩展(read()
,update()
……)。我们将分两步实现新功能:
- 让我们以新的接口方法的形式添加另一种使用表的功能。
- 接下来,在实现该接口的类中,我们将在该接口生成的新方法中描述软件实现。
Share
(股票) 的示例存储库。主要逻辑在创建表、指定字段的SQL数据类型以及添加限制的命令中:
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");
}
}
其他存储库和父类的列表可通过本文末尾的 github 存储库链接获得。当然,您可以对程序进行不同的程序设计或更彻底的重构:将公共部分移到父类中,突出显示公共方法等等。但该系列文章的主要目标是直接与数据库打交道,所以如果你愿意的话,你可以设计程序之类的,你可以自己做。当前的项目结构: 除了存储库和模型之外,我们还创建了一个StockExchangeDB
用于仿真的一般管理的类。在此阶段,我们管理存储库(在接下来的部分中,我们将转向服务)。我们声明它们并开始创建表:
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 драйвер для СУБД не найден!");
}
}
}
执行结果:
概括
在文章的 第二部分和第三部分中我们了解到:- SQL 数据类型。
- 数据库表。
- 设计数据库:表结构及其之间的关系。
- SQL查询语言用于创建数据库表、设置字段限制以及表之间的关系。
- 有关与 JDBC 交互的更多信息。
- 数据处理应用程序的三层(三层)模型/存储库/服务架构。
有用的链接
- H2 数据库引擎(英文);
- SQL命令说明(英文);
- H2中的数据类型(英文);
- SQL 保留字列表;
- Martin Graber 着的《Understanding SQL》一书;
- 使用 BigDecimal 的基础知识;
- GitHub 存储库
GO TO FULL VERSION