← Назад к вопросам

Какие знаешь интерфейсы JDBC?

1.3 Junior🔥 121 комментариев
#Базы данных и SQL

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Интерфейсы JDBC (Java Database Connectivity)

JDBC — это API для взаимодействия с релационными базами данных из Java. Это набор интерфейсов и классов, образующих слой абстракции между приложением и драйвером БД.

Основные интерфейсы JDBC

1. Driver

Отвечает за подключение к конкретной БД. Каждая БД имеет свой Driver.

public interface Driver {
    Connection connect(String url, Properties info) throws SQLException;
    int getMajorVersion();
    int getMinorVersion();
    DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException;
    boolean acceptsURL(String url);
}

// Регистрация драйвера
Class.forName("com.mysql.cj.jdbc.Driver");
// или автоматически (Java 6+):
// DriverManager.getConnection() сам найдет драйвер

2. Connection

Представляет соединение с БД. Создается при помощи DriverManager или DataSource.

public interface Connection {
    Statement createStatement() throws SQLException;
    PreparedStatement prepareStatement(String sql) throws SQLException;
    CallableStatement prepareCall(String sql) throws SQLException;
    void commit() throws SQLException;
    void rollback() throws SQLException;
    void setAutoCommit(boolean autoCommit) throws SQLException;
    boolean getAutoCommit() throws SQLException;
    DatabaseMetaData getMetaData() throws SQLException;
    void close() throws SQLException;
}

// Получение соединения
Connection conn = DriverManager.getConnection(
    "jdbc:mysql://localhost:3306/mydb",
    "root",
    "password"
);

// Или через DataSource (лучше для приложений)
DataSource dataSource = new MysqlDataSource();
dataSource.setURL("jdbc:mysql://localhost:3306/mydb");
dataSource.setUser("root");
dataSource.setPassword("password");
Connection conn = dataSource.getConnection();

// Управление транзакциями
conn.setAutoCommit(false);
try {
    // SQL операции
    conn.commit();
} catch (SQLException e) {
    conn.rollback();
}
finally {
    conn.close(); // Важно закрыть соединение!
}

3. Statement

Используется для выполнения статических SQL запросов без параметров.

public interface Statement {
    ResultSet executeQuery(String sql) throws SQLException;
    int executeUpdate(String sql) throws SQLException;
    boolean execute(String sql) throws SQLException;
    ResultSet getResultSet() throws SQLException;
    int getUpdateCount() throws SQLException;
    void close() throws SQLException;
}

// Пример: SELECT
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM users");
while (rs.next()) {
    int id = rs.getInt("id");
    String name = rs.getString("name");
    System.out.println(id + ": " + name);
}
rs.close();
stmt.close();

// Пример: INSERT/UPDATE/DELETE
Statement stmt = conn.createStatement();
int rowsAffected = stmt.executeUpdate("INSERT INTO users (name) VALUES ('Alice')");
System.out.println("Rows affected: " + rowsAffected);
stmt.close();

Проблема: уязвимость к SQL-инъекциям!

4. PreparedStatement

Предотвращает SQL-инъекции, позволяет использовать параметризованные запросы. Используй это вместо Statement!

public interface PreparedStatement extends Statement {
    void setString(int parameterIndex, String x) throws SQLException;
    void setInt(int parameterIndex, int x) throws SQLException;
    void setDouble(int parameterIndex, double x) throws SQLException;
    void setDate(int parameterIndex, java.sql.Date x) throws SQLException;
    void setTimestamp(int parameterIndex, java.sql.Timestamp x) throws SQLException;
    void setBoolean(int parameterIndex, boolean x) throws SQLException;
    void setNull(int parameterIndex, int sqlType) throws SQLException;
    ResultSet executeQuery() throws SQLException;
    int executeUpdate() throws SQLException;
}

// Правильно: параметризованный запрос
String sql = "SELECT * FROM users WHERE email = ? AND status = ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, "user@example.com");
pstmt.setString(2, "ACTIVE");
ResultSet rs = pstmt.executeQuery();

// Правильно: INSERT с параметрами
String sql = "INSERT INTO users (name, email) VALUES (?, ?)";
PreparedStatement pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
pstmt.setString(1, "Bob");
pstmt.setString(2, "bob@example.com");
int rowsAffected = pstmt.executeUpdate();

// Получить автогенерированный ID
ResultSet generatedKeys = pstmt.getGeneratedKeys();
if (generatedKeys.next()) {
    Long newId = generatedKeys.getLong(1);
    System.out.println("New user ID: " + newId);
}

pstmt.close();

5. CallableStatement

Для вызова stored procedures и functions в БД.

public interface CallableStatement extends PreparedStatement {
    void registerOutParameter(int parameterIndex, int sqlType) throws SQLException;
    void registerOutParameter(int parameterIndex, int sqlType, String typeName) throws SQLException;
    Object getObject(int parameterIndex) throws SQLException;
    String getString(int parameterIndex) throws SQLException;
    int getInt(int parameterIndex) throws SQLException;
}

