История развития пистолетов-пулеметов: Предпосылкой для возникновения пистолетов-пулеметов послужила давняя тенденция тяготения винтовок...
Двойное оплодотворение у цветковых растений: Оплодотворение - это процесс слияния мужской и женской половых клеток с образованием зиготы...
Топ:
Характеристика АТП и сварочно-жестяницкого участка: Транспорт в настоящее время является одной из важнейших отраслей народного хозяйства...
Техника безопасности при работе на пароконвектомате: К обслуживанию пароконвектомата допускаются лица, прошедшие технический минимум по эксплуатации оборудования...
Марксистская теория происхождения государства: По мнению Маркса и Энгельса, в основе развития общества, происходящих в нем изменений лежит...
Интересное:
Что нужно делать при лейкемии: Прежде всего, необходимо выяснить, не страдаете ли вы каким-либо душевным недугом...
Уполаживание и террасирование склонов: Если глубина оврага более 5 м необходимо устройство берм. Варианты использования оврагов для градостроительных целей...
Берегоукрепление оползневых склонов: На прибрежных склонах основной причиной развития оползневых процессов является подмыв водами рек естественных склонов...
Дисциплины:
2022-10-10 | 55 |
5.00
из
|
Заказать работу |
|
|
Ответ: Понимаете, как там получается. Вот эта строчка, как бы раздваивается, и вы изменения делаете в копии. Внутри 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 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!