Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Интерфейсы 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
- Всегда используй 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();
}
// Автоматически закроет все ресурсы
- Используй PreparedStatement вместо Statement
- Управляй транзакциями явно при нужде
- Используй DataSource с пулированием в production
- Помни про SQL-инъекции при использовании строк
JDBC — это фундамент для всех ORM фреймворков, понимание его критично для Java разработчика.