Skip to the content.

Технологии программирования

Назад на главную

Работа с sql-базами данных из приложений на java. Миграции баз данных.

JDBC

JDBC - Java Database Connectivity

JDBC - это API для подключения и выполнения запросов к базе данных. JDBC может работать с любой базой данных, если предоставлены надлежащие драйверы.

Чтобы подключиться к базе данных нам нужен драйвер для этой базы данных. Его нужно добавить в зависимости и зарегистрировать.

Мы можем сделать это легко, добавив его в уже известные нам зависимости gradle, найдя нужную зависимость в репозитории maven Например, для postgresql:

dependencies {
    implementation 'org.postgresql:postgresql:42.3.8'
}

Для подключения к базе необходимо создать соединение, указав строку подключения:

public class Example {
    public static void main(String[] args) {
        Class.forName("org.postgresql.Driver");
        
        try (Connection con = DriverManager.getConnection("jdbc:postgresql://localhost:5432/myDb", "user1", "pass")) {
            // use con here
        }
    }
}

Statement

Для выполнения инструкций SQL необходимо создать Statement. В контексте JDBC (Java Database Connectivity), Statement представляет собой интерфейс, который используется для выполнения SQL-запросов к базе данных. Это основной инструмент для взаимодействия с базой данных, позволяющий выполнять различные типы запросов, включая простые запросы SELECT, INSERT, UPDATE, DELETE, а также более сложные запросы, требующие параметров.

Существует три основных типа Statement:

Создание объекта Statement обычно происходит после установления соединения с базой данных. Например, для создания объекта Statement можно использовать метод Connection.createStatement().

public class Example {
    public static void main(String[] args) {
        Class.forName("org.postgresql.Driver");

        try (Connection con = DriverManager.getConnection("jdbc:postgresql://localhost:5432/myDb", "user1", "pass")) {
            try (Statement stmt = con.createStatement()) {
                String tableSql = "CREATE TABLE IF NOT EXISTS employees"
                        + "(emp_id int PRIMARY KEY AUTO_INCREMENT, name varchar(30),"
                        + "position varchar(30), salary double)";
                int affectedLinesCount = stmt.execute(tableSql);

                String insertSql = "INSERT INTO employees(name, position, salary)"
                        + " VALUES('john', 'developer', 2000)";
                stmt.executeUpdate(insertSql); // для добавления записей используем метод executeUpdate


                String selectSql = "SELECT * FROM employees";
                // для добавления данных используем executeQuery
                try (ResultSet resultSet = stmt.executeQuery(selectSql)) {
                    Employee emp = new Employee();
                    emp.setId(resultSet.getInt("emp_id"));
                    emp.setName(resultSet.getString("name"));
                    emp.setPosition(resultSet.getString("position"));
                    emp.setSalary(resultSet.getDouble("salary"));
                    employees.add(emp);
                }
            }
        }
    }
}

PreparedStatement

PreparedStatement в контексте JDBC (Java Database Connectivity) – это интерфейс, который наследуется от базового интерфейса Statement и используется для выполнения SQL-запросов с параметрами. Это мощный инструмент, который позволяет повысить безопасность и производительность при работе с базой данных.

Основное отличие PreparedStatement от обычного Statement заключается в том, что в первом можно использовать параметры, которые передаются в запрос при выполнении. Это позволяет избежать SQL-инъекций, так как параметры автоматически экранируются, и делает запросы более читаемыми и удобными в обслуживании

Для создания объекта PreparedStatement используется метод Connection.prepareStatement(String sql) или Connection.prepareStatement(String sql, int resultSetType, int resultSetConcurrency), где sql – строка с SQL-запросом, содержащим параметры.

После создания объекта PreparedStatement параметры задаются с помощью методов setXXX(int parameterIndex, XXX value), где XXX – тип параметра (например, setString, setInt, setFloat и т.д.), а parameterIndex – индекс параметра в запросе.

