Примеры работы с базой данных PostgreSQL через JDBC.
- CREATE TABLE - Создание таблиц
- INSERT - Вставка данных
- SELECT - Выборка данных
- UPDATE - Обновление данных
- DELETE - Удаление данных
- Работа с JDBC
- Подготовленные запросы (PreparedStatement)
Оператор CREATE TABLE используется для создания новых таблиц в базе данных.
CREATE TABLE table_name ( column1 datatype constraints, column2 datatype constraints, column3 datatype constraints, ... );
CREATE TABLE users ( id SERIAL PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE, email VARCHAR(100) NOT NULL UNIQUE, age INTEGER, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );
Объяснение:
id SERIAL PRIMARY KEY- автоинкрементное поле, первичный ключVARCHAR(50)- строка переменной длины до 50 символовNOT NULL- поле обязательно для заполненияUNIQUE- значения должны быть уникальнымиDEFAULT CURRENT_TIMESTAMP- значение по умолчанию
CREATE TABLE orders ( id SERIAL PRIMARY KEY, user_id INTEGER NOT NULL, product_name VARCHAR(200) NOT NULL, quantity INTEGER DEFAULT 1, total_price DECIMAL(10, 2), order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE );
Объяснение:
FOREIGN KEY- внешний ключ, связь с таблицей usersON DELETE CASCADE- при удалении пользователя удаляются его заказыDECIMAL(10, 2)- число с фиксированной точностью (10 цифр, 2 после запятой)
CREATE TABLE products ( id SERIAL PRIMARY KEY, name VARCHAR(200) NOT NULL, description TEXT, price DECIMAL(10, 2) CHECK (price >= 0), stock_quantity INTEGER DEFAULT 0 CHECK (stock_quantity >= 0), category VARCHAR(50), is_active BOOLEAN DEFAULT true, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );
Объяснение:
CHECK (price >= 0)- проверка, что цена не отрицательнаяTEXT- текст неограниченной длиныBOOLEAN- логический тип (true/false)
Оператор INSERT добавляет новые строки в таблицу.
INSERT INTO table_name (column1, column2, column3, ...) VALUES (value1, value2, value3, ...);
INSERT INTO users (username, email, age) VALUES ('john_doe', '[email protected]', 25);
Объяснение:
- Указываем только нужные поля (id создастся автоматически)
- created_at получит значение по умолчанию
INSERT INTO users (username, email, age) VALUES ('alice_smith', '[email protected]', 30), ('bob_jones', '[email protected]', 28), ('carol_white', '[email protected]', 35);
Объяснение:
- Можно вставить несколько записей за один запрос
- Повышает производительность при массовой вставке
INSERT INTO products (name, price, stock_quantity, category) VALUES ('Laptop', 999.99, 10, 'Electronics') RETURNING id, name;
Объяснение:
RETURNINGвозвращает указанные поля вставленной записи- Полезно для получения сгенерированного id
INSERT INTO orders (user_id, product_name, quantity, total_price) SELECT id, 'Premium Subscription', 1, 99.99 FROM users WHERE username = 'john_doe';
Объяснение:
- Данные для вставки берутся из результата SELECT
- Удобно для копирования/переноса данных
Оператор SELECT используется для извлечения данных из таблиц.
SELECT column1, column2, ... FROM table_name WHERE condition ORDER BY column LIMIT number;
SELECT * FROM users;
Объяснение:
*означает все столбцы- Возвращает все записи из таблицы
SELECT username, email, age FROM users;
Объяснение:
- Указываем только нужные столбцы
- Уменьшает объем передаваемых данных
SELECT username, email FROM users WHERE age >= 25 AND age <= 35;
Объяснение:
WHEREфильтрует записи по условию- Можно использовать
AND,OR,NOT
SELECT * FROM users WHERE email LIKE '%@gmail.com';
Объяснение:
LIKE- поиск по шаблону%- любое количество любых символов_- ровно один любой символ
SELECT username, age FROM users ORDER BY age DESC, username ASC;
Объяснение:
ORDER BYсортирует результатыDESC- по убыванию,ASC- по возрастанию (по умолчанию)- Можно сортировать по нескольким полям
SELECT username, email FROM users ORDER BY created_at DESC LIMIT 10 OFFSET 20;
Объяснение:
LIMIT 10- вернуть максимум 10 записейOFFSET 20- пропустить первые 20 записей- Используется для пагинации
SELECT COUNT(*) as total_users, AVG(age) as average_age, MIN(age) as youngest, MAX(age) as oldest FROM users;
Объяснение:
COUNT()- подсчет записейAVG()- среднее значениеMIN(),MAX()- минимум и максимумasсоздает псевдоним для столбца
SELECT category, COUNT(*) as product_count, AVG(price) as avg_price FROM products WHERE is_active = true GROUP BY category HAVING COUNT(*) > 5 ORDER BY product_count DESC;
Объяснение:
GROUP BYгруппирует записиHAVING- условие для групп (работает после группировки)- Агрегатные функции применяются к каждой группе
SELECT u.username, u.email, o.product_name, o.total_price, o.order_date FROM users u INNER JOIN orders o ON u.id = o.user_id WHERE o.order_date >= CURRENT_DATE - INTERVAL '30 days' ORDER BY o.order_date DESC;
Объяснение:
INNER JOIN- возвращает только совпадающие записиLEFT JOIN- все записи из левой таблицы + совпадения справаON- условие соединенияuиo- алиасы для таблиц
Оператор UPDATE изменяет существующие записи в таблице.
UPDATE table_name SET column1 = value1, column2 = value2, ... WHERE condition;
UPDATE users SET age = 26, email = '[email protected]' WHERE username = 'john_doe';
Объяснение:
- Обновляет возраст и email конкретного пользователя
WHEREгарантирует обновление только нужной записи
UPDATE products SET price = price * 0.9, updated_at = CURRENT_TIMESTAMP WHERE category = 'Electronics' AND stock_quantity > 0;
Объяснение:
- Скидка 10% на электронику в наличии
price * 0.9- использование текущего значения- Обновляется время изменения
UPDATE orders SET total_price = total_price * 1.1 WHERE user_id IN ( SELECT id FROM users WHERE age < 25 );
Объяснение:
- Увеличивает цену заказов для пользователей младше 25
INпроверяет вхождение в список значений из подзапроса
UPDATE products SET price = CASE WHEN stock_quantity = 0 THEN price * 1.2 WHEN stock_quantity < 10 THEN price * 1.1 ELSE price * 0.95 END, updated_at = CURRENT_TIMESTAMP;
Объяснение:
CASE- условная логика в SQL- Разные изменения цены в зависимости от остатка
- +20% если нет в наличии, +10% если мало, -5% если много
UPDATE users SET age = age + 1 WHERE created_at < CURRENT_DATE - INTERVAL '1 year' RETURNING id, username, age;
Объяснение:
- Увеличивает возраст пользователей старше года
- Возвращает обновленные данные
Оператор DELETE удаляет записи из таблицы.
DELETE FROM table_name WHERE condition;
DELETE FROM users WHERE username = 'john_doe';
Объяснение:
- Удаляет конкретного пользователя
- Если есть ON DELETE CASCADE, удалятся связанные заказы
DELETE FROM orders WHERE order_date < CURRENT_DATE - INTERVAL '1 year';
Объяснение:
- Удаляет заказы старше года
- Полезно для очистки старых данных
DELETE FROM orders WHERE user_id IN ( SELECT id FROM users WHERE email LIKE '%@temporary.com' );
Объяснение:
- Удаляет заказы временных пользователей
- Сначала находим id временных пользователей
DELETE FROM products WHERE stock_quantity = 0 AND updated_at < CURRENT_DATE - INTERVAL '6 months' RETURNING id, name, category;
Объяснение:
- Удаляет товары без остатка, не обновлявшиеся 6 месяцев
- Возвращает информацию об удаленных товарах
-- При создании таблицы с ON DELETE CASCADE: CREATE TABLE comments ( id SERIAL PRIMARY KEY, order_id INTEGER NOT NULL, comment_text TEXT, FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE ); -- Удаление заказа автоматически удалит все комментарии: DELETE FROM orders WHERE id = 123;
Объяснение:
ON DELETE CASCADEавтоматически удаляет связанные записи- Альтернативы:
ON DELETE SET NULL,ON DELETE RESTRICT
import java.sql.*; public class DatabaseConnection { private static final String URL = "jdbc:postgresql://localhost:5432/mydb"; private static final String USER = "postgres"; private static final String PASSWORD = "password"; public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } }
public List<User> getAllUsers() { List<User> users = new ArrayList<>(); String sql = "SELECT id, username, email, age FROM users"; try (Connection conn = DatabaseConnection.getConnection(); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql)) { while (rs.next()) { User user = new User(); user.setId(rs.getInt("id")); user.setUsername(rs.getString("username")); user.setEmail(rs.getString("email")); user.setAge(rs.getInt("age")); users.add(user); } } catch (SQLException e) { e.printStackTrace(); } return users; }
public boolean insertUser(String username, String email, int age) { String sql = "INSERT INTO users (username, email, age) VALUES (?, ?, ?)"; try (Connection conn = DatabaseConnection.getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql)) { pstmt.setString(1, username); pstmt.setString(2, email); pstmt.setInt(3, age); int rowsAffected = pstmt.executeUpdate(); return rowsAffected > 0; } catch (SQLException e) { e.printStackTrace(); return false; } }
- Защита от SQL-инъекций
- Повышение производительности (запрос компилируется один раз)
- Автоматическое экранирование специальных символов
// ОПАСНО! Уязвимость SQL-инъекции! String username = request.getParameter("username"); String sql = "SELECT * FROM users WHERE username = '" + username + "'"; // Если username = "admin' OR '1'='1", то будут выбраны все пользователи!
public User findUserByUsername(String username) { String sql = "SELECT * FROM users WHERE username = ?"; try (Connection conn = DatabaseConnection.getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql)) { pstmt.setString(1, username); ResultSet rs = pstmt.executeQuery(); if (rs.next()) { User user = new User(); user.setId(rs.getInt("id")); user.setUsername(rs.getString("username")); user.setEmail(rs.getString("email")); return user; } } catch (SQLException e) { e.printStackTrace(); } return null; }
public void insertMultipleUsers(List<User> users) { String sql = "INSERT INTO users (username, email, age) VALUES (?, ?, ?)"; try (Connection conn = DatabaseConnection.getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql)) { conn.setAutoCommit(false); // Начинаем транзакцию for (User user : users) { pstmt.setString(1, user.getUsername()); pstmt.setString(2, user.getEmail()); pstmt.setInt(3, user.getAge()); pstmt.addBatch(); // Добавляем в пакет } pstmt.executeBatch(); // Выполняем все запросы conn.commit(); // Подтверждаем транзакцию } catch (SQLException e) { e.printStackTrace(); try { conn.rollback(); // Откатываем при ошибке } catch (SQLException ex) { ex.printStackTrace(); } } }
- Java 21+
- PostgreSQL 12+
- Maven 3.9+
mvn testПроект настроен для автоматической сборки и тестирования:
- GitHub Actions:
.github/workflows/maven.yml - GitLab CI:
.gitlab-ci.yml