// Вызов stored procedure
String sql = "{ CALL calculate_discount(?, ?) }"; // ? для параметров
CallableStatement cstmt = conn.prepareCall(sql);
cstmt.setDouble(1, 1000.0); // IN параметр
cstmt.registerOutParameter(2, Types.DOUBLE); // OUT параметр
cstmt.execute();
double discount = cstmt.getDouble(2);
System.out.println("Discount: " + discount);
cstmt.close();

// Вызов function с возвращаемым значением
String sql = "{ ? = CALL get_user_count() }";
CallableStatement cstmt = conn.prepareCall(sql);
cstmt.registerOutParameter(1, Types.INTEGER);
cstmt.execute();
int count = cstmt.getInt(1);
cstmt.close();

6. ResultSet

Представляет результаты запроса. Содержит курсор, указывающий на текущую строку.

public interface ResultSet {
    boolean next() throws SQLException; // Перемещает курсор на следующую строку
    boolean previous() throws SQLException;
    boolean first() throws SQLException;
    boolean last() throws SQLException;
    
    String getString(int columnIndex) throws SQLException;
    String getString(String columnName) throws SQLException;
    int getInt(int columnIndex) throws SQLException;
    double getDouble(String columnName) throws SQLException;
    boolean getBoolean(String columnName) throws SQLException;
    java.sql.Date getDate(String columnName) throws SQLException;
    java.sql.Timestamp getTimestamp(String columnName) throws SQLException;
    
    ResultSetMetaData getMetaData() throws SQLException;
    int getRow() throws SQLException;
    void close() throws SQLException;
}

// Типы ResultSet
// TYPE_FORWARD_ONLY (по умолчанию) — только next()
// TYPE_SCROLL_INSENSITIVE — next(), previous(), first(), last()
// TYPE_SCROLL_SENSITIVE — как выше + видит изменения

Statement stmt = conn.createStatement(
    ResultSet.TYPE_SCROLL_INSENSITIVE,
    ResultSet.CONCUR_READ_ONLY
);
ResultSet rs = stmt.executeQuery("SELECT * FROM users");

// Итерация
while (rs.next()) {
    int id = rs.getInt("id");
    String name = rs.getString("name");
    String email = rs.getString("email");
    java.sql.Timestamp createdAt = rs.getTimestamp("created_at");
}

// Позиционирование
rs.last();
int totalRows = rs.getRow();
rs.first();
String firstUserName = rs.getString("name");

// Метаинформация
ResultSetMetaData metadata = rs.getMetaData();
int columnCount = metadata.getColumnCount();
for (int i = 1; i <= columnCount; i++) {
    System.out.println(metadata.getColumnName(i) + " (" + metadata.getColumnType(i) + ")");
}

7. DatabaseMetaData

Обеспечивает информацию о структуре БД и её возможностях.

public interface DatabaseMetaData {
    String getDatabaseProductName() throws SQLException;
    String getDatabaseProductVersion() throws SQLException;
    String getDriverName() throws SQLException;
    int getDriverMajorVersion();
    ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String[] types) throws SQLException;
    ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException;
    ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException;
    ResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, boolean approximate) throws SQLException;
}

// Использование
DatabaseMetaData metadata = conn.getMetaData();
System.out.println("DB: " + metadata.getDatabaseProductName());
System.out.println("Version: " + metadata.getDatabaseProductVersion());

ResultSet tables = metadata.getTables(null, null, "%", new String[]{"TABLE"});
while (tables.next()) {
    String tableName = tables.getString("TABLE_NAME");
    System.out.println("Table: " + tableName);
}

ResultSet columns = metadata.getColumns(null, null, "users", null);
while (columns.next()) {
    System.out.println(columns.getString("COLUMN_NAME") + " - " + columns.getString("TYPE_NAME"));
}

8. DataSource

Модерный способ получения Connection через пулирование соединений.

public interface DataSource extends CommonDataSource {
    Connection getConnection() throws SQLException;
    Connection getConnection(String username, String password) throws SQLException;
}

// JDBC Connection Pool (встроенный в Java 6+)
HikariCP hikariConfig = new HikariConfig();
hikariConfig.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
hikariConfig.setUsername("root");
hikariConfig.setPassword("password");
hikariConfig.setMaximumPoolSize(20); // Максимум соединений
hikariConfig.setMinimumIdle(5);

HikariDataSource dataSource = new HikariDataSource(hikariConfig);

Connection conn = dataSource.getConnection();
// ... используем
conn.close(); // Возвращает соединение в пул, не закрывает его

dataSource.close(); // Закрыть пул при выключении приложения

Иерархия интерфейсов

Driver → Connection → Statement/PreparedStatement/CallableStatement → ResultSet

Best Practices

  1. Всегда используй try-with-resources:
try (Connection conn = dataSource.getConnection();
     PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM users");
     ResultSet rs = pstmt.executeQuery()) {
    while (rs.next()) {
        System.out.println(rs.getString("name"));
    }
} catch (SQLException e) {
    e.printStackTrace();
}
// Автоматически закроет все ресурсы
  1. Используй PreparedStatement вместо Statement
  2. Управляй транзакциями явно при нужде
  3. Используй DataSource с пулированием в production
  4. Помни про SQL-инъекции при использовании строк

JDBC — это фундамент для всех ORM фреймворков, понимание его критично для Java разработчика.

Какие знаешь интерфейсы JDBC? | PrepBro