public class Example {
    public static void main(String[] args) {
        Class.forName("org.postgresql.Driver");
        
        try (Connection con = DriverManager.getConnection("jdbc:postgresql://localhost:5432/myDb", "user1", "pass")) {
            String updatePositionSql = "UPDATE employees SET position=? WHERE emp_id=?";
            try (PreparedStatement pstmt = con.prepareStatement(updatePositionSql)) {
                pstmt.setString(1, "lead developer");
                pstmt.setInt(2, 1);

                int rowsAffected = pstmt.executeUpdate();
            }
        }
    }
}

Как масштабировать приложение с реляционной базой данных?

Масштабирование приложения с реляционной базой данных означает увеличение его способности обрабатывать растущий объем данных и запросов без потери производительности. Есть два основных подхода к масштабированию: вертикальная и горизонтальная масштабируемость.

Вертикальная масштабируемость подразумевает увеличение мощности существующего сервера путем добавления большего количества ресурсов, таких как процессор, память, диск. Это может быть эффективным решением для небольших и средних приложений, но имеет свои ограничения, когда дело доходит до больших объемов данных и высокой нагрузки.

Горизонтальная масштабируемость достигается путем добавления дополнительных серверов для распределения нагрузки. Это позволяет приложению обрабатывать больше запросов одновременно, делая его более устойчивым к высоким нагрузкам. Горизонтальная масштабируемость включает в себя два основных метода: репликацию и шардирование.

Репликация

Репликация – это процесс копирования и размещения идентичной информации на разных серверах. Существует два типа серверов: master и slave. Master – основной сервер, в который записывается новая информация или изменяется имеющаяся, slave служит для копирования информации с мастера и её чтения. При репликации создается большое количество копий данных, что обеспечивает высокую доступность и отказоустойчивость системы.

Шардирование баз данных

Шардирование (или шардинг) – это метод горизонтального масштабирования, при котором данные распределяются между различными физическими серверами. Разные части таблиц базы данных могут храниться на разных серверах. Это позволяет эффективно обрабатывать большие объемы данных и запросы, распределяя нагрузку между несколькими серверами.

Миграции баз данных

Миграция баз данных — это что-то вроде системы контроля версий для вашей схемы базы данных. Она позволяет разработчикам изменять структуру БД, сообщать другим участникам команды об этих изменениям и самим быть в курсе апдейтов, а также отслеживать историю изменений.

В java-приложениях чаще всего используют инструменты

Рассмотрим Liquibase

dependencies {
    implementation 'org.liquibase:liquibase-core:4.10.0'
}

Создадим в папке с ресурсами файл с ченджсетом src/main/resources/db/changelog/changelog.xml

<databaseChangeLog
       xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog">
   <changeSet id="create_table_genre" author="mediaSoft">
        <!-- Прописываем создание таблицы genre&ndash;-->
       <createTable tableName="genre">
        <!--Создаем поля -->
           <column autoIncrement="true" name="genre_id" type="bigint">
               <constraints primaryKey="true" nullable="false"/>
           </column>
           <column name="genre_name" type="varchar(64)">
               <constraints nullable="false" unique="true"/>
           </column>
       </createTable>
   </changeSet>
</databaseChangeLog>
<changeset author="mueller@synyx.de" id="2"> 
  <sql> 
    UPDATE Person SET firstname = SUBSTRING_INDEX(name, ' ', 1); 
    UPDATE Person SET lastname = SUBSTRING_INDEX(name, ' ', -1); 
  </sql> 
  <rollback> 
    UPDATE Person SET firstname = ''; 
    UPDATE Person SET lastname = ''; 
  </rollback> 
</changeset>
liquibase init project --format=xml

liquibase --url=jdbc:h2:tcp://localhost:9090/mem:integration update
liquibase rollback --tag=myTag --changelog-file=example-changelog.xml

Полезные ссылки