חלק ראשון חלק שני
אפליקציית Java
ארגון 3 שכבות
בואו נחזור לאפליקציית Java. הגרסה מהחלק הקודם נוצרה בסגנון HelloWorld כדי לשלוט בנכונות הפעולות הראשוניות. אנו מיישמים ארכיטקטורה תלת-שכבתית (תלת-שכבתית), אשר בספרות באנגלית נקראת לרוב 3tier/3layer . המהות הקצרה שלו היא כדלקמן:- כל הישויות מעוצבות כמודלים. אלו הם אובייקטים המכילים:
- קבוצה של תכונות (שדות פרטיים של הכיתה).
- קונסטרוקטור(ים).
- מגדירים וגטרים להגדרה/קריאה של תכונות.
- חשוב שהם לא יכילו שום קוד אחר מלבד האמור לעיל. אובייקטים כאלה נקראים לעתים קרובות POJO (Plain Old Java Object).
- כל ההיגיון לעבודה עם מודלים מיושם על ידי שכבת השירות. זה מייצר כללים עסקיים לדוגמניות. לדוגמה, עיבוד בקשות מאפליקציית Java. ארגומנטים של שאילתה ותוצאות שהוחזרו כוללים לרוב מודלים (או אוספים שלהם).
- שכבת המאגר היא "מתווכת" בין ה-DBMS לשירות, עובדת ישירות עם מסד הנתונים ואחראית על האינטראקציה איתו.
דֶגֶם
לכל הישויות שלנו (מניות, סוחרים, שערים ופעולות סוחרים) ולמקבילות הטבלה שלהם יש תכונה משותפת - מפתח ראשוני מלאכותי. לכן, בואו ניצור מחלקת בסיס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
בחלק הראשון למדנו איך ליצור חיבור למסד הנתונים ולסגור אותו. עכשיו בואו נמשיך הלאה. שלבי העבודה עם JDBC מוצגים בתרשים הבא:Class.forName()
טוען את המחלקה ורושם אותה ב-DriverManager;DriverManager.getConnection()
יחזורConnection
- חיבור למסד הנתונים שצוין בארגומנט המתודה ובאמצעות מנהל ההתקן JDBC המתאים (שנטען באמצעותClass.forName()
).createStatement()
יחזיר לנוStatement
אובייקט שעל בסיסו נוכל ליצור שאילתות למסד הנתונים. יש גם:PreparedStatement
הקלה על יצירת שאילתות עם פרמטרים ושאילתות אצווה.
CallableStatement
לקרוא לפונקציות והנהלים של SQL של ה-DBMS (הם נקראים מאוחסנים).- קבלת "ביד"
statement
תאפשרexecute()
לך לשלוח בקשה בצורה של פקודת שפת שאילתה של SQL ישירות לביצוע DBMS ולהחזיר תגובה בצורה שלResultSet
. לנוחות יש:executeQuery()
– לקריאת נתונים מה-DBMS.
executeUpdate()
- כדי לשנות נתונים ב-DBMS. - ניתן לעבד את תגובת השרת עצמו
ResultSet
בצורה על ידי איטרציה דרךfirst()
,last()
,next()
וכן הלאה. אנו יכולים לקבל שדות תוצאות בודדים באמצעות מגברים: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.
- ארכיטקטורת מודל/מאגר/שירות תלת-שכבתי (תלת שכבות) של יישום עיבוד נתונים.
GO TO FULL VERSION