Вопрос: А можем ли мы увидеть изменения, которые делаются с помощью этого вызова updateString()? — КиберПедия 

История развития пистолетов-пулеметов: Предпосылкой для возникновения пистолетов-пулеметов послужила давняя тенденция тяготения винтовок...

Двойное оплодотворение у цветковых растений: Оплодотворение - это процесс слияния мужской и женской половых клеток с образованием зиготы...

Вопрос: А можем ли мы увидеть изменения, которые делаются с помощью этого вызова updateString()?

2022-10-10 55
Вопрос: А можем ли мы увидеть изменения, которые делаются с помощью этого вызова updateString()? 0.00 из 5.00 0 оценок
Заказать работу

Ответ: Понимаете, как там получается. Вот эта строчка, как бы раздваивается, и вы изменения делаете в копии. Внутри ResultSetполучается вспомогательная строка и вы ее меняете. Может быть у нее есть одна вспомогательная позиция где эти изменения накапливаются. И если вы перейдете на следующую запись, то я так понимаю, что те изменения по сути мы уже отменили. Как технически это устроено, мы можем только гадать. А можем ли мы прочитать эти данные, которые были изменены? Допустим, пользователь сидел-сидел-сидел, 5 столбцов поменял, потом решил посмотреть, что у него получилось и дальше уже принять решение: «сохранить в БД или отказаться». И вот я, например, посмотрел, что есть в ResultSet, я не нашел возможности указать, что я хочу получить данные не из текущей записи, а вот из той, которая менялась. И как это там все сделано и есть ли такая возможность, навскидку могу сказать, что ее нет. Но это непроверенная информация.

Придется тогда создавать объекты и в нем кэшировать все эти изменения. Но это выглядит как-то странно, потому что там оно уже кэшируется.

packagesql2; importjava.sql.*; publicclassSql2 {   publicstaticvoidmain(String[] args) throwsException { // TODO code application logic here      //ПОДКЛЮЧЕНИЕВЛОБ    //Создаемдрайверсоединения    Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");      String url = "jdbc:sqlserver://10.10.110.21:1433;database=AdventureWorks";      Connection con;    //пишемдрайвер-менеджер    con = DriverManager.getConnection(url, "sa", "1234");    DatabaseMetaData meta = con.getMetaData();      ResultSet res = meta.getTables(null, null, "Pu%", new String[]{"TABLE"});    System.out.printf("List of tables:\n");      while(res.next()){          System.out.printf("%s %s %s %s\n", res.getString(1),res.getString(2), res.getString(3), res.getString(4));    }    Statement st = con.createStatement();    res = st.executeQuery("Select top 10 * from Person.Contact"); while(res.next())    {        System.out.printf("%s %s %s\n", res.getString(4),res.getString(6), res.getString(8));    }      //Create an updatable result set    st = con.createStatement(res.TYPE_SCROLL_SENSITIVE, res.CONCUR_UPDATABLE);      res = st.executeQuery("SELECT top 3 * FROM Person.Contact");      res.last();   //   for(int i = 1; i < 3; i++) //   { //       res.next() //   }      //Move cursor to the row to update      res.updateString(4, "Рамзес");      res.updateString(6, "Жданов");        res.updateRow();      res.cancelRowUpdates();      con.close(); }   }
run: List of tables: AdventureWorks Purchasing PurchaseOrderDetail TABLE AdventureWorks Purchasing PurchaseOrderHeader TABLE Рамзес Жданов [email protected] Ковалев Александр [email protected] Рамзес Жданов [email protected] Зося Шамина [email protected] Георгий Дзгоев [email protected] Алексей Гречкин [email protected] Дмитрий Петрухин [email protected] Валерий Рассадин [email protected] Иван Дёмин [email protected] Дмитрий Захаров Третий способ смены данных СБОРКА УСПЕШНО ЗАВЕРШЕНА (общее время: 0 секунд)

 

Идем дальше… Открываем нормальный 32 слайд, где написано про DML (DataModificationLanguage)

Правильно. У нас есть команды: INSERT, UPDATE, DELETE. Это и есть то, что составляет вместе с SELECTраздел «DML». И здесь не нужно ничего усложнять. Кстати, использование именно этих команд будет намного эффективнее. Вы даже курсор создавать не будете. Ведь вы же обратно ничего не возвращаете. Вы говорите: «Изменить!». И там все меняется. Ресурсы используются намного эффективнее и поэтому, конечно, в основном мы работаем так. Может быть по этой причине, например, Microsoftвообще отказался от серверных курсоров. А то каждый начнет изобретать от себя, а потом начнутся проблемы с производительностью сервера. А мы используем вот эти команды. Это основной наш механизм.

Итак, что здесь меняется? Во-первых, мы сразу должны обратить внимание, что изменилось только следующее. У нас был executeQuery(), а здесь executeUpdate(). Если вы добавляете одну запись и если вам вернули счетчик обновлений «1» и нет Exception, то все нормально. Конечно, такой вариант INSERTочень плох. Все знают, что это никуда не годится. Создавать и склеивать строки, а самое худшее, если мы будем брать данные из сервера и их туда в этот запрос INSERTвклеивать, то мы в общем-то напрашиваемся на SQL-инъекцию.

Вопрос: Вы видели пример SQL-инъекций?

Ответ: Выглядит это примерно так. Представьте себе, что у вас написано, запрос с SELECT + что-то там + WHERE = и пользователь должен передать id.

Пользователь, который уже не пользователь уже в данном случае, он к этой единице цепляет небольшой вагончик, который в этом WHEREделает, что id= 1 + еще там идет логическая операция и возвращается вся таблица. Это безобидная SQL-инъекция. Он просто прочитал вместо одной записи всю таблицу. Но туда же можно и какой-то еще забросить скрипт, который будет работать в SQL так, как вам бы и не хотелось. Так что нам нужно что, чтобы подобным атакам противостоять?Ответ: проверять пользовательский ввод. И очень хорошо, когда мы используем для этого сам ЯП, например, Java. ЯП Javaстрого типизированный. И если вы сделаете не склеиванием строк «WHEREid =»и единицу, как текст туда добавляете, а если вы сделаете параметр целочисленного типа, то сам ЯП в лице компилятора (виртуальная машина) будет проверять, что это целочисленная величина. И вам не нужно будет уже специально писать код. Поэтому вместо этого безобразия нам нужен параметризованный запрос. А интерфейс, который мы сейчас разбирали Statement – это не умеет. Но на наше счастье, есть второй интерфейс, который называется PreparedStatement.

Ну вот здесь я взял какую-то картинку первую попавшуюся.

Ещё одна проблема с тем запросом, который был на предыдущем слайде.

Вопрос: а представьте, что вам нужно так добавить, с помощью такого INSERT, 20000 записей? Это что? Вы каждый раз будете БД говорить: «Вот эту команду выполни». А ведь она как работает? Она должна её прочитать. Понять. Построить дерево запросов. Сделать оптимизацию. Выполнить. И потом так еще 20000 раз? Она, конечно, будет работать, но эффективности-то никакой. А как нужно было сделать? А нужно было один раз выполнить все подготовительные операции, запомнить результат после оптимизации (понять, разобрать, оптимизировать) и в кэше сохранить результат после оптимизации. А потом только выполнить-выполнить-выполнить. Конечно же, производительность будет совсем другая. И ресурсов будет намного меньше тратиться. Но, и это тоже требует каких-то дополнительных с нашей стороны усилий. Вы должны сказать: «вот тебе запрос, подготовь его». И вот это все параметры, предварительно подготовленный запрос – это все часть другого интерфейса, который называется PreparedStatement.

Давайте я сейчас открою Statement. Посмотрите, кто от него наследует?

Что нужно PreparedStatement? Какой новый функционал в нем появляется? Параметры! Нам нужны параметры! У меня на слайде вроде один параметр. Я в документации открыл и вижу, что у них два параметра. Это же совсем другое дело. Причем у них числовые параметры, типизированные! Мы это сразу видим!

Обратите внимание, что вы создаете PreparedStatementестественно с объекта Connection. Помните, что у нас был createStatement() в случае интерфейса Statement, ав случае PreparedStatementбудет prepareStatement(). И вы ставите просто знаки вопроса. Вот там, где должен быть подставлен, при выполнении запроса на сервере, какое-то значение, то вы пишете знак вопроса. Ваш движок, который делает это все на клиенте, он считает «раз» параметр, «два» параметр. И если вы попытаетесь выполнить эту команду и не передадите значение двух параметров, то будет ошибка. Именно в интерфейсе PreparedStatementдобавлены все вот эти методы, начинающиеся с «set». Это позволяет вам задать значение параметра. Они перегружены на все типы данных, какие только есть.

Например:

PreparedStatement ps = con.prepareStatement("UPDATE EMPLOYEES SET SALARY =? WHERE ID =?"); ps.setBigDecimal(1, 153833.00); ps.setInt(2, 110592);

Отгадаличтоэтотакое?Ответ: Номер и параметр.

Читаем в вашем тексте, в котором вы написали, слева направо. Два вопросительных знака, значит два параметра. На слайде один вопросительный знак, значит один параметр. Ну здесь он строковый. Ну здесь строка должна дополнительно проверяться, все-таки это строка. Вот тут уже нужен пользовательский ввод, его нужно детально изучать. Регулярные выражения здесь вам помогут.

Самое важное – это то, что вы этот запрос можете выполнять.

· создать объект PreparedStatement – он уже внутри себя содержит текст.

· отдельно задается параметр

· выполнили.

· все это ушло в БД.

· БД это зафиксирует, и вы можете потом задать другое значение параметра и снова вызвать execute. Еще поменять и снова вызвать execute(). И она уже будет каждый раз выполнять тот запрос с новыми параметрами. Конечно, может быть вам нужно будет 1 раз выполнить, но тогда для вас плюсом будет – это параметризация запроса. Это более безопасный вариант. Ну а если их несколько выполнять, то это вообще шикарно, с т.з. оптимизации.

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

Итак! Последний интерфейс! Чего не хватает, что мы только что разобрали? Параметры – это конечно хорошо. А как хранимые процедуры вызывают? И кто же сегодня пишет запросы и в БД отправляют с SELECT? Это же неудобно очень. А если в БД изменилась бизнес-логика? Вам сказали: «Ой! Ребята! Простите, мы забыли вам сказать, что аудит в каждом действии нужно выполнять». И куда вы этот аудит поместите? А если у нас вся бизнес-логика в хранимых процедурах, автор, тот кто занимается сопровождением БД, откроет хранимые процедуры и в каждую добавит необходимый аудит. Кстати, для вас, скорее всего, это будет недоступная секретная информация, что там происходит какой-то аудит и в какие таблицы это все кладется. Это в общем-то логично с т.з. возможности дальнейшего обновления, безопасности, чтобы меньше народу знало, как устроена БД и т.д.

Да, что я вам про процедуры-то рассказываю? Вы же процедурное программирование знаете с пеленок. Повторное использование кода. Один написал и все пользуются. Периодически в группе попадаются программисты БД и они сразу говорят: «обычным программистам писать SQL-запросы давать нельзя вообще». Потому что они не понимают работу движка, оптимизацию, которую может сделать движок, и они могут все так попортить, что это будет исполняться крайне отвратительно. И если человек специализируется на написании запросов к БД, то это его работа. Вот он ее и выполняет. А мы пишем интерфейсы, фасады и все что угодно.

Ответ из зала: Там даже сопровождающим программистам SELECTне дают писать. Представляют интерфейс. Вот эта таблица обновляется такой-то процедурой, удаляется такой-то процедурой.

Ответ препода: Мы просто даем набор функций. У вас есть вся бизнес-логика, реализованная в хранимых процедурах. Вам их как разработчикам приносят и говорят: «вот тебе 20 хранимых процедур и всё, точка». Черный ящик.

Так вот, если вы хотим вызвать хранимую процедуру, то нам нужен CallableStatement.

Я специально показал вариант, потому что хранимая процедура получает параметры, и она может возвращать результат. Поэтому здесь знак вопроса может быть в начале, в скобках, также через запятую – это собственно параметры, которые мы туда передаем. Вы спросите: «А чем это отличается от предыдущего варианта?». А дело в том, что хранимые процедуры могут быть параметры, которые передаются туда и результат возвращается обратный (так называемый out-параметр). Так вот out-параметры нужно отдельно регистрировать. Поэтому здесь был добавлен в этот интерфейс CallableStatement, к тому что мы видели раньше: набор методов с регистром «out-параметр». Вот из этих параметров допустим, только один out-параметр (первый знак вопроса). А остальные передаются туда. Можно создать много out-параметров. Они могут быть все out-параметрами. Но важно, что out-параметр мы обязаны зарегистрировать. А те, которые туда передаются – для них регистрация не нужна.


Поделиться с друзьями:

Своеобразие русской архитектуры: Основной материал – дерево – быстрота постройки, но недолговечность и необходимость деления...

Кормораздатчик мобильный электрифицированный: схема и процесс работы устройства...

Общие условия выбора системы дренажа: Система дренажа выбирается в зависимости от характера защищаемого...

Особенности сооружения опор в сложных условиях: Сооружение ВЛ в районах с суровыми климатическими и тяжелыми геологическими условиями...



© cyberpedia.su 2017-2024 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!

0.021 с.