Страницы

Поиск по вопросам

понедельник, 15 октября 2018 г.

Подстановка параметра PreparedStatement в JDBC Oracle

Столкулся с тем, что данная конструкция подстановки параметра (:1) работает с драйвером Oracle:
try { Class.forName("oracle.jdbc.driver.OracleDriver"); try (Connection con = DriverManager.getConnection("HOST", "USER", "PASS")) { try (PreparedStatement preparedStatement = con.prepareStatement("select * from TABLE where name = :1")) { preparedStatement.setString(1, "NAME"); try (ResultSet resultSet = preparedStatement.executeQuery()) { while (resultSet.next()) { System.out.println(resultSet.getObject(1)); } } } } } catch (Exception e) { e.printStackTrace(); }
В JSR указано использование только знака ?. Это особенность реализации драйвера?
UPD:
Версия БД: Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production PL/SQL Release 12.1.0.2.0 - Production
Что замечено еще:
try (PreparedStatement preparedStatement = con.prepareStatement("select * from TABLE where name = :abc and id = :dcf")) { preparedStatement.setString(1, "PARAM"); preparedStatement.setInt(2, 173); try (ResultSet resultSet = preparedStatement.executeQuery()) { while (resultSet.next()) { System.out.println(resultSet.getObject(1)); } } }
просьба обратить внимание на название подстановок, этот код работает. А вот этот уже не работает:
try (PreparedStatement preparedStatement = con.prepareStatement("select * from TABLE where name = :abc and id = :dcf")) { preparedStatement.setString(2, "NAME"); preparedStatement.setInt(1, 173); try (ResultSet resultSet = preparedStatement.executeQuery()) { while (resultSet.next()) { System.out.println(resultSet.getObject(1)); } } }
java.sql.SQLSyntaxErrorException: ORA-01722: неверное число
То есть на название вообще нет реакции, только на ":" порядок.


Ответ

В JSR указано использование только знака ?.
Символ ? это ещё не подстановочный параметер, это только местозаполнитель (placeholder), все символы-местозаполнители функция prepareStatement() заменит на подстановочные переменные (или переменные связывания (bind variables)) используя синтаксис для подстановочных переменных целевой СУБД.
Если в SQL выражении указать подстановочные параметры сразу в том виде, в котором на целевой СУБД выполнится подготовка и компиляция (parse), то функция prepareStatement() не призведёт никакой замены и не заметит, что её "лишили работы".
Это особенность реализации драйвера?
Да, или лучше сказать - это особенность целевой СУБД, которую этот драйвер поддерживает. Касательно подстановочных переменных, различные СУБД имеют различный синтаксис этих переменных:
Oracle: :var (colon) MySQL, DB2 and Firebird: ? (question marks) Sybase, MS SQL Server: @var (at sign) PostgreSQL: $var (dollar sign)
Для подтверждения вышесказанного, рассмотрим следующий пример.
Выполним один и тот же запрос несколько раз с различным использованием местозаполнителей и подстановочных параметеров:
create or replace and compile java source named TestPrepared as import java.sql.*; public class TestPrepared { public static void selectValue (int id, String item) { String[] stmts = { /*#1*/"/* ? */ select id, item from items where id = ? and item = ?", /*#2*/"/* ? */ select id, item from items where id = :1 and item = :2", /*#3*/"/* ? */ select id, item from items where id = :2 and item = :3", /*#4*/"/* ? */ select id, item from items where id = :id and item = :item"}; try { Connection con = DriverManager.getConnection("jdbc:oracle:thin:@dbsrv:1521/pdb1","sh","sh"); for (int i=0; iДа, в JDBC стандарте важен только порядок (bind by index). В коде вопроса, к которому эта цитата относится, порядок нарушен, что привело к ошибке. В расмотренном выше примере, замена произведена учитывая только порядок (т.е. по индексу), какие имена/номера стояли после символа не сыграло никакой роли.
Если интересна подстановка по имени (bind by name), то как упомянуто в оф. документации гл. Binding by name
This capability to bind by name using the setXXX methods is not part of the JDBC specification, and Oracle does not support it.
Oracle не поддерживает подстановку по имени при использовании метода, как в вопросе, setString(). То есть в стандартном JDBC интерфейсе PreparedStatement это не поддерживается.
Но можно воспользоваться, например, расширением к этому интерфейсу OraclePreparedStatement
create or replace and compile java source named TestPreparedOra as import java.sql.*; import oracle.jdbc.*; public class TestPreparedOra { public static void selectValue (int id, String item) { try { Connection con = DriverManager.getConnection("jdbc:default:connection"); OraclePreparedStatement ps = (OraclePreparedStatement) con.prepareStatement ( "select id, item from items where item = :item and id = :id"); ps.setStringAtName("item", item); ps.setIntAtName( "id", id); ResultSet resultSet = ps.executeQuery(); while (resultSet.next()) { System.out.println("id=" + resultSet.getObject(1) + ",item=" + resultSet.getObject(2)); } } catch (Exception e) { e.printStackTrace(); } } } / create or replace procedure selectValueOraEx (id number, item varchar2) as language java name 'TestPreparedOra.selectValue (int, java.lang.String)'; / exec selectValueOraEx (2, 'item2')
PL/SQL procedure successfully completed.
id=2,item=item2

Комментариев нет:

Отправить комментарий