前編
私たちはシンプルな証券取引所エミュレータの作成を続けています。やることは次のとおりです。
- データベースの組織図を作成してみましょう。
- 何を、どのように、どこに保管するかを説明します。
- データが相互にどのように関連しているかを見てみましょう。
- SQL 言語のデータ定義言語 ( DDL ) である SQL テーブル作成コマンドCREATE TABLEの例を使用して、SQL の基本を学び始めましょう 。
- Java プログラムの作成を続けましょう。JDBC と 3 層アーキテクチャを使用して、プログラムでデータベースを作成するための DBMS の主要な機能を java.sql で実装します。
SQL の基本と DBMS の構成を内部から理解し、Java との類推をする必要があるため、これら 2 つの部分はよりボリュームのあるものであることがわかりました。コードのリストに飽きないよう、最後にプログラムに対応するコミット github リポジトリへのリンクがあります。
DBMS設計
アプリケーションの説明
データ ストレージの整理がプログラミングに不可欠な部分であることはすでに聞いたことがあるでしょう。私たちのアプリケーションの目的は最も単純な交換エミュレーションであることを思い出してください。
- 所定のルールに従って取引日中に価値が変動する可能性がある株式があります。
- 初期資本を持ったトレーダーがいます。
- トレーダーはアルゴリズムに従って株式を売買できます。
交換は
ティック単位、つまり固定時間 (この場合は 1 分) で行われます。ティック中に株価が変化する可能性があり、トレーダーは株式を売買することがあります。
Exchangeエミュレーションデータ構造
個々の交換エンティティをモデルと呼びましょう。丸め誤差を避けるために、クラスを通じて金額を処理します
BigDecimal
(詳細は記事の最後にあるリンクにあります)。各モデルの構造をさらに詳しく説明します。
プロモーション:
属性 |
タイプ |
説明 |
name |
ストリング |
名前 |
changeProbability |
整数 |
各ティックのレート変化の確率をパーセンテージで表したもの |
startPrice |
BigDecimal |
初期費用 |
delta |
整数 |
現在の値が変更できる最大量 (パーセンテージ) |
株価:
属性 |
タイプ |
説明 |
operDate |
ローカル日時 |
レートを設定する時間(ティック) |
share |
プロモーション |
プロモーションへのリンク |
rate |
BigDecimal |
株価 |
トレーダー:
属性 |
タイプ |
説明 |
name |
弦 |
レートを設定する時間(ティック) |
sfreqTick |
整数 |
トランザクションの頻度。トレーダーが操作を実行するまでの期間 (ティック単位) で指定されます。 |
cash |
BigDecimal |
株式以外の金額 |
traidingMethod |
整数 |
トレーダーが使用するアルゴリズム。これを定数として設定しましょう。アルゴリズムの実装は (次の部分で) Java コードになります。 |
changeProbability |
整数 |
操作が完了する確率、パーセンテージ |
about |
弦 |
各ティックにおけるレート変化の確率 (パーセンテージ) |
トレーダーのアクション:
属性 |
タイプ |
説明 |
operation |
整数 |
取引タイプ(買いまたは売り) |
traider |
トレーダー |
トレーダーリンク |
shareRate |
株価 |
株価へのリンク (それぞれ、株式自体、そのレート、発行時刻) |
amount |
長さ |
取引に関与した株式数 |
各モデルの一意性を確保するために、 longid
型の 属性を追加します。
この属性はモデル インスタンス内で一意であり、モデル インスタンスを一意に識別します。他のモデル (トレーダー、株式、株価) を参照する属性は、このモデルを使用して、対応するモデルを一意に識別できます。このようなデータを保存するために使用できるのではないか 、対応するモデルはどこにあるのかという考えがすぐに思い浮かびます。ただし、次の条件下でコードにこれを実装してみてください。
id
Map<Long, Object>
Object
- データ サイズが利用可能な RAM の量を大幅に超えています。
- データへのアクセスは十数の異なる場所から行われることが予想されます。
- データの変更と読み取りを同時に行う機能が必要です。
- データの形成と整合性に関するルールを確保する必要がある。
...そして、適切な資格と実装に時間が必要なタスクに直面することになります。「車輪の再発明」をする必要はありません。私たちのためにすでに多くのことが考えられ、書かれています。したがって、すでに何年にもわたってテストされているものを使用します。
Java でのデータの保存
アクションを考えてみましょう。
Share
Java では、フィールド
name
、
changeProbability
、
startPrice
、を含むこのモデルの特定のクラスを作成しました
delta
。また、多くの共有は として保存されており
Map<Long, Share>
、キーは各共有の一意の識別子です。
public class Share {
private String name;
private BigDecimal startPrice;
private int changeProbability;
private int delta;
}
Map<Long, Share> shares = new HashMap<>();
shares.put(1L, new Share("ibm", BigDecimal.valueOf(20.0), 15, 10));
shares.put(2L, new Share("apple", BigDecimal.valueOf(14.0), 25, 15));
shares.put(3L, new Share("google", BigDecimal.valueOf(12.0), 20, 8));
...
shares.put(50L, new Share("microsoft", BigDecimal.valueOf(17.5), 10,4 ));
ID によって目的のプロモーションにアクセスするには、 メソッドを使用します
shares.get(id)
。名前または価格で株式を検索するタスクでは、すべてのレコードをループして必要なレコードを探します。しかし、ここでは逆に値を DBMS に保存します。
DBMS へのデータ保存
DBMS のデータ ストレージ ルールの初期セットを定式化してみましょう。
- DBMS 内のデータは、レコードのセットであるテーブル ( TABLE ) に編成されます。
- すべてのレコードには同じフィールドのセットがあります。これらはテーブルの作成時に設定されます。
- このフィールドはデフォルト値 ( DEFAULT ) に設定できます。
- テーブルの場合、データの整合性を確保するための要件を記述する制約 ( CONSTRAINT ) を設定できます。これはテーブル作成段階 ( CREATE TABLE )で行うことも、後で追加する ( ALTER TABLE ... ADD CONSTRAINT ) こともできます。
- 最も一般的なCONSTRAINT :
- 主キーは PRIMARY (この場合は ID) です。
- 固有値フィールドUNIQUE (車両テーブルの VIN)。
- CHECKフィールドをチェックします(パーセント値は 100 を超えることはできません)。フィールドに対するプライベート制限の 1 つはNOT NULLまたはNULLで、テーブル フィールドに NULL を格納することを禁止または許可します。
- サードパーティのテーブルFOREIGN KEYへのリンク(株価テーブル内の株式へのリンク)。
- インデックスINDEX (フィールド内の値の検索を高速化するためにフィールドにインデックスを付ける)。
- フィールドの値が制限 (CONSTRAINT) と矛盾する場合、レコードの変更 ( INSERT、UPDATE ) は行われません。
- 各テーブルには、レコードを一意に識別するために使用できるキー フィールド (または複数) を含めることができます。このようなフィールド (複合キーを形成する場合は複数のフィールド) が、テーブルの主キーPRIMARY KEYを形成します。
- 主キーはテーブル内のレコードの一意性を保証し、その上にインデックスが作成され、キー値に基づいてレコード全体に素早くアクセスできるようになります。
- 主キーがあると、テーブル間のリンクを作成するのがはるかに簡単になります。次に、人工主キーを使用します。最初のレコードに対して
id = 1
、後続の各レコードは、ID 値が 1 ずつ増加してテーブルに挿入されます。このキーは、しばしばAutoIncrementまたはAutoIdentityと呼ばれます。
実際、銘柄の表:
この場合、銘柄名をキーとして使用することは可能ですか? 概して、そのとおりですが、一部の企業が別の株式を発行し、それを自社の名前のみで呼んでいる可能性があります。この場合、一意性はなくなります。実際には、人工主キーが頻繁に使用されます。同意します。人の記録を含むテーブルの一意のキーとしてフルネームを使用しても、一意性は保証されません。フルネームと生年月日の組み合わせも使用します。
DBMSのデータ型
他のプログラミング言語と同様に、SQL にはデータ型指定があります。最も一般的な SQL データ型は次のとおりです。
整数型
SQLの種類 |
SQLの同義語 |
Javaでのマッチング |
説明 |
INT |
INT4、整数 |
java.lang.Integer |
4 バイトの整数、-2147483648 … 2147483647 |
ブール値 |
ブール、ビット |
java.lang.Boolean |
真/偽 |
タイイント |
|
java.lang.バイト |
1 バイトの整数、-128 ~ 127 |
スモールント |
INT2 |
java.lang.Short |
2 バイトの整数、-32768 ~ 32767 |
BIGINT |
INT8 |
java.lang.Long |
8 バイトの整数、-9223372036854775808 … 9223372036854775807 |
自動増加 |
インクリメント |
java.lang.Long |
テーブルに固有の増分カウンタ。新しい値が挿入されると 1 ずつ増加し、生成された値が繰り返されることはありません。 |
本物
SQLの種類 |
SQLの同義語 |
Javaでのマッチング |
説明 |
10 進数(N,M) |
12 月、番号 |
java.math.BigDecimal |
固定精度 10 進数 (整数 N 桁と小数 M 桁)。主に財務データを操作するために設計されています。 |
ダブル |
FLOAT8 |
java.lang.Double |
倍精度実数 (8 バイト)。 |
本物 |
FLOAT4 |
java.lang.Real |
単精度実数 (4 バイト)。 |
弦
SQLの種類 |
SQLの同義語 |
Javaでのマッチング |
説明 |
VARCHAR(N) |
NVARCHAR |
java.lang.String |
長さ N の UNICODE 文字列。長さは 2147483647 に制限されます。文字列の内容全体をメモリにロードします。 |
日時
SQLの種類 |
SQLの同義語 |
Javaでのマッチング |
説明 |
時間 |
|
java.time.LocalTime、java.sql.Time |
時刻 (ナノ秒まで) を保存し、DATETIME に変換すると、日付は 1970 年 1 月 1 日に設定されます。 |
日付 |
|
java.time.LocalDate、java.sql.Timestamp |
日付は yyyy-mm-dd 形式で保存され、時刻は 00:00 として設定されます。 |
日付時刻 |
タイムスタンプ |
java.time.LocalDateTime、java.sql.Timestamp |
日付 + 時刻を保存します (タイムゾーンは考慮せず)。 |
大量のデータの保存
SQLの種類 |
Javaでのマッチング |
説明 |
BLOB |
java.io.InputStream、java.sql.Blob |
バイナリ データ (写真、ファイルなど) の保存。 |
クロブ |
java.io.Reader、java.sql.Clob |
大きなテキスト データ (書籍、記事など) を格納する場合は、VARCHAR とは異なり、データを部分的にメモリにロードします。 |
SQLの書き方
多くの言語には、コード形式のガイドラインがあります。通常、このようなドキュメントには、変数、定数、メソッド、その他の言語構造の命名規則が含まれています。したがって、Pythonの場合はPEP8、
Javaの場合は「Oracle Code Conventions for Java」があります。SQL 用にいくつかの異なるセットが作成されていますが、それぞれ若干異なります。いずれにせよ、特にチームで作業している場合は、コードをフォーマットするときにルールに従う習慣を身に付ける必要があります。ルールは、たとえば次のとおりです (もちろん、自分用に別のルールを作成することもできます。重要なのは、将来的にそれらを遵守することです)。
- コマンドや演算子を含むキーワードと予約語は、CREATE TABLE、CONSTRAINT... のように大文字で記述する必要があります。
- テーブル、フィールド、およびその他のオブジェクトの名前は、SQL 言語のキーワードと一致してはなりません (記事の最後にあるリンクを参照) が、これらのキーワードが含まれる場合があります。
- テーブル名はその目的を反映している必要があります。それらは小文字で書かれます。名前内の単語はアンダースコアで区切られます。最後の単語は複数形でなければなりません: traders (トレーダー)、share_rates (シェアレート)。
- テーブルのフィールド名はその目的を反映している必要があります。これらは小文字で書かれ、名前の単語はキャメルケース形式でフォーマットされ、末尾の単語は単数形で使用される必要があります: name (名前)、share_rates (シェアレート)。
- 人工キー フィールドには単語 id が含まれている必要があります。
- CONSTRAINT 名はテーブルの命名規則に従う必要があります。また、それに関連するフィールドとテーブルも含める必要があり、セマンティック プレフィックスで始まります: check_ (フィールド値のチェック)、pk_ (主キー)、fk_ (外部キー)、uniq_ (フィールドの一意性)、idx_ (インデックス)。例: pk_traider_share_actions_id (trader_share_actions テーブルの id フィールドの主キー)。
- SQL を学習すると、ルールのリストが補充/変更されます。
DBMS設計
DBMS を作成する直前に設計を行う必要があります。最終的なスキーマには、テーブル、フィールドのセット、CONSTRAINT、キー、フィールドのデフォルト条件、テーブルと他のデータベース エンティティ間の関係が含まれます。インターネット上では、小規模な DBMS を設計するための無料のオンライン/オフライン デザイナーが数多く見つかります。検索エンジンに「データベース デザイナー 無料」などと入力してみてください。このようなアプリケーションには、次のような便利な追加プロパティがあります。
- SQL コマンドを生成して DBMS を作成できます。
- 設定を図上に視覚的に表示します。
- より見やすくするためにテーブルを移動できます。
- キー、インデックス、関係、デフォルト値などを図上に表示します。
- DBMS スキーマをリモートに保存できます。
たとえば、
dbdiffo.com ではキーが強調表示され、空ではないフィールドと AI (AutoIncrement) カウンターが NN ラベルで表示されます。
DBMS でのテーブルの作成
これで図ができました。次に、テーブルの作成 (CREATE TABLE) に進みます。これを行うには、予備データを用意することをお勧めします。
- テーブル名
- フィールド名とタイプ
- フィールドの制限 (CONSTRAINTS)
- フィールドのデフォルト値 (利用可能な場合)
- 主キー (PRIMARY KEY) (利用可能な場合)
- テーブル間の接続 (FOREIGN KEY)
CREATE TABLE コマンドのすべてのオプションを詳しく学習するわけではありません。トレーダー用のテーブルを作成する例を使用して SQL の基本を見ていきます。
CREATE TABLE traiders(
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
freqTiсk INTEGER NOT NULL,
cash DECIMAL(15,2) NOT NULL DEFAULT 1000,
tradingMethod INTEGER NOT NULL,
changeProbability INTEGER NOT NULL DEFAULT 50,
about VARCHAR(255) NULL
);
ALTER TABLE traiders ADD CONSTRAINT check_traiders_tradingMethod
CHECK(tradingMethod IN (1,2,3));
ALTER TABLE traiders ADD CONSTRAINT check_traiders_changeProbability
CHECK(changeProbability <= 100 AND changeProbability > 0)
詳しく見てみましょう:
CREATE TABLE traiders
(フィールドの説明) - 指定された名前でテーブルを作成します。説明では、フィールドはカンマで区切られます。すべてのコマンドはセミコロンで終わります。
- フィールドの説明は名前で始まり、そのタイプ、CONSTRAINT、デフォルト値が続きます。
id BIGINT AUTO_INCREMENT PRIMARY KEY
– 整数型の id フィールドは主キーと増分カウンターです (id フィールドの新しいレコードごとに、このテーブルに対して以前に作成された値より 1 大きい値が生成されます)。
cash DECIMAL(15,2) NOT NULL DEFAULT 1000
– 現金フィールド、10 進数、小数点の前 15 桁、小数点以下 2 桁 (ドルとセントなどの財務データ)。NULL 値は受け入れられません。値が指定されていない場合は、値 1000 が取得されます。
about VARCHAR(255) NULL
– about フィールドは、最大 255 文字の長さの文字列で、空の値を受け入れることができます。
テーブルの作成後にCONSTRAINT条件の一部を設定できること に注意してください。テーブル構造とそのフィールドを変更するための構造を考えてみましょう:
ALTER TABLE table_name ADD CONSTRAINT制約_name CHECK (条件)例を使用します。
CHECK(tradingMethod IN (1,2,3))
– tradeMethod フィールドは値 1、2、3 のみを取ることができます
CHECK(changeProbability <= 100 AND changeProbability > 0)
–changeProbabilityフィールドは1から100の範囲の整数値を取ることができます
テーブル間の関係
テーブル間の関係の説明を分析するために、share_rates の作成を見てみましょう。
CREATE TABLE share_rates(
id BIGINT AUTO_INCREMENT PRIMARY KEY,
operDate datetime NOT NULL,
share BIGINT NOT NULL,
rate DECIMAL(15,2) NOT NULL
);
ALTER TABLE share_rates ADD FOREIGN KEY (share) REFERENCES shares(id)
別のテーブルの値への参照は、次のように設定できます。
ALTER TABLE
table_from_that_referred
ADD FOREIGN KEY
(field_that_referred)
REFERENCES
table_to_that_referred (field_that_referred to)
株式に株式に関するレコードがあるとします。たとえば、id=50 の場合、Microsoft 株式を初期価格で保存します。 17.5、デルタは 20、変化の可能性は 4% です。
share_ratesテーブルでは、次の 3 つの主要なプロパティを取得します。
- 残りの情報 (名前など) を share テーブルから取得するために使用するには、shares テーブルの id キーの値のみを share フィールドに保存する必要があります。
- 存在しないプロモーションの料金を作成することはできません。テーブル間には対応関係がないため、存在しない値を共有フィールド (この ID を持つ共有テーブルにレコードが存在しない) に挿入することはできません。
- share_rates でレートが設定されている株式の株式エントリーを削除することはできません。
最後の 2 つのポイントは、保存されたデータの整合性を保証するために役立ちます。この記事の最後にある github リポジトリへのリンクを使用して、エミュレーションの SQL テーブルの作成と、対応するクラスのメソッドの Java 実装での SQL クエリの例を確認できます。
第三部
GO TO FULL VERSION