Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit fe28aa4

Browse files
Add files and folders SqlAdvancedLess of JDBC Practice.
1 parent de2affb commit fe28aa4

File tree

9 files changed

+792
-0
lines changed

9 files changed

+792
-0
lines changed

‎SqlAdvancedLess/files/train.jpg‎

49.7 KB
Loading[フレーム]
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
db.url=jdbc:postgresql://localhost:5432/flight_repository
2+
db.username=postgres
3+
db.password=testadmin
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
Исследование методов интерфейса DatabaseMetaData:
3+
- *.getCatalogs()
4+
- *.getCatalogs()
5+
- *.getSchemas()
6+
- *.getTables()
7+
8+
Не забываем подключить в настройках
9+
драйвер соединения с базой данных (*.jar),
10+
который лежит в папке 'lib' проекта 'JDBCLessonOne',
11+
иначе словим исключение. Не забываем пометить
12+
папку 'resources', как ресурсную.
13+
*/
14+
15+
import connection_util.ConnectionManager;
16+
17+
import java.sql.*;
18+
19+
public class SQLQueryApp_10 {
20+
21+
public static void main(String[] args) throws SQLException {
22+
/* Тестируем работу методов интерфейса DatabaseMetaData */
23+
checkMetaData();
24+
}
25+
26+
private static void checkMetaData() throws SQLException {
27+
try (Connection connection = ConnectionManager.getBaseConnection()) {
28+
/*
29+
Для работы с метаданными нашей базы данных нам не нужен
30+
интерфейс Statement. Нам нужен интерфейс DatabaseMetaData
31+
и его методы.
32+
33+
С помощью интерфейса Connection и реализации его метода
34+
*.getMetaData() - мы извлекаем объект DatabaseMetaData,
35+
содержащий метаданные о базе данных,
36+
к которой этот объект Connection
37+
представляет соединение.
38+
39+
У нас это база: flight_repository
40+
*/
41+
DatabaseMetaData metaData = connection.getMetaData();
42+
/*
43+
Метод *.getCatalogs() - извлекает имена
44+
каталогов, доступные в этой базе данных.
45+
*/
46+
ResultSet catalogs = metaData.getCatalogs();
47+
/* Перебираем результирующие строки запроса (как Iterator) */
48+
while (catalogs.next()) {
49+
/* Определили имя каталога(ов) с которым(и) будем работать */
50+
String catalog = catalogs.getString(1);
51+
System.out.println("*************************** BASE CATALOGS ***************************");
52+
System.out.println(catalog);
53+
/*
54+
Метод *.getSchemas() - извлекает имена схем, доступные в этой базе данных.
55+
56+
Из документации можно узнать, что мы можем извлечь из ResultSet:
57+
- TABLE_SCHEM String => schema name
58+
- TABLE_CATALOG String => catalog name (may be null)
59+
*/
60+
ResultSet schemas = metaData.getSchemas();
61+
System.out.println("*************************** SCHEMA ***************************");
62+
while (schemas.next()) {
63+
/*
64+
Метод *.getString(String columnLabel) интерфейса ResultSet
65+
возвращает String и извлекает значение указанного столбца
66+
в текущей строке текущего объекта ResultSet в виде строки
67+
на языке программирования Java.
68+
69+
Раннее мы определились, что хотим извлечь TABLE_SCHEM -
70+
имена наших схем в базе.
71+
*/
72+
String schema = schemas.getString("TABLE_SCHEM");
73+
System.out.println("Name of schema: " + schema);
74+
/*
75+
Метод *.getTables(String catalog, String schemaPattern,
76+
String tableNamePattern, String[] types)
77+
интерфейса DatabaseMetaData возвращает ResultSet и извлекает
78+
описание таблиц, доступных в данном каталоге.
79+
80+
С данными аргументами (которыми можно "играть") мы хотим
81+
получить данные из конкретного 'catalog','schema' используя
82+
'%' - мы говорим методу, что все имена. И наконец, последним
83+
аргументом мы показываем, что нас интересуют только "TABLE",
84+
а не: "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY",
85+
"LOCAL TEMPORARY", "ALIAS", "SYNONYM".
86+
*/
87+
ResultSet tables = metaData.getTables(catalog,
88+
schema,
89+
"%",
90+
new String[] {"TABLE"});
91+
/* Извлекаем имена таблиц из двух наших схем */
92+
if (schema.equals("flight_repository") || schema.equals("train_base")) {
93+
System.out.println("***************** TABLE OF '" + schema + "' SCHEMA *****************");
94+
while (tables.next()) {
95+
System.out.println("Table name: " + tables.getString("TABLE_NAME"));
96+
}
97+
System.out.println("********************************************************************");
98+
}
99+
}
100+
}
101+
}
102+
}
103+
}
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
/*
2+
Исследование транзакций SQL операторы:
3+
- COMMIT - фиксирует все изменения для текущей транзакции,
4+
как только COMMIT выполнится, остальным
5+
пользователям будут доступны внесенные изменения.
6+
- ROLLBACK - используется для отмены работы, выполняемой текущей
7+
транзакцией или транзакции, которая сомнительна.
8+
9+
В данном примере мы создадим ситуацию при которой попробуем
10+
удалить связные между таблицами данные и с имитируем проблему,
11+
чтобы отменить изменения.
12+
13+
Не забываем подключить в настройках
14+
драйвер соединения с базой данных (*.jar),
15+
который лежит в папке 'lib' проекта 'JDBCLessonOne',
16+
иначе словим исключение. Не забываем пометить
17+
папку 'resources', как ресурсную.
18+
*/
19+
20+
import connection_util.ConnectionManager;
21+
22+
import java.sql.*;
23+
24+
public class SQLQueryApp_11 {
25+
26+
public static void main(String[] args) throws SQLException {
27+
28+
int del_flightId = load_data_to_base();
29+
30+
/*
31+
Номер рейса для удаления, предварительно
32+
созданный методом *.load_data_to_base()
33+
*/
34+
long flightId = del_flightId;
35+
/* Готовим запросы для удаления данных в формате PreparedStatement */
36+
var deleteFlightSql = "DELETE FROM flight_repository.flight WHERE id = ?";
37+
var deleteTicketsSql = "DELETE FROM flight_repository.ticket WHERE flight_id = ?";
38+
/*
39+
Создаем нулевые соединения и запросы,
40+
которые должны быть доступны в любом
41+
куске кода.
42+
*/
43+
Connection connection = null;
44+
PreparedStatement deleteFlightStatement = null;
45+
PreparedStatement deleteTicketsStatement = null;
46+
47+
try {
48+
/* Инициализация */
49+
connection = ConnectionManager.getBaseConnection();
50+
deleteFlightStatement = connection.prepareStatement(deleteFlightSql);
51+
deleteTicketsStatement = connection.prepareStatement(deleteTicketsSql);
52+
/*
53+
Отключаем в базе AutoCommit, т.е. теперь
54+
все подтверждения запросов вручную.
55+
*/
56+
connection.setAutoCommit(false);
57+
/* Передаем параметры в наши PreparedStatement запросы */
58+
deleteFlightStatement.setLong(1, flightId);
59+
deleteTicketsStatement.setLong(1, flightId);
60+
61+
/*
62+
Когда мы создавали таблицы см. папку base в ConnectLessOne.
63+
Мы таблицу 'flight':
64+
**********************************************************************
65+
CREATE TABLE flight
66+
(
67+
id BIGSERIAL PRIMARY KEY ,
68+
flight_no VARCHAR(16) NOT NULL ,
69+
departure_date TIMESTAMP NOT NULL ,
70+
departure_airport_code CHAR(3) REFERENCES airport(code) NOT NULL ,
71+
arrival_date TIMESTAMP NOT NULL ,
72+
arrival_airport_code CHAR(3) REFERENCES airport(code) NOT NULL ,
73+
aircraft_id INT REFERENCES aircraft (id) NOT NULL ,
74+
status VARCHAR(32) NOT NULL
75+
);
76+
**********************************************************************
77+
привязали к таблице 'ticket', через внешний ключ 'flight_id'
78+
**********************************************************************
79+
CREATE TABLE ticket
80+
(
81+
id BIGSERIAL PRIMARY KEY ,
82+
passenger_no VARCHAR(32) NOT NULL ,
83+
passenger_name VARCHAR(128) NOT NULL ,
84+
flight_id BIGINT REFERENCES flight (id) NOT NULL ,
85+
seat_no VARCHAR(4) NOT NULL,
86+
cost NUMERIC(8, 2) NOT NULL
87+
);
88+
**********************************************************************
89+
И теперь мы можем безболезненно удалить данные из таблицы 'ticket',
90+
а вот данные связные с этой таблицей из таблицы flight мы не можем.
91+
92+
Не сложно заметить, что внешний ключ не имеет дополнительного
93+
ограничения, например:
94+
- ON DELETE CASCADE - означает, что если удаляется запись в
95+
родительской таблице, то соответствующие
96+
записи в дочерней таблице будут удалены
97+
автоматически - каскадное удаление.
98+
- ON DELETE SET NULL - означает, что если запись в родительской
99+
таблице удаляется, то соответствующие поля
100+
в записи дочерней таблице, имеющие foreign
101+
key станут NULL.
102+
*/
103+
deleteTicketsStatement.executeUpdate();
104+
/*
105+
Предыдущий запрос отправил базе команду на удаление
106+
билетов с 10 рейса, текущая строка выводит количество
107+
удаленных строк.
108+
*/
109+
System.out.println("Удалили билетов: " + deleteTicketsStatement.getUpdateCount());
110+
/* Имитируем проблему т.е. ниже программа не пойдет*/
111+
if (true) {
112+
throw new RuntimeException("Имитируем проблему! После которой, вроде бы удаленные, билеты останутся в базе");
113+
}
114+
/*
115+
Пытаемся удалить рейс с номером 10, но вылетит ошибка,
116+
т.к. таблицы связны и данная операция без доп. инструкций
117+
не допустима.
118+
*/
119+
deleteFlightStatement.executeUpdate();
120+
/*
121+
АвтоКоммит отключен и мы делаем подтверждение операций
122+
руками, однако до сюда программа не дойдет
123+
*/
124+
connection.commit();
125+
126+
} catch (Exception e) {
127+
/*
128+
Поскольку мы словили исключение, то нужно отменить
129+
удаление билетов, предварительно проверив соединение
130+
на NULL
131+
*/
132+
if (connection != null) {
133+
connection.rollback();
134+
}
135+
throw e;
136+
} finally {
137+
/*
138+
Поскольку у нас нет блока try-with-resources,
139+
то закрываем все соединения и стайтменты руками.
140+
*/
141+
if (connection != null) {
142+
connection.close();
143+
}
144+
if (deleteFlightStatement != null) {
145+
deleteFlightStatement.close();
146+
}
147+
if (deleteTicketsStatement != null) {
148+
deleteTicketsStatement.close();
149+
}
150+
}
151+
}
152+
/*
153+
Предварительно загрузим в базу немного данных, которые
154+
потом в методе MAIN попробуем удалить.
155+
*/
156+
private static int load_data_to_base(){
157+
int auto_gen_key = 0;
158+
String sql_query_add_flight = """
159+
INSERT INTO flight_repository.flight (flight_no,
160+
departure_date,
161+
departure_airport_code,
162+
arrival_date,
163+
arrival_airport_code,
164+
aircraft_id,
165+
status)
166+
VALUES
167+
('KQ1202', '2021年03月14日T14:30', 'MNK', '2020年06月14日T18:07', 'LDN', 3, 'DEPARTED');
168+
""";
169+
try (Connection my_connect = ConnectionManager.getBaseConnection();
170+
Statement my_statement = my_connect.createStatement()){
171+
my_statement.executeUpdate(sql_query_add_flight, Statement.RETURN_GENERATED_KEYS);
172+
System.out.println("Добавили рейсов: " + my_statement.getUpdateCount());
173+
var generatedKeys = my_statement.getGeneratedKeys();
174+
if (generatedKeys.next()) {
175+
var generatedId = generatedKeys.getInt("id");
176+
System.out.println("Только что добавили рейс с id:" + generatedId);
177+
auto_gen_key = generatedId;
178+
}
179+
String sql_query_add_ticket =
180+
"INSERT INTO flight_repository.ticket " +
181+
"(passenger_no, passenger_name, flight_id, seat_no, cost) " +
182+
"VALUES ('134533', 'Малкольм Стоун', " + auto_gen_key + ", 'A1', 200)," +
183+
"('12434A', 'Санара Куэста', " + auto_gen_key + ", 'B1', 180)," +
184+
"('QQ138D', 'Дуглас Линд', " + auto_gen_key + ", 'B2', 175)," +
185+
"('QY184E', 'Таймус Роддерик', " + auto_gen_key + ", 'C2', 175), " +
186+
"('1OQ2A4', 'Говард Аддингтон', " + auto_gen_key + ", 'D1', 160)," +
187+
" ('SS81M3', 'Амир Ахди', " + auto_gen_key + ", 'A2', 198);";
188+
189+
my_statement.executeUpdate(sql_query_add_ticket);
190+
System.out.println("Добавили билетов: " + my_statement.getUpdateCount());
191+
192+
} catch (SQLException e) {
193+
throw new RuntimeException(e);
194+
}
195+
return auto_gen_key;
196+
}
197+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /