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

Можно ли передавать параметры в CallableStatement?

2.0 Middle🔥 131 комментариев
#Другое

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

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

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

Ответ на вопрос о параметрах в CallableStatement

Можно ли передавать параметры в CallableStatement?

Да, можно передавать параметры в CallableStatement несколькими способами. CallableStatement используется для вызова хранимых процедур в БД и поддерживает передачу параметров трёх типов: IN, OUT и INOUT.

Основные типы параметров

1. IN-параметры - передаём значения в хранимую процедуру

CallableStatement cs = connection.prepareCall("{call myProcedure(?)}");
cs.setString(1, "Hello");  // IN-параметр
cs.execute();

2. OUT-параметры - получаем результаты из процедуры

CallableStatement cs = connection.prepareCall("{call myProcedure(?)?}");
cs.registerOutParameter(2, java.sql.Types.INTEGER);
cs.setString(1, "Hello");
cs.execute();
int result = cs.getInt(2);  // Получаем OUT-параметр

3. INOUT-параметры - передаём значение и получаем результат

CallableStatement cs = connection.prepareCall("{call processProcedure(?)}");
cs.setString(1, "input");  // IN часть
cs.registerOutParameter(1, java.sql.Types.VARCHAR);  // OUT часть
cs.execute();
String result = cs.getString(1);  // Получаем результат

Полный пример с IN-параметрами

public class CallableStatementExample {
    public void callProcedureWithParameters(Connection conn) throws SQLException {
        // Синтаксис: {call procedure_name(?, ?, ?)}
        String sql = "{call calculateSum(?, ?, ?)}"; 
        
        try (CallableStatement cs = conn.prepareCall(sql)) {
            // Устанавливаем IN-параметры
            cs.setInt(1, 10);        // Первый параметр (IN)
            cs.setInt(2, 20);        // Второй параметр (IN)
            cs.registerOutParameter(3, java.sql.Types.INTEGER);  // Третий OUT
            
            // Выполняем
            cs.execute();
            
            // Получаем результат
            int result = cs.getInt(3);
            System.out.println("Результат: " + result);
        }
    }
}

Передача различных типов данных

public void parameterTypes(Connection conn) throws SQLException {
    String sql = "{call processData(?, ?, ?, ?, ?, ?)}"; 
    
    try (CallableStatement cs = conn.prepareCall(sql)) {
        // Целые числа
        cs.setInt(1, 100);                      // int
        cs.setLong(2, 9999999999L);             // long
        
        // Дробные числа
        cs.setBigDecimal(3, new BigDecimal("99.99"));  // BigDecimal
        cs.setDouble(4, 3.14);                  // double
        
        // Строки
        cs.setString(5, "Hello World");         // String
        
        // Даты
        cs.setDate(6, java.sql.Date.valueOf("2024-03-22"));
        
        cs.execute();
    }
}

Передача с OUT-параметрами

public void callProcedureWithOutput(Connection conn) throws SQLException {
    String sql = "{call getOrderInfo(?, ?, ?, ?)}"; 
    
    try (CallableStatement cs = conn.prepareCall(sql)) {
        // IN-параметры
        cs.setInt(1, 12345);  // orderId
        
        // OUT-параметры (регистрируем перед выполнением)
        cs.registerOutParameter(2, java.sql.Types.VARCHAR);     // orderStatus
        cs.registerOutParameter(3, java.sql.Types.DECIMAL);    // orderTotal
        cs.registerOutParameter(4, java.sql.Types.VARCHAR);     // customerName
        
        // Выполняем процедуру
        cs.execute();
        
        // Получаем результаты
        String status = cs.getString(2);
        BigDecimal total = cs.getBigDecimal(3);
        String customer = cs.getString(4);
        
        System.out.println("Статус: " + status);
        System.out.println("Сумма: " + total);
        System.out.println("Клиент: " + customer);
    }
}

Именованные параметры (современный подход)

public void namedParameters(Connection conn) throws SQLException {
    // Если БД поддерживает именованные параметры
    String sql = "{call updateUser(firstName => ?, lastName => ?, age => ?)}"; 
    
    try (CallableStatement cs = conn.prepareCall(sql)) {
        cs.setString("firstName", "John");
        cs.setString("lastName", "Doe");
        cs.setInt("age", 30);
        
        cs.execute();
    }
}

Обработка результирующих наборов

public void getResultSet(Connection conn) throws SQLException {
    String sql = "{call getEmployees(?, ?)}"; 
    
    try (CallableStatement cs = conn.prepareCall(sql)) {
        cs.setInt(1, 2024);      // IN-параметр (год)
        cs.registerOutParameter(2, java.sql.Types.INTEGER);  // OUT
        
        cs.execute();
        
        // Обработка результирующего набора
        try (ResultSet rs = cs.getResultSet()) {
            while (rs.next()) {
                System.out.println("ID: " + rs.getInt("id"));
                System.out.println("Name: " + rs.getString("name"));
                System.out.println("Salary: " + rs.getBigDecimal("salary"));
            }
        }
        
        // Получаем OUT-параметр
        int totalCount = cs.getInt(2);
        System.out.println("Всего сотрудников: " + totalCount);
    }
}

Массивы и коллекции (если БД поддерживает)

public void arrayParameters(Connection conn) throws SQLException {
    String sql = "{call processList(?)}"; 
    
    try (CallableStatement cs = conn.prepareCall(sql)) {
        // Если БД (например, Oracle) поддерживает массивы
        Array sqlArray = conn.createArrayOf("VARCHAR", 
            new String[]{"item1", "item2", "item3"});
        cs.setArray(1, sqlArray);
        
        cs.execute();
        sqlArray.free();
    }
}

Обработка NULL значений

public void nullParameters(Connection conn) throws SQLException {
    String sql = "{call process(?, ?, ?)}"; 
    
    try (CallableStatement cs = conn.prepareCall(sql)) {
        cs.setString(1, "data");  // Обычное значение
        cs.setNull(2, java.sql.Types.VARCHAR);  // Явно NULL
        cs.setInt(3, 42);
        
        cs.execute();
    }
}

Проверка NULL в OUT-параметрах

public void checkNullOutput(Connection conn) throws SQLException {
    String sql = "{call getOptionalValue(?)}"; 
    
    try (CallableStatement cs = conn.prepareCall(sql)) {
        cs.registerOutParameter(1, java.sql.Types.VARCHAR);
        cs.execute();
        
        // Проверяем был ли NULL
        String value = cs.getString(1);
        if (cs.wasNull()) {
            System.out.println("Параметр был NULL");
        } else {
            System.out.println("Значение: " + value);
        }
    }
}

Лучшие практики

public class CallableStatementBestPractices {
    
    // ✅ Правильно: используем try-with-resources
    public void goodExample(Connection conn) throws SQLException {
        try (CallableStatement cs = conn.prepareCall("{call proc(?)}")) {
            cs.setString(1, "value");
            cs.execute();
        }  // Автоматически закроется
    }
    
    // ❌ Неправильно: утечка ресурсов
    public void badExample(Connection conn) throws SQLException {
        CallableStatement cs = conn.prepareCall("{call proc(?)}");
        cs.setString(1, "value");
        cs.execute();
        // cs не закрывается
    }
    
    // ✅ Параметризация защищает от SQL-injection
    public void secureProcedure(Connection conn, String userInput) throws SQLException {
        try (CallableStatement cs = conn.prepareCall("{call search(?)}" )) {
            cs.setString(1, userInput);  // Безопасно
            cs.execute();
        }
    }
}

Различия между Statement типами

ТипИспользованиеПараметры
StatementОбычный SQLНет
PreparedStatementПараметризованный SQLIN
CallableStatementХранимые процедурыIN, OUT, INOUT

Резюме

  • Да, параметры передаются - несколькими способами (IN, OUT, INOUT)
  • Синтаксис: {call procedure_name(?, ?, ?)}
  • Установка: setXxx() методы для IN-параметров
  • Получение результата: registerOutParameter() и getXxx() для OUT
  • Типы данных: поддерживает все стандартные Java/SQL типы
  • Безопасность: параметризация защищает от SQL-injection
  • Resource management: всегда используй try-with-resources