Как стать автором
Обновить

Комментарии 235

Запрос:


В теле запроса допущена опечатка (намеренно), в имени поля us_last пропущена буква "s"

Сообщение об ошибке:


нулевое значение в столбце "us_last" нарушает ограничение NOT NULL

А если бы не было ограничения NOT NULL на этой колонке?

Контроль значения поля можно добавить в явном виде, например так
if (us_last == null) throw new RestException("RST0100E", new Object[] {"us_last"}, lang);


см метод inset класса TestQuery.java

Я повторю свой вопрос: что будет с тем же самым запросом, если в БД нет ограничения NOT NULL?


см метод inset класса TestQuery.java

Я что-то не понимаю. У вас универсальный сервис (т.е., тот, который не надо править при изменении структуры БД), или не универсальный (т.е., его надо править под структуру БД)?

Совершенно верно, универсальный. Пример, который Вас заинтересовал — это пример реализации расширения функциональности сервиса. Контроль параметров в этом случае обеспечивается самой реализацией этого расширения.

Тогда вернемся к предыдущему вопросу: что будет с тем же самым запросом, если в БД нет ограничения NOT NULL (и если сервис никак не "расширяли")?

Возникнет ошибка выполнения SQL запроса с сообщением, что поле us_lat не существует.

А почему SQL-запрос в примере при этом выглядит вот так: INSERT INTO rp.users (us_name, us_last, us_email) VALUES (?, ?, ?)? Где там поле us_lat?

Сервис генерирует запрос по полученным параметрам, параметра us_last нет в параметрах запроса, а запрос


INSERT INTO rp.users (us_name, us_lat, us_email) VALUES (?, ?, ?)


выполнится с ошибкой

Сервис генерирует запрос по полученным параметрам

Что-то не сходится.


Вот тело HTTP-запроса из вашего примера:


[{"us_name":"3", "us_lat":"333", "us_email":"333@domain.ru"}]

Вот сообщение об ошибке из того же примера:


[24344@likhovskikh-vv] SYS0250E При вызове метода "execute" возникла ошибка.
Ошибка: "ru.funsys.avalanche.sql.SQLException: [24344@likhovskikh-vv] SQL0021E При выполнении запроса произошла ошибка. Номер запроса: 0, запрос: INSERT INTO rp.users (us_name, us_last, us_email) VALUES (?, ?, ?).
org.postgresql.util.PSQLException: ОШИБКА: нулевое значение в столбце "us_last" нарушает ограничение NOT NULL
Подробности: Ошибочная строка содержит (3 , null, 333@domain.ru )."

Там явно приведен SQL-запрос:


INSERT INTO rp.users (us_name, us_last, us_email) VALUES (?, ?, ?)

us_lat, который есть в HTTP-запросе, там нет. us_last, которого нет в HTTP-запросе, там есть.


Как так получается?

Вы путаете два разных запроса. Обращаю ваше внимание на пример, который Вас заинтересовал — это пример расширения функциональности это сервиса! В этом случае контроль полученных параметров осуществляется в самой реализации расширения.


Для вставки записи/записей самим сервисом нужно указать другой URL запроса .../data/table/rs.users. В этом случае сервис генерирует SQL запрос по полученным параметрам, выполнение которого при указанной опечатке в имени поля завершиться с ошибкой.


В заинтересовавшем Вас примере указан URL .../data/query/TestQuery.insert.

В заинтересовавшем Вас примере указан URL .../data/query/TestQuery.insert.

Тогда вернемся к предыдущему вопросу: что будет с тем же самым запросом, если в БД нет ограничения NOT NULL (и если сервис никак не "расширяли")?


(я хочу заметить, что этот диалог — это типичный пример того, что будет в голове разработчика, которому надо будет интегрироваться с этим сервисом)

Тот же самый запрос без использования расширения


Запрос:


POST /restdb/rs/data/table/rs.users HTTP/1.1
Accept: application/json
Content-Language: ru
Content-Length: 61
Host: localhost:8080
Content-Type: application/json

[{"us_name":"3", "us_lat":"333", "us_email":"333@domain.ru"}]

Ответ: (HTTP Status 400)


{
"message": "При выполнении оператора INSERT возникла ошибка.",
"code": "RST0003E",
"cause": "[30648@likhovskikh-vv] SYS0250E При вызове метода \"execute\" возникла ошибка.\n\tОшибка: \"ru.funsys.avalanche.sql.SQLException: [30648@likhovskikh-vv] SQL0019E При компиляции запроса произошла ошибка. Номер запроса: 0, запрос: INSERT INTO rp.users (us_lat, us_name, us_email) VALUES (?, ?, ?).\r\n\torg.postgresql.util.PSQLException: ОШИБКА: столбец \"us_lat\" в таблице \"users\" не существует\n Позиция: 23\""
}

Сгенерированный SQL запрос и возникшая ошибка (из лога без стека вызовов)


12:08:52.541 [http-nio-8080-exec-6] INFO   - SQL0010I Запрос: -1815764162 - INSERT INTO rs.users (us_lat, us_name, us_email) VALUES (?, ?, ?)
12:08:52.549 [http-nio-8080-exec-6] ERROR  - ru.funsys.avalanche.sql.SQLException: [30648@likhovskikh-vv] SQL0019E При компиляции запроса произошла ошибка. Номер запроса: 0, запрос: INSERT INTO rs.users (us_lat, us_name, us_email) VALUES (?, ?, ?).
Тот же самый запрос без использования расширения

Это не тот же запрос.

Первый, приведенный в статье, использует расширения функциональности.


Второй, приведенный выше, использует универсальный сервис.


Оба эти запроса выполняют одно и тоже, вставляют одну и ту же запись в таблицу.


Еще остались вопросы?

Да.


Как поведет тот же самый запрос, если сервис не был расширен?

В ответ #comment_21245044


приведен пример того же самого запроса, без расширения функциональности.

Это другой запрос. А я спрашиваю, что будет с тем же самым.

С "тем же самым" другого варианта быть не может. "Тот же самый" вызывается только как функция расширения универсального сервиса.


Вы задали вопрос, как поведет себя универсальный сервис, если подобная ошибка (опечатка в имени поля) будет допущена при его вызове. Я вам привел ответ на этот вопрос "тот же самый запрос" — вызов через универсальный сервис без расширения функциональности. См. ответ #comment_21245044


Еще есть вопросы?

С "тем же самым" другого варианта быть не может.

Что значит "не может"? Что мешает клиенту послать такой запрос?

Правила формирования URI запроса.


.../data/table/… — запрос на модификацию БД через универсальный сервис


.../data/query/… — запрос на модификацию, определенную в методе класса расширения

И что? Был у вас клиент, слал запросы, потом на сервере убрали расширение. Что случится?

Будет ошибка, как и в любой другой реализации REST сервиса, если в этой реализации "убить" какой то метод.


Реализация сервиса описанная в статье вернет ошибку
"RST0021E" — Имя метода класса генератора SQL запроса не определено.

Очень. Удобно.


(Я даже не буду спрашивать, почему это REST)

Совершенно верно, именно удобно. В других реализациях вам прилетит 500 ошибка и куча HTML "мусора", когда Вы ожидаете JSON или XML.

Не знаю, я не пользуюсь такими реализациями. Обычно прилетает 404.

Хорошо, прилетит 404 ошибка, но она все равно будет содержать кучу HTML "мусора". И чтобы добраться до "причины" Вам нужно "ковырять" этот "мусор".


Этот сервис вернет 404 ошибку и причину ошибки в том формате, который вы ожидаете.

Хорошо, прилетит 404 ошибка, но она все равно будет содержать кучу HTML "мусора".

Да нет, не будет. Будет там обычный content negotiation.


Этот сервис вернет 404 ошибку и причину ошибки в том формате, который вы ожидаете.

Неа. Он вернет ее в том content-type, который я запросил (если он его умеет), и в том формате, который он поддерживает.

Ваши реализации сервисов то же не все форматы поддерживают. Да и поддерживать все, какой вздумается, в принципе невозможно.

Поэтому полезно разделять "вернем ошибку в ожидаемом формате" и "вернем ошибку в поддерживаемом формате".

В данном случае, формулировка не существенна — HTML "мусор" точно не ожидается.

Ну, я как бы уже сказал — вы его в нормальной реализации и не получите, ничего уникального в конкретно вашей с этой точки зрения нет.

А почему прилетит куча HTML мусора? Мне непонятно

Потому что запрошенный URL, если он был удален в вашем сервисе, не будет связан вообще ни с одним вашим ресурсом REST. Этот запрос обработает WEB сервер, который и возвратит этот "мусор". Хорошо, если в него ("мусор") будет включена хоть какая то полезная для Вас информация. А если Вы не сможете найти там внятной информации? А если этот "мусор" без внятной информации получит пользователь, что он должен сообщить в техподдержку — " У меня тут ошибка какая то"?

Потому что запрошенный URL, если он был удален в вашем сервисе, не будет связан вообще ни с одним вашим ресурсом REST. Этот запрос обработает WEB сервер, который и возвратит этот "мусор".

С чего бы это?

Что гадать то, проведите эксперимент.

Чего эксперимент-то проводить, я постоянно с этим работаю.


404 Not Found
Content-Type: application/json
{
  "message": "The path you have requested was not found"
}

А все потому, что "сервис" висит на "корневом" ресурсе, и поэтому все запросы все равно проходят через него, хостящий веб-сервер про внутреннюю структуру и не знает ничего.

И что говорит вам это "информативное" сообщение? Не найдено что, ресурс, запись или что то еще? А что скажет это "информативное" сообщение техподдержке, если пользователь передаст ей это сообщение? А если оно прилит Вам от техподдержки — какие выводы Вы по нему сделаете?

И что говорит вам это "информативное" сообщение?

Ровно то, что положено.


Не найдено что, ресурс, запись или что то еще?

Ресурс, конечно. Это же REST.


Речь шла о том, что сервис вернет HTML-мусор. Как видите, не вернет, даже в ответ на мусорный URL.


Если послать запрос на не-случайный URL, ошибка будет тоже менее генеричной:


404 Not Found
Content-Type: application/json
{
  "message": "The model azure-01 was not found"
}

Это, в общем-то, совершенно тривиальные вещи, удивительно, что их вообще озвучивать надо.

Это для Вас они тривиальные, а для техподдержки и пользователей — это ничто! Ну скажут они Вам код 404. Далее что будете делать? Где в вашей системе будете искать ошибку по этому информативному коду?

Это для Вас они тривиальные, а техподдержки и пользователей — это ничто!

А при чем тут техподдержка и пользователи? Я сейчас говорю о том, что для разработчика тривиально.


Ну скажут они Вам код 404. Далее что будете делать?

А что будете делать вы, когда вам скажут код 400?


Сообщение об ошибке достаточно информативно само по себе, вообще-то, в нем явно сказано, что не найдена модель, и какая конкретно модель, а что это такое — пользователь сервиса знает сам.


Когда нужно что-то большее, просто подкалываем все соответствующие логи под идентификатор запроса и говорим "пользователю", где этот идентификатор искать.


404 Not Found
Content-Type: application/json
x-amzn-RequestId: 4fe027f3-5c80-42a5-8389-3c44fc7734f8
{
  "message": "The model azure-01 was not found"
}

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


Через 10 лет Вы вспомните что за "model azure-01" такое и где это вообще?

Должно быть ясно всем.

Нет, не должно быть. С чего бы?


Через 10 лет Вы вспомните что за "model azure-01" такое и где это вообще?

Без контекста? Нет. Посмотрев на запрос и описание API — да.


Вообще, удивительно, конечно. Вы считаете, что ваше сообщение ""RST0021E" — Имя метода класса генератора SQL запроса не определено" чем-то понятнее? Так нет, не понятнее, по крайней мере, со стороны (это, кстати, привет "должно быть ясно всем"). Лично вам понятнее? Ну так это тоже понятно, вы разработчик.

Ответственность за работоспособность информационной системы лежит не на программисте (не на Вас), а на персонале эксплуатирующей организации. И им в первую очередь должно быть понятно как быстро справляться с той или иной проблемой, возникающей в процессе эксплуатации.


Правилом хорошей реализации, считаю наличие документации с описанием кода ошибки, причины (которые, могут приводить к возникновению ошибки с этим кодом) и действий пользователя (обслуживающего персонала), которые устранят эту ошибку. Например, как у IBM


SQL0120N Invalid use of an aggregate function or OLAP function.
Explanation
An aggregate function or OLAP function can only be used in the select list of a fullselect, the having clause, or, with restrictions, in a WHERE clause or GROUP BY clause.

A WHERE clause can contain an aggregate function or OLAP function only if that clause appears within a subquery of a HAVING clause and the argument of the function is a correlated reference to a group.

A GROUP BY clause can contain an aggregate function or OLAP function only if the argument of the function is a correlated reference to a column in a different subselect than the one containing the GROUP BY clause.

An OLAP function cannot be used within the argument list of an XMLQUERY or XMLEXISTS expression.

The statement cannot be processed.

User response
Change the statement so that the aggregate function or OLAP function is not used or used only where it is supported.

sqlcode: -120

sqlstate: 42903
И им в первую очередь должно быть понятно как быстро справляться с той или иной проблемой, возникающей в процессе эксплуатации.

Ну им и будет понятно.


Правилом хорошей реализации, считаю наличие документации с описанием кода ошибки, причины (которые, могут приводить к возникновению ошибки с этим кодом) и действий пользователя (обслуживающего персонала), которые устранят эту ошибку.

А я считаю правилом хорошего тона наличие документации, из которой понятно, что и как делать. Код ошибки, хотя и полезен, не обязателен.

У смены в зоне ответственности может находиться в эксплуатации сотни различных систем. Вы думаете сменный персонал способен понять что означает код 404 в вашей системе?


Вы никогда не сдавали серьезных промышленных систем в эксплуатацию? Вас ни когда не будили ночью или за столом с друзьями для консультации из-за какого ЧП в информационной системе, когда лично Вы заинтересованы дать короткую и ясную консультацию не имея ничего "перед глазами", чтобы вам повторно не перезванивали? На Вас ведь бизнес может повесить ответственность за простой системы, которая может повлечь и финансовые возмещения убытков.

Вы думаете сменный персонал способен понять что означает код 404 в вашей системе?

Вот для этого у них есть документация.


Вы никогда не сдавали серьезных промышленных систем в эксплуатацию?

Сдавал.


лично Вы заинтересованы дать короткую и ясную консультацию не имея ничего "перед глазами"

А вы, я так понимаю, коды ошибок наизусть помните? Я — нет, и не собираюсь их учить. А сообщение "model not found" мне по крайней мере понятно.


На Вас ведь бизнес может повесить ответственность за простой системы, которая может повлечь и финансовые возмещения убытков.

Не может.

И что Вы напишите в этой документации про код 404? Сотню различных вариантов или несколько сотен, а может тысяч? Как сменный персонал, будет ориентироваться в вашей документации без дополнительной информации о причине ошибке?


Очень сильно сомневаюсь, если и сдавали, то "прятались" за спины более опытных коллег.


Коды не нужно знать наизусть. Они повышают информативность сообщения об ошибке и значительно ускоряют поиск проблемы и ее устранение. И позволяют ориентироваться Вам в возможных причинах при консультации по телефону. Пользователь, техподдержка и эксплуатирующий персонал должны разговаривать "на одном языке" — специализированный код ошибки это и позволяет делать.


Может, вас похоже не подпускали еще к серьезным системам.

И что Вы напишите в этой документации про код 404?

"See documentation for the appropriate request URL". 404 — она не в воздухе возникает, она в ответ на что-то.


Как сменный персонал, будет ориентироваться в вашей документации без дополнительной информации о причине ошибке?

Так дополнительная информация есть, она в message написана.


И позволяют ориентироваться Вам в возможных причинах при консультации по телефону.

Каким образом, если я их не знаю наизусть? Сообщение "model not found" намного лучше позволяет ориентироваться при консультации по телефону, чем "Error EMQP0114X".

Напомню 404 — это HTTP код, который сигнализирует, что что то не найдено. В информационных системах с множеством объектов этот код не дает Вам какой либо ясности, что же не найдено. Ваше сообщение для подавляющим большинством пользователей воспринимается как "абракадабра". Хорошим, подчеркиваю хорошим, "тоном" программирования является присвоение в системе каждой ошибке в вашей системе уникального кода. Это значительно повышает информативность возвращаемого сообщения и позволяет всем участникам процесса говорить на одном языке вне зависимости от их квалификации. А Вам позволяет достаточно быстро понять причину проблему.

Напомню 404 — это HTTP код, который сигнализирует, что что то не найдено. В информационных системах с множеством объектов этот код не дает Вам какой либо ясности, что же не найдено.

Вот именно поэтому есть контекст, выраженный запросом, и сообщение об ошибке.


Ваше сообщение для подавляющим большинством пользователей воспринимается как "абракадабра".

А откуда вы что-то знаете о пользователях моей системы?


присвоение в системе каждой ошибке в вашей системе уникального кода.

Этот код не воспринимается пользователями как абракадабра? А почему?


А Вам позволяет достаточно быстро понять причину проблему.

Каким образом код EMQP0114X позволяет мне быстрее понять причину проблемы, чем сообщение "model X not found"?

Вы вольны реализовывать 404 как Вам угодно.


Я исхожу из того, что увидит пользователь при ошибке, что он скажет техподдержке, как это сказанное сообщение об ошибке трансформируется и дойдет до разработчика системы. Код ошибки при передаче по этой цепочке не искажается, а любые фразы, да еще содержащие "абракадабру" могут дойти до Вас в неузнаваемом виде.

Код ошибки при передаче по этой цепочке не искажается

Почему?


а любые фразы, да еще содержащие "абракадабру" могут дойти до Вас в неузнаваемом виде.

Copy-paste никто не отменял. Все — подчеркиваю, все — запросы на поддержку, которые ко мне пришли за последние лет пять, были в виде текста или скриншота. Ни разу он не был в виде звонка.

Пользователь выберет тот способ обращения в техподдержку, который ему удобен и сообщит то, что он поймет глядя на ваше сообщение.

Пользователь выберет тот способ обращения в техподдержку, который ему удобен

Прекрасно, пусть выбирает: емейл, чат (выводится из обслуживания в этом году) и форма в специализированной системе.

Еще раз, пользователь выберет то, что посчитает нужным. Опишет/расскажет то, что он поймет в вашем сообщении.

Еще раз, пользователь выберет то, что посчитает нужным.

Вы обратили внимание, что у него нет возможности пообщаться голосом? Никакой? Только текст?


Опишет/расскажет то, что он поймет в вашем сообщении.

А, ну, здесь мы на равных.


В моем опыте бывает преимущественно два варианта: говорят "была ошибка", не давая никакой информации, либо просто копируют все сообщение об ошибке.

"Говорят"? У вас же нет "голоса" :-)


С вами пользователь не может пообщаться голосом, служба техподдержки предоставляет ему такую возможность. Вы не путаете две разные службы — вашу и заказчика. У всех крупных заказчиков есть внутренняя служба техподдержки, которая ретранслирует Вам то, что она поняла из обращения своего пользователя, часто исказив полученную информацию.

Вы не путаете две разные службы — вашу и заказчика.

Не путаю. Мне все равно, как служба техподдержки заказчика общается с пользователями, мне важно, что к нам приходит.


часто исказив полученную информацию.

Вот чтобы искажений не было, и надо копировать сообщение об ошибке полностью. Как ни странно, люди достаточно быстро этому учатся.

Вы получите ровно то, что техподдежка заказчика поняла из "описания" проблемы пользователя. При этом, учитывая несколько линий эта информация искажается внутри службы поддержки вашей и заказчика — уникальный код ошибки исказить очень трудно. Ваш код 404 в этой системе будет гарантированно искажен.

Вы получите ровно то, что техподдежка заказчика поняла из "описания" проблемы пользователя.

Говорю же: копировать сообщение об ошибке целиком. Не надо ничего "понимать". Надо копировать сообщение об ошибке. Если система user-facing, там прямо кнопочка есть "send error report".


уникальный код ошибки исказить очень трудно

Да нет, легко.


Ваш код 404 в этой системе будет гарантированно искажен.

Гм. Нет, не будет.

Говорю же, что пользователь сказал по телефону службе поддержки и как это сказанное поняла служба поддержки — то вы и получите. Другому просто неоткуда взяться.


Вы думаете что в службе поддержки сидят сплошные специалисты по вашей системе и могут "ее разбирать и собирать с закрытыми глазами за 45 сек"?


Гарантировано будет. Для подавляющего числа IT специалистов код 404 означает — ресурс не найден. Так они Вам это и передадут.

Говорю же, что пользователь сказал по телефону службе поддержки и как это сказанное поняла служба поддержки — то вы и получите. Другому просто неоткуда взяться.

Есть такая штука как "условия оказания технической поддержки".


Вы думаете что в службе поддержки сидят сплошные специалисты по вашей системе и могут "ее разбирать и собирать с закрытыми глазами за 45 сек"?

Нет, не думаю. Им и не надо.


Гарантировано будет.

Докажите.


Для подавляющего числа IT специалистов код 404 означает — ресурс не найден. Так они Вам это и передадут.

Обратите внимание, что код не искажен. Искажено сообщение об ошибке.


Что я могу сказать, эти "IT-специалисты" сами виноваты — получат свой запрос обратно со словами "предоставьте полный текст сообщения об ошибке".

Может, вас похоже не подпускали еще к серьезным системам.

А, я понял, это было про "бизнес может повесить". Так вот, бизнес "может повесить" ровно то, что в контракте написано, и никак не больше. И что-то мне кажется, что для "серьезных систем" персональная финансовая ответственность в контракте — это несколько глупо, потому что там суммы убытков такие, что любой отдельный разработчик их возместить не может. Намного осмысленнее ставить в качестве ответственного юридическое лицо-подрядчик — у него и капитал поболе, и репутационные риски есть.

Для серьезных систем бизнес Вам указывает время вашей реакции на проблемы в вашей системе, далее идут штрафные санкции. Терпеть убытки, когда вы на пляже загораете, бизнес не намерен.

Для серьезных систем бизнес Вам указывает время вашей реакции на проблемы в вашей системе, далее идут штрафные санкции.

Мне как разработчику или архитектору лично? Нет, не указывает.


Терпеть убытки, когда вы на пляже загораете, бизнес не намерен.

А это его проблемы, если вкратце.


Чтобы не терпеть убытки, когда я загораю на пляже, намного полезнее не зависеть от меня как от единственного человека, способного решить проблемы. А то разные случаи бывают.

Которые станут вашими при потере заказчика

Которые станут вашими при потере заказчика

Если "заказчик" не дает мне возможности полететь на самолете Москва-Токио, честное слово, не нужен мне такой заказчик.


Повторюсь, с точки зрения работоспособности системы намного выгоднее иметь больше одного человека, способного ее (систему) починить, чем накладывать любые штрафные санкции на единственного способного ее починить человека. Еще и потому, что когда он скажет "достали меня ваши санкции, ухожу я", сделать будет нельзя ничего.

В любом ПО, даже в котором нет ни одной ошибки, в процессе эксплуатации возникают проблемы, с которые может устранить только разработчик.

которые может устранить только разработчик.

Компания-разработчик. Потому что если эксплуатация ПО завязана на одного человека, то это очень плохо для стабильности эксплуатации (хотя может быть и хорошо, в финансовом плане, для этого человека).

Дело не в одном человеке и ни в компании разработчике.


Это же элементарно!


В процессе эксплуатации системы условия эксплуатации постоянно меняются. Появляются новые смежные системы, меняется компоновка технических средств, меняется техпроцесс (оператора заменили на смежную систему например), меняются версии используемого ПО и многое другое. Это может порождает проблемы в эксплуатации, которые могут и не сразу проявиться.

Дело не в одном человеке

Если дело не в одном человеке, то этот человек может прекрасно отдыхать на пляже. О чем и шла речь.


Это же элементарно!

Это элементарно, если не терять нить дискуссии.


В процессе эксплуатации системы условия эксплуатации постоянно меняются.

… сразу в проде, я стесняюсь спросить?


Это может порождает проблемы в эксплуатации, которые могут и не сразу проявиться.

И почему это должно мешать моему отпуску?

Сразу в проде. Ни одна система тестирования не даст Вам 100% результат. (В одной точке вселенной можно собрать всю информацию о всей вселенной, только на это потребуется гораздо больше времени чем существование самой вселенной.)


Потому что у заказчика "пожар"

Сразу в проде.

Ну вот поэтому у вас и "пожар" на "серьезной системе".


Потому что у заказчика "пожар"

И что? Его пожар стоит того, чтобы послать за мной курьера?


Повторюсь, чтобы не надо было тушить "пожары" из отпуска, достаточно завести сменщика, который будет этим заниматься в мое отсутствие по штатному процессу.


Это же элементарно!

Пожар стоит того, чтобы получить у Вас консультацию.

Пожар стоит того, чтобы получить у Вас консультацию.

Я так не думаю.

И курьера слать не обязательно, достаточно позвонить вам "на пляж"

Так там покрытия нет. Никакого.

Значит будут звонить вашему сменщику. Будут звонить всем, кто способен дать консультацию.

Прекрасно! Это ровно то, что мне и надо — мой отпуск в безопасности.

Если только на Эверест заберетесь или на белого медведя отправитесь в естественных условиях посмотреть.

Да нет, есть намного более простые ситуации. Начиная с перелета Амстердам-Сиэттл (десять часов, если мне память не изменяет).

у сменщика выходной, он на "своем пляже", не доступен, телефон сел, вдрызг день рожденье на отмечался :-)

Если он обязан быть на работе в это время — это его проблемы. Не мои.

Ваш сменщик не работает круглосуточно, как и Вы. И "пожары" не догадываются о существовании режима труда и отдыха

Ваш сменщик не работает круглосуточно, как и Вы.

Нужна круглосуточная поддержка? Заводится столько сменщиков, сколько надо, чтобы ее обеспечить.

Так они Вам и будут звонить.

См. выше: я недоступен.


Собственно, какой смысл в сменщиках, если они не могут решить проблему без моего участия?

Вопросы:

1. Фронтэнд выполняется в браузере, кто и как будет контролировать доступность данных пользователю? Ну условно мы хотим показать гостю список сообщений, а он взял, поменял запрос и удалил все данные.

2. Где будут хранится данные доступа в базу, вы же не будете каждому гостю копировать данные доступа в браузер?

3. Как такой сервис защищается от SQL inject, если по факту там именно SQL и выполняется?

4. Если мы хотим иметь сложную логику на стороне сервера, чтобы не гонят кучу записей по сети, как быть в этом случае?

5. Чем это отличается от всевозможных реализация rest api у баз данных, например таких или таких. Если мы уже можем напрямую работать по rest с базой данных, зачем нам еще один слой, который не добавляет ничего дополнительного?
  1. Считаю хорошим примером реализации построение пользовательского интерфейса на основании прав пользователя, что сразу "гасит" ваш вопрос. Дополнительно, доступ к разным функциям, разным таблицам и прочему "разному" можно закрыть ролями настроив соответствующие ограничения в файле web.xml. Гость может выполнить только то, что Вы ему разрешите.


  2. Параметры доступа к БД хранятся на узле сервера приложения. Это может быть тот же узел, где развернут этот сервис или совершенно другой узел.


  3. Пользователь не может выполнить произвольный запрос вообще никак.


  4. Сервис не ограничивает Вас в реализации логики любой сложности. Архитектура движка позволяет Вам вызвать любой код, в том числе и методы этого сервиса на прямую (без REST вызова) как обычный локальный Java код даже с другого узла системы.


  5. Рассмотренный сервис может с ходу работать с любой БД любого производителя поддерживающего JDBC. Ваши примеры, как я понимаю из беглого ознакомления, заточены только на определенные базы. Для сравнения функциональных возможностей требуется гораздо больше времени. Этот сервис можно встроить в любое приложение, например у которого REST сервисы не являются основной функциональностью — для экспорта своих данных в другую систему по запросу.


Этот сервис можно встроить в любое приложение, например у которого REST сервисы не являются основной функциональностью — для экспорта своих данных в другую систему по запросу.

Минуя все бизнес-правила, конечно же?

Все зависит от ваших желаний и потребностей и какие бизнес-правила вы хотите соблюсти.

Ну вот самое простое: есть сущность "контрагент", у нее есть атрибут "кредитный лимит", пользователь, входящий в роль "сейл", может видеть кредитные лимиты контрагентов, пользователь, в эту роль не входящий — не может.

Элементарно


  1. Можно создать VIEW в котором нет поля, которое "не может видеть"


  2. Можно создать класс расширения, который вернет то "что нужно"


  3. Нужно реализовать интерфейс пользователя так, чтобы он мог видеть и делать только то что ему позволено, в зависимости от привилегий пользователя.


  4. Можно использовать 1, 2 и 3 в любом сочетании.


Нужно реализовать интерфейс пользователя так, чтобы он мог видеть и делать только то что ему позволено, в зависимости от привилегий пользователя.

Какой-такой интерфейс пользователя? Напоминаю, что речь шла напрямую о REST-сервисах:


Этот сервис можно встроить в любое приложение, например у которого REST сервисы не являются основной функциональностью — для экспорта своих данных в другую систему по запросу.

Вот мы об экспорте данных и говорим сейчас. По REST.

такой "такой интерфейс пользователя", напомню — пользователь сам не набирает "волшебные буковки" в строке запроса. Или в ваших системах нет интерфейса пользователя?


Экспорт данных не предусматривает наличие пользователя вообще!

Или в ваших системах нет интерфейса пользователя?

Зачастую нет. Я, знаете ли, преимущественно сервисами занимаюсь.


Экспорт данных не предусматривает наличие пользователя вообще!

Да ну? А под чьими правами он происходит?

А что же тогда все про интерфейс то пользователя твердите, если Вы им не занимаетесь?


Настройка привилегий взаимодействия система — системы вообще ни каких проблем не вызывает.

А что же тогда все про интерфейс то пользователя твердите, если Вы им не занимаетесь?

А я что-то про него твержу?


Настройка привилегий взаимодействия система — системы вообще ни каких проблем не вызывает.

Ну вот и расскажите, как это сделать, учитывая, что система, получающая данные, должна работать с привилегиями (и ограничениями) пользователя, который ее запускает.

Вы указали хаб Высокая производительность, но из статьи непонятно, как это обеспечивается и насколько производительность высока.
Пожалуйста, раскройте эту тему подробнее. Есть ли результаты нагрузочных тестов? Проводилось ли сравнение с другими системами и каковы результаты?

Утверждение "высокая производительность" относится к фреймворку "Avalanche — application framework for Java", на основе которого реализован пример универсального сервиса. Указанный фреймворк является дальнейшим развитием эксплуатируемого уже много лет движка информационной системы — распределенные мульти параллельные вычисления — один запрос пользователя порождает множество параллельных вычислений на множестве узлов системы, на каждом узле в свою очередь может быть порождено свое множество параллельных потоков (лавина).


Такой подход позволил реализовать функции планирования, прогнозирования, ситуационное моделирование на данных реального времени. Большая часть указанной функциональности отрабатывает менее чем 3 сек. У части этих функций критерии запроса пользователь может задавать самостоятельно.


Измерений и сравнений естественно нет. Подобные системы уникальны. Могу только отметить, что ни одна другая информационная система в этой же корпорации, работающая на таком же полигоне со схожими условиями не может похвастаться подобными результатами по производительности. В них, как правило, создаются дублирующие (не оперативные) источники данных, на которых и запускаются различные расчеты для формирования "статических отчетов".


Производительность достигается за счет:


  1. контроля состояния каждым узлом всех узлов, с которыми он связан. Система мгновенно перераспределяет нагрузку между узлами при обнаружении любого "дефектного узла", либо сохраняет свою частичную работоспособность без потери производительности "при потере" сегмента сети.
  2. минимизации различных преобразований данных в цепочке вызовов
  3. параллельности вычислений
  4. экономии "на всем" — это уже непосредственная реализация, к фреймворку не относится.

Основное отличие "Avalanche — application framework for Java" от своего предшественника, это значительное упрощение создания распределенных систем.

Простите, я не совсем понял: Avalanche — open-source продукт или ваша закрытая разработка, сделанная под ваши задачи?
А "его предшественник" — кастомное решение или что-то широко доступное?

К сожалению, это пока не OpenSource проекты.

Раз это не open source, как вы можете разделить фреймворк и остальные части системы? У вас есть десяток разных приложений? Вы тестировали Avalanche отдельно от других частей?
Последний вопрос риторический: исходя из ваших ответов, нагрузочного тестирования не проводилось.

Avalanche, как и предшественник — это промежуточное программное обеспечение, которое можно встраивать в любую предметную область. Сервер приложений "накручивается" сверху него. Промышленную систему, которая сейчас находится в эксплуатации — тестировали, "одномоментно" было послано около 16 000 запросов на сервер приложений, этот узел упал, когда начал раздавать результаты по OutOfMemory. Все остальное осталось в рабочем состоянии.


Тест тесту рознь. Avalanche — продукт, который предоставляет готовый сервис для создания распределенных отказоустойчивых систем непрерывной доступности. Внутренние функционал Avalanche не создает какой либо существенной нагрузки. Нагрузка вся "от предметной области". Тесты на устойчивость Avalanche естественно проводились, но это не нагрузочное тестирование — нагружать нечего.

Базовый нагрузочный тест — посылать на тестируемую систему 100, 1000, 10 000, 50 000 (и т.д.) запросов в секунду. Определяется порог: при какой нагрузке система начинает помирать. Так можно тестировать не только клиентское приложение, но и middleware, и отдельную подсистему. Например, БД или подсистему авторизации. Вопрос не в том, какую нагрузку создает фреймворк, а какую нагрузку он способен принимать и обрабатывать.


Отказоустойчивость и высокая доступность — вещи, ортогональные высокой производительности. Как и распределенность системы.


Было бы прекрасно, если вы подробнее расскажете про нагрузку в 10-15-16к запросов: это уже похоже на высокую производительность.

Согласитесь, что нельзя сравнивать по количеству запросов разные системы.


Запрос запросу рознь! Не во всех системах можно провести нагрузочное тестирование или смоделировать его. Чтобы построить испытательный полигон моей системы для проведения предложенных вами тестов нужны миллиарды рублей (порядок цифр реальный, не сомневайтесь) и уйму времени и специалистов. На промышленной системе подобные тесты проводить никогда не разрешат.


Для небольших систем, наподобие той, что описана в статье по вашей ссылке, построить тестовый полигон его "вкивь и вкось" не проблема.

Для небольших систем, наподобие той, что описана в статье по вашей ссылке

Просто чтобы не ошибиться, вы Discord небольшой системой называете?

На промышленной системе подобные тесты проводить никогда не разрешат.

Вы же сами описывали, что давалась нагрузка в 16к запросов. Вполне себе проверка производительности, небольшой нагрузочный тест. Стоило это миллиарды или нет — вы знаете лучше меня.


Обычно, для нагрузочного тестирования берут один узел кластера либо сервер с кратно меньшими параметрами. Наверное, так было и у вас. Отправить 16к REST запросов в секунду вполне можно с 1-2 машины разработчика.


Согласитесь, что нельзя сравнивать по количеству запросов разные системы.

Ну я даже не знаю что сказать. Именно так и сравниваютоценивают: количество запросов (типичных для этой системы), время ответа, процент потерь. Делается вывод, какую нагрузку выдержит система. В попугаях запросах, типичных именно для нее.


Но я не хочу вещать о том, как правильно делать. Я здесь для другого. Мне интересны подробности вашей истории. Вы ведь хотели поделиться ей, раз опубликовали ее?
Если не секрет, расскажите какая подсистема упала от 16 000 запросов: Avalanche или что-то другое? Если ваш фреймворк, то делался ли анализ "горячих точек"? Это были самые тяжелые или самые легкие запросы для системы?

Да, про 16К описывал, это была моя личная авантюра без какого либо согласования и моей полной уверенности отсутствия каких либо серьезных последствий. Цель эксперимента — проверка устойчивости работы сервера приложений с БД, БД "убивать" нельзя вне зависимости от действий пользователей.


Упал один узел сервера приложения, на этапе обработки полученных результатов. "Транспорт" (распределенная система) выдержал. Для Avalanche пока не нашел варианта внедрения с подобными нагрузками.

ни одна другая информационная система в этой же корпорации, работающая на таком же полигоне со схожими условиями не может похвастаться подобными результатами по производительности

Вас не затруднит озвучить параметры? Сколько запросов в секунду обрабатывает, время ответа? Сколько ресурсов потребляет (RAM, CPU, Storage), на каком железе крутится?
Второй вопрос — про сравнение с "другими информационными системами". Они выполняют схожие функции/задачи? Если да, то почему нельзя сравнить Avalanche с ними? Если нет, то зачем вы это написали?


Большая часть указанной функциональности отрабатывает менее чем 3 сек.

Я правильно понимаю, что реакция системы на запрос пользователя — 3 секунды? Если нет, то каков response time на GET при а) средней нагрузке б) максимальной нагрузке? Понятно, что запросы бывают простые и не очень, хотелось бы увидеть данные для трех случаев:


  1. Результат — небольшой объект, бизнес-логики нет.
  2. Размер объекта и объем бизнес-логики — средние для вашей системы
  3. В ответ возвращается большой список (>1000 объектов)

P.S. Пожалуйста, поймите меня правильно. Я не хочу придираться, но мне (наверное, не только мне) хочется увидеть границы применимости этой системы. Без этих данных "высокая производительность" — пустые слова.

Масштаб внедрения — вся страна.


Около 20 MainFrame-ов (СУБД), около 40 серверов приложений (виртуалки), 1 кластер MS — все сервера приложений равноправны, все сервера приложений взаимодействуют друг с другом. Система сохранит свою полную работоспособность при отказе до 50% серверов приложений. У MF несколько другой принцип резервирования. Характеристик серверов приложений довольно скромные по нынешним временам: 4 ЦПУ, 8 — 16 ГБ ОЗУ: кластерные узлы: 8 ЦПУ, 32 ГБ ОЗУ. Кластер используется для долгосрочного хранения данных, которые уже не изменяются, и для хранения оперативных кратковременных расчетов (производиться расчет на данных с MF-ов, расчет повторяется через несколько минут, результат сохраняется в кластерной БД, пользовательские запросы не посылаются на MF-ы, а перенаправляются на кластер — за счет этого уменьшена нагрузка на MF-ы).


Общее количество запросов в систему около 100 тыс в сутки (под запросом понимается выдача "полезной" формы сервером приложений). 2/3 запросов — запросы от сменных (оперативных) сотрудников


Пользователи — от первых лиц компании до ИТР предприятий


Отслеживается миллионы объектов, непрерывно меняющих свое состояние. Гарантированное хранение всех операций с объектами всего 2 суток


Пики нагрузок — начала рабочего дня и передача смены (периоды примерно по 2 часа), последний и первый день месяца (контроль выполнения плановых и бюджетных показателей)


Бизнес логика присутствуют в сервере приложения.


Подавляющее число форм отрабатывает за время, менее 1 сек. (на основе данных собираемой статистики). "Тяжелые" формы (прогнозные, ситуационные) — 3-5 сек. Наиболее "тяжелые" расчеты работают в фоновом режиме. Один запрос пользователя или фонового процесса может загрузить до половины серверов приложения и все MF-ы.


Большинство форм аналитические (таблица, карта, схема, график) — характеризуют состояние различных объектов управления в различных разрезах. Пользователь может "провалиться" с самого верхнего уровня, до самого нижнего. Может получить и списки, иногда получают списки более 1000 объектов (не понимаю, как пользователь может анализировать такие списки).

Масштаб внедрения — вся страна

К сожалению, масштаб не коррелирует с высокой производительностью.


Общее количество запросов в систему около 100 тыс в сутки
Отслеживается миллионы объектов, непрерывно меняющих свое состояние

К сожалению, это не попадает в "высокую производительность".
100 тыс. в сутки — это ~1,16 запроса в секунду. У high-load систем их десятки тысяч в секунду. Сравните "менее секунды" и "десятки миллисекунд", ваши "миллионы объектов" с "миллиардами структур данных" из статьи в том же хабе.


Пока я вижу, что вы выдаете желаемое за действительное.

У нас разные понятия об "одном запросе"!


Что Вы понимаете под одним запросом? Одну отдельную операцию? Вставка или чтение одной записи?


Я понимаю под одним запросом пользователя — запрос "полезной" для него информации, который формируется на множестве записей из множества БД множеством серверов приложений.

Когда говорят о нагрузке, обычно подразумевают типичный, самый массовый запрос.
Запросы уникальны в каждой (под)системе. Если рассуждать об аналитических системах, то агрегат (sum либо average) над миллионом-другим записей вполне может быть типичным. Если же вы рассказываете про фреймворк, то типичные запросы могут быть другими. В частности, в описании вы говорите о REST запросах.
Так как Avalanche — заказная разработка, то что является обычным — можете сказать только вы. Сколько на один пользовательский запрос приходится REST в среднем, можете знать только вы. А можете и не знать, если эта статистика никому не была интересна — такое тоже бывает :)

Avalanche — не заказная разработка! Эта результат моей личной инициативы. В предшественнике реализация устойчивости работы в распределенной среде получилась очень громоздкой, из-за чего пришлось отказаться от ее расширения при возникновении одного нового нетипичного требования (потребовалась внутренняя сервисная функция сервера приложений). Стало лень вносить изменения в существующею реализацию ради этой функции. Но задуматься это требование заставило, что надо это все как то упростить. Плюс опыт эксплуатации распределенной среды поднакопился. В результате и появился продукт — Avalanche.


Avalanche — сказка! :-) Создавать распределенные системы или программные кластеры не просто просто, а очень просто. Появилась возможность создавать виртуальный сервер приложений на основе множества узлов в распределенной среде.


А REST запросы это или что то другое — значение не имеет. Любой "простой" запрос может потребовать большого объема вычислений для получения "простого" ответа. Я знаю одно, чем меньше выполняется в коде различных преобразований тем более производительная система. Поэтому считаю некоторые очень распространенные и популярные продукты "программным мусором". Этот пример демонстрация такого подхода. Можно из этого примера исключить Avalanche? Можно, только кода будет чуть больше и "распределенность" пропадет. Этот пример с легкостью будет работать с двумя, тремя и т.д. копиями БД. Поменяли конфигурацию, получили резервирование БД — все. Если этот пример немного усложнить, то можно получить отказоустойчивую систему из двух узлов и двух копий БД.

В статье, при беглом ознакомлении, описывается проблема производительности одноузловой системы с элементарными, на мой взгляд, функциями.


Если сложить все процессорные операции для обслуживания всего лишь одного запроса в моей системе — не сомневаюсь, миллиард будет с легкостью превзойден.

Нет, речь о количестве запросов, обычных для вашей системы. Точнее — о запросах к Avalanche. Так как в статье вы описывали обращение к нему по REST, я предполагаю что речь идет о количестве REST запросов к "одноузловой системе с элементарными функциями".

REST просто пример, не более. Повторюсь, какие запросы обрабатывать не имеет значения.


"В одноузловой системе с элементарными функциями" производительность целиком и полностью зависит от мощности этого узла. Терять производительность практически негде.

У меня что-то внезапно простой вопрос: а как делать JOIN и прочие хоть сколько-нибудь сложные операции? "Дайте мне все открытые заказы вместе с адресами доставки", что-нибудь вот такое.

… собственно даже фиг с ними, со всеми заказами, как нам получить один заказ целиком, учитывая, что нам нужно знать и про заказчика (емейл, телефон, имя, адрес), и про строки заказа (что и сколько), и про платежи (когда и сколько), и про отправления (когда и что).

Элементарно — ни каких проблем с решением подобных задач нет.


Join и прочие реализуются с помощью классов расширения функциональности — сможете написать требуемый вам запрос, универсальный сервис его выполнит.


Не формализованными данными Вы работаете так же как и в любой другой реализации, реализуете специальные функции получения не формализованных данных. При их получении можете воспользоваться функциями этого сервиса для формирования ваших не формализованных данных их множества таблиц. Это позволит Вам частично формализовать ваши не формализованные данные.

Join и прочие реализуются с помощью классов расширения функциональности — сможете написать требуемый вам запрос, универсальный сервис его выполнит.

Получается, "стандартный" (без вмешательства в код сервиса) механизм этого не позволяет, на каждый новый запрос над существующими сущностями надо писать расширение для сервиса?


А, гм, зачем оно такое и какой от этого профит?


Не формализованными данными Вы работаете так же как и в любой другой реализации, реализуете специальные функции получения не формализованных данных.

А при чем тут неформализованные данные? (я даже не очень в курсе, что конкретно вы имеете в виду)

Вмешиваться в код этого сервиса не надо для реализации любой функциональности с не формализованными данными. Вы разве не знакомы с ООП?

Вмешиваться в код этого сервиса не надо для реализации любой функциональности с не формализованными данными.

А причем тут неформализованные данные?


Вы разве не знакомы с ООП?

Знаком.

Не формализованные данные не возможно решить универсальным способом.


Вы разве не знакомы с ООП?

Знаком.

Судя по вашим вопросам, начинаю сомневаться в этом.

Не формализованные данные не возможно решить универсальным способом.

Что такое "неформализованные данные", и какое отношение это имеет к моему вопросу про выборку заказов?


Судя по вашим вопросам, начинаю сомневаться в этом.

Ну, ваши сомнения — это ваши сомнения, но безотносительно моих знаний, как получить данные из моих примеров выше без вмешательства в код сервиса?


Чтобы сразу не было недопонимания, ваши "произвольные запросы, расширяющие функциональность сервера", которые реализуются путем добавления кода, я считаю вмешательством в код сервиса.

ваши вопросы, это ваши вопросы :-)


Ваш пример с заказом — пример не формализованных данных.

Ваш пример с заказом — пример не формализованных данных.

Что такое "неформализованные данные", и почему вы относите к ним мой пример с заказом?


Для меня это полностью формализованные данные, на них спецификация есть.

Данные в таблицах — формализованные данные


Данные заказа — не формализованные данные, т.к. содержат данные из из нескольких таблиц (сочетание произвольное — не формализованное). Вы оперируете понятием "заказ", применимым только в вашей системе. В другой системе другой предметной области "заказ" будет иметь совершенно другие атрибуты и построен совершенно на других "таблицах".

Данные заказа — не формализованные данные, т.к. содержат данные из из нескольких таблиц (сочетание произвольное — не формализованное).

Нет, не произвольное.


Я еще раз спрошу: каким определением "неформализованных данных" вы пользуетесь?


Вы оперируете понятием "заказ", применимым только в вашей системе.

Ну да, и что?


(мне вот любопытно стало: а когда вы из таблицы выбираете не все поля, они в этот момент перестают быть формализованными?)

формализованные данные — данные формально не зависящие от предметной области. Например, этот сервис "не знает" с какими данными он работает (из какой предметной области). Этот сервис может любыми данными любых таблиц в любой предметной области.


Не формализованные данные — структура данных, зависящая от чего либо, и не может быть представлена в общем виде. Ваш "заказ" имеет свой уникальных набор атрибутов — не формализованные данные. Ваше ПО неприменимо в другой предметной области, где так же есть понятие "заказ", потому что он должен иметь свой уникальный набор атрибутов.

формализованные данные — данные формально не зависящие от предметной области.
Не формализованные данные — структура данных, зависящая от чего либо, и не может быть представлена в общем виде.

Простите, а откуда эти определения взяты?


Ваш "заказ" имеет свой уникальных набор атрибутов — не формализованные данные.

Что такое "уникальный набор атрибутов"?


Ваше ПО неприменимо в другой предметной области

Какое "мое ПО"?


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


А вот ПО, которое применимо во многих предметных областях, и которое способно решить поставленную мной выше задачу — конечно же, существует. Типичный пример — (некоторые) СУБД. Вот, скажем, MS SQL. Или MySQL.


Я, собственно, поэтому и не понимаю, какое эти определения вообще имеют отношение к простому вопросу: можно ли решить мою задачу в вашем универсальном сервисе, не меняя его код. В приведенных выше СУБД — точно можно, безотносительно определений.

Мной придуманы.


Если это не тема нашего обсуждения, то что так упорно "пристаете" со своим заказом? Почему хотите чтобы ваш "частный случай" должен обрабатываться кодом, который не может "вычислить" информацию о структуре вашего заказа.


На ваш вопрос, может ли вашу задачу решить мой уникальный сервис без изменения его кода, я уже ответил — МОЖЕТ, "надстройкой" над этим сервисом специализированного кода, отвечающего за формирование данных в вашем "формате". Еще раз может и код этого сервиса менять не нужно.

Мной придуманы.

А, ок. Не удивляйтесь только, что я вас не понимаю тогда.


Если это не тема нашего обсуждения, то что так упорно "пристаете" со своим заказом?

Потому что это простой типовой пример из реальной жизни.


"Не тема нашего обсуждения", называется этот пример формализованными или неформализованными данными.


На ваш вопрос, может ли вашу задачу решить мой уникальный сервис без изменения его кода, я уже ответил — МОЖЕТ, "надстройкой" над этим сервисом специализированного кода, отвечающего за формирование данных в вашем "формате". Еще раз может и код этого сервиса менять не нужно.

Покажите, как.

Элементарно, так же как это сделали и Вы. Либо смотрите в примеры в интернет, их там много. Напомню, универсальный сервис ни как не ограничивает ваши "фантазии".


Но, сейчас я подумал, в принципе можно формализовать ваш пример с "заказом". Правда он ни чего общего с вашими форматами запроса и ответа иметь не будет, но будет возвращать требуемые вам данные. Появиться и еще один тип запроса, например:


.../data/object/...

Элементарно, так же как это сделали и Вы.

Сделал что?


Напомню, универсальный сервис ни как не ограничивает ваши "фантазии".

Моя "фантазия" — сделать джойн по существующим в БД таблицам. Как?


Но, сейчас я подумал, в принципе можно формализовать ваш пример с "заказом".

Я знаю, что можно — другие-то системы умеют. Мне интересно, как с этим справляется предложенное в вашем посте решение.

Сделал что?

Любой ваш сервис. Или вы уже не занимаетесь сервисами?


Моя "фантазия" — сделать джойн по существующим в БД таблицам. Как?

Вы не знаете как писать JOIN запросы? Пишите (генерируете) SQL запрос с JOIN по полученным параметрам и готово. Запрос будет выглядеть так


.../data/query/ваш_класс.ваш_метод? параметры


все, пользуйтесь на здоровье.

Любой ваш сервис.

А откуда вы знаете, что делает "любой мой сервис"? И, что любопытнее, как он это делает?


Запрос будет выглядеть так
.../data/query/ваш_класс.ваш_метод? параметры

Так, еще раз, чтобы я правильно вас понял. Я, значит, беру ваш сервис как он есть сейчас в исходниках, разворачиваю где-нибудь, шлю на него запрос, содержащий мой_класс.мой_метод, и этот класс/метод выполняется?

А откуда вы знаете, что делает "любой мой сервис"?

Мне знать и не нужно. Главное, чтобы Вы знали, что делают ваши сервисы.


Так, еще раз, чтобы я правильно вас понял. Я, значит, беру ваш сервис как он есть сейчас в исходниках, разворачиваю где-нибудь, шлю на него запрос, содержащий мой_класс.мой_метод, и этот класс/метод выполняется?

Правильно! Только предварительно, Вы должны разработать ваш_класс.ваш_метод и опубликовать его на сервере, чтобы этот сервис его мог найти.

Мне знать и не нужно.

Тогда вы не можете утверждать, что что-то можно сделать так же, "как это сделал я".


Только предварительно, Вы должны разработать ваш_класс.ваш_метод и опубликовать его на сервере,

Это и есть та модификация кода сервера, о которой я вас неоднократно спрашивал.


А моя, как вы выражаетесь, фантазия состоит в том, чтобы просто делать запрос, ничего не модифицируя.


(Повторюсь, РСУБД мне это позволяет, так что ничего неординарного я в этом пожелании не вижу.)

Тогда вы не можете утверждать, что что-то можно сделать так же, "как это сделал я".

Могу, разница будет в реализации — а не в сути.


Это и есть та модификация кода сервера, о которой я вас неоднократно спрашивал.

Это не модификация (исходный код сервиса не затрагивается), а расширения, о чем в статье и заявлено.


А моя, как вы выражаетесь, фантазия состоит в том, чтобы просто делать запрос, ничего не модифицируя.(Повторюсь, РСУБД мне это позволяет, так что ничего неординарного я в этом пожелании не вижу.)

В чем тогда вопрос Ваш, раз Вы понимаете, что модификации кода не нужно?

Могу, разница будет в реализации — а не в сути.

Прежде чем говорить о реализации, надо знать решаемую задачу, а вы о ней (в случае моих сервисов) ничего не знаете.


Это не модификация (исходный код сервиса не затрагивается), а расширения, о чем в статье и заявлено.

В моей системе терминов это модификация, потому что совокупный код сервиса (все, что обрабатывает запросы на данный адрес) — меняется. Единица развертывания изменилась, если так проще.


(можно еще было бы подискутировать, если бы этот код подливался в сервис динамически, но тут начнется другой клубок змей)


В чем тогда вопрос Ваш, раз Вы понимаете, что модификации кода не нужно?

Да мой вопрос как раз в том, что в случае РСУБД модификации кода не нужно, а вашем — нужно. Повторюсь, под моим определением модификации кода, но я это определение озвучил сильно выше по треду, специально чтобы избежать недопониманий.


Можно еще с другой стороны подойти к вопросу. Вот есть ваш сервис, как он сейчас описан (а не как "можно было бы сделать"), развернутый на некоем сервере А. Он предоставляет доступ к таблицам В и Г через ваш стандартный api data/table/В и data/table/Г. Ничего больше он не предоставляет, никакой дополнительной функциональности там не развернуто.


Я разрабатываю клиент к этому сервису. Мне надо выполнить запрос вида "все Г, для которых существует В, удовлетворяющее таким-то условиям, связанным с текущим Г" (например "все заказы, покупатель которых младше 18 лет"), и мне надо выполнить его на стороне БД из соображений производительности. Каков полный набор действий, который мне, как разработчику клиента, надо совершить, чтобы этого добиться?

  1. Не вижу каких либо сложностей в реализации любого сервиса.


  2. В моей терминологии — это расширение (считайте это плагином). Я описываю в статье свое решение и использую свои термины. Расширение может написать любой программист, не затрагивая моих авторских прав на пример этого сервиса. Модификация кода — всегда затрагивает авторские права.


  3. Реализуете ваш_класс.ваш_метод, который вернет требуемый вам запрос. Далее сервис найдет ваш запрос, подставит в него параметры и отправит на выполнение в СУБД. Получит результат (только тот, который вам требуется) и отдаст вам в требуемом формате.


Не вижу каких либо сложностей в реализации любого сервиса.

Вы это серьезно, или все-таки просто забыли упомянуть какие-то (возможно, очевидные вам) ограничения?


В моей терминологии — это расширение (считайте это плагином). Я описываю в статье свое решение и использую свои термины.

Окей, давайте в ваших терминах. Я хочу иметь возможность сделать JOIN не используя расширения (или плагины). Как неоднократно говорилось, РСУБД мне такое позволяет.


Реализуете ваш_класс.ваш_метод, который вернет требуемый вам запрос. Далее сервис найдет ваш запрос

Вы не пропустили никакой шаг? Я просил полный набор действий.

:-)


Вам сколько раз надо написать, что ни каких ограничений на реализацию любого сервиса пример универсального сервиса не накладывает. Может жирным шрифтом нужно выделить?


Сервис не накладывает каких либо ограничений на выполняемые запросы в СУБД. При использовании расширений Вы можете выполнить любой запрос в СУБД.


Не пропустил. Вам нужно реализовать только ваш_класс.ваш_метод который вернет сгенерированный SQL по переданным в этот метод параметрам. Все остальное за вас сделает этот сервис.

Вам сколько раз надо написать, что ни каких ограничений на реализацию любого сервиса пример универсального сервиса не накладывает. Может жирным шрифтом нужно выделить?

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


Сервис не накладывает каких либо ограничений на выполняемые запросы в СУБД. При использовании расширений Вы можете выполнить любой запрос в СУБД.

Подождите, я же явно написал: не используя расширений. А вы мне пишете "при использовании расширений".


Вам нужно реализовать только ваш_класс.ваш_метод который вернет сгенерированный SQL по переданным в этот метод параметрам. Все остальное за вас сделает этот сервис.

Вот я реализовал этот класс. Он лежит у меня в версионном хранилище. Как сервис его "за меня" найдет?

:-) Давайте обсуждать то, что написал я. Если Вы хотите обсуждать ваши решения, напишите, опубликуйте и я, по возможности, присоединюсь к обсуждению.


Как сервис найдет "ваш код", я писал выше.

Давайте обсуждать то, что написал я.

Мы ровно ваши решения и обсуждаем. Просто вы отказываетесь отвечать на прямые и простые вопросы.


Как сервис найдет "ваш код", я писал выше.

Это было там, где вы написали " опубликовать его на сервере"? Проблема в том, что теперь вы утверждаете, что публикация не нужна. Так нужна или нет?

Спасибо, что натолкнули на мысль с "заказам" — манипулирование связанными данными во множестве таблиц. Подумаю, как это формализовать. Спасибо за дискуссию.


Смысла "топтаться на месте" больше не вижу.

Смысла "топтаться на месте" больше не вижу.

Я это трактую как "у меня нет ответа на поставленные вопросы".


Ок.

Трактуйте как хотите. :-)


Вы ужасно любите многократно задавать один и тот же вопрос и полностью игнорируете любые ответы. Не судьба, так не судьба.

Вы ужасно любите многократно задавать один и тот же вопрос и полностью игнорируете любые ответы.

Да нет, я не игнорирую прямые конкретные ответы. Но, к сожалению, в данном треде от вас их пока не было. А додумывать я не люблю, потому что регулярно выясняется, что додумал неправильно.

Как не было? Все ваши "хотелки" решаются — реализацией расширения (плагина). ЛЮБЫЕ хотелки

Моя "хотелка" включает в себя не реализовывать расширение. Я не хочу никак вмешиваться в уже развернутый сервис.

Не вмешивайтесь. Кто заставляет? Пользуйтесь готовой функциональностью.

Пользуйтесь готовой функциональностью.

Которая не позволяет сделать JOIN. А мне надо JOIN и не вмешиваться в сервис.

не проблема, ответ по JOIN см выше

не проблема, ответ по JOIN см выше

Там, вроде бы, было сказано "при использовании расширений". А мне надо JOIN, и не писать расширения.

не хотите, не пишите, ни кто не заставляет

… как тогда получить JOIN?

см ответ выше

Ну то есть никак.


Получается ровно то, о чем я написал больше пяти часов назад: сделать JOIN (или любой другой запрос, затрагивающий более одной сущности одновременно) без расширения сервиса нельзя.


Что и требовалось доказать.

ответил уже пару десятков раз — написать расширение

Ну да, и тем самым подтвердили мой тезис: без расширения сервиса — нельзя.

Есть! См статью.

Что — "есть"? В статье слово JOIN не упоминается ни разу.

Упоминается, см расширения

Упоминается

Вас не затруднит привести цитату? Похоже, меня обманывает полнотекстовый поиск.


расширения

Напомню про введенное выше граничное условие: без расширений.


Удивительно, честное слово. Казалось бы, что сложного — признать, что такое использование не задумывалось, так сделать нельзя. Это нормально, у каждой системы свои сценарии использования. Но нет, вы продолжаете ходить по кругу, утверждая, что можно сделать что-то (что не совпадает с тем, что мне нужно).

1-ое утверждение.


Пример реализации сервиса готов работать с любыми данными в любых таблицах любой предметной области!


2-ое утверждение.


Сервис ориентируется на входные параметры для генерации запроса и метаданные полученного результата для формирования ответа.


3-е утверждение.


Сервис ничего не знает о предметной области, данными которой он манипулирует. Т.е не знает как вы хотите "сложить" данные из множества таблиц и по каким условиям это делать.


4-е утверждение.


Для того чтобы сервис смог "сложить" данные из множества таблиц в один результат, Вы должны сказать сервису как это сделать. Есть два варианта решения этого вопроса. 1-ый вариант. Реализовать в сервисе функция выполнения любого запроса. 2-ой вариант. Реализовать механизм расширения.


Вопросы?

Да нет, вы опять подтвердили то, что я говорил: нельзя сделать JOIN (или любой другой запрос, затрагивающий более одной сущности одновременно) без расширения сервиса.

можно, см утв. 4


Вы должны и обязаны сказать сервису как вы хотите объединить данные таблиц. Пока Вы это не скажите, ни одна реализация не сможет выполнить ваш запрос.


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


Я выбрал 2-ой вариант, в котором написать расширения не значит написать требуемый сервис. Вы просто говорите (пишите SQL — запрос) как хотите сложить данные из множества таблиц. Если у Вас будет множество таких расширений, у Вас есть возможность управлять правами доступа разных пользователям к эти расширениям. Все.


Вопросы?

можно, см утв. 4

"Утверждение 4" не применимо к вашему сервису, который мы и обсуждаем, потому что оно оперирует двумя вариантами, а вы, по вашему же признанию, уже выбрали один из них:


Я выбрал 2-ой вариант, в котором написать расширения не значит написать требуемый сервис.

И этот выбор подтверждает то, что я озвучил раньше: в вашем сервисе нельзя сделать JOIN (или любой другой запрос, затрагивающий более одной сущности одновременно) без расширения сервиса.

Ну, если можно, то приведите пример запроса на data/table, который это делает.

см. выше

Там нет примера такого запроса. Следовательно, нельзя.

можно, см. выше

Так и запишем: нельзя. И пока не приведете примера, так и останется.


Нет примера — нельзя.

Можно, см выше

есть, все уже расписал, повторятся не буду, см выше

Интересное решение.
А как быть с транзакциями, например?
Чем это решение лучше PostgRESTa?
Такое апи страшно будет выставлять наружу.

Не совсем понимаю первый вопрос, но проблем с транзакциями никаких нет.


Это универсальный пример, будет работать с любой БД любого производителя, легко расширяемое решение.


В чем, Вы видите "стах" выставления наружу? Доступно гибкая настройка прав доступа, можно настроить любое сочетание. Больше чем разрешено, использовать будет нельзя.

проблем с транзакциями никаких нет.

Да? Как получить несколько записей из разных таблиц в рамках одной транзакции БД? (сразу оговорюсь: без расширения сервиса) Аналогично, как записать в несколько таблиц с сохранением консистентности?


Доступно гибкая настройка прав доступа, можно настроить любое сочетание.

Дадада, я выше уже спросил, как настроить простенькое разделение прав, ответа так и не было.

Нет каких либо проблем с транзакций.


:-) Если Вы чего то не знаете, то это вовсе не означает, что это не возможно или это не поддерживается.


Похоже Вы не в состоянии понять написанное #comment_21247274
Поясню более подробно. Сервис реализован в рамкам спецификации J2EE и спецификация JAAS (Java Authentication and Authorization Service) в полном вашем распоряжении. Интересует, почитайте и настраивайте права доступа в любом сочетании.


Дополнительно, можно поднять множество копий источников данных (DataSource) с разными правами в БД (под разными учетными записями БД), множество копий этого сервиса (каждая копия сервиса со своей копий источника данных) и играйтесь доступом как Вам вздумается.


Прошу отметить, что все это в одном WEB-приложении и ни каких изменений в коде.

Нет каких либо проблем с транзакций.

Прекрасно, приведите пример запроса, реализующего озвученное мной выше. В смысле, HTTP-запроса.


это вовсе не означает, что это не возможно или это не поддерживается.

Я вполне готов признать, что я чего-то не понимаю. Просто покажите пример.


Сервис реализован в рамкам спецификации J2EE и спецификация JAAS (Java Authentication and Authorization Service) в полном вашем распоряжении.

И как мне это поможет при работе с REST-сервисом?


Дополнительно, можно поднять множество копий источников данных (DataSource) с разными правами в БД (под разными учетными записями БД), множество копий этого сервиса (каждая копия сервиса со своей копий источника данных) и играйтесь доступом как Вам вздумается.

Ну так это как раз признание того, что ваш сервис этого не может — вам приходится все делегировать в БД.

так как Вы многократно задаете одни и те же вопросы и игнорируете все ответы, то предпочту отослать вас любой поисковик по поиску интересующих Вас вопросов.


Вы же все равно проигнорируете все мои ответы, и опять зададите те же самые вопросы, чтобы я вам не ответил.

Да нет, меня устроит пример HTTP-запроса, который делает то, что мне нужно (и не требующий расширения сервиса). Вы нигде и никогда не привели такого примера.

Я не знаю, что Вам нужно.

Казалось бы, явно написано выше:


  • выбрать записи из двух таблиц одним запросом
  • получить несколько записей из разных таблиц в рамках одной транзакции БД
  • записать в несколько таблиц с сохранением консистентности
  • сделать так, чтобы внешняя система, обращающаяся в контексте разных пользователей, имела доступ к разным колонкам одной и той же таблицы

Все это без расширения сервиса (т.е., обращением на data/table) и строго по HTTP(s).

опишите подробнее

Какой из пунктов? (нет, все не буду)

опишите подробнее вашу задачу, что вы хотите получить, примеры входных-выходных данных, описание таблиц, примеры записей в таблицах и т.д.

Нет.


Необходимое и достаточное описание второй задачи звучит так: есть две таблицы, А и Б, экспонированные в вашем сервисе как data/table/А и data/table/Б. Я читаю строки по некоторому условию из А, потом по некоторому условию из Б. Мне нужно, чтобы между этими чтениями (которые являются независимыми HTTP-запросами) была гарантия repeatable read.


Приведите пример HTTP-запросов, решающих эту задачу.

выполняете запрос ...data/object/… получаете требуемый результат. Хоте подробностей?
Опишите подробно, что хотите

выполняете запрос ...data/object/… получаете требуемый результат

Этого пути нет в статье.


И я явно сказал, что мне нужно больше одного запроса.


Как я уже сказал, описание задачи достаточно для ответа на вопрос, поддерживаются ли транзакции. Если вам нужны подробности, задавайте конкретные вопросы.

Пардон, пропустил .../data/query/{object}


Вы требуете от меня пример и игнорируете все примеры выше. Напишите подробно что хотите, а то опят заявите что это не то что вам нужно.

Пардон, пропустил .../data/query/{object}

Это явно противоречит требованию "без использования расширений".


Вы требуете от меня пример и игнорируете все примеры выше.

Я их не игнорирую: я каждый раз указываю вам на то, какому из моих требований они не соответствуют. Вот и в этот раз вы опять пропустили требование "без расширений", хотя оно было явно озвучено:


Все это без расширения сервиса (т.е., обращением на data/table) и строго по HTTP(s).

Что за требование?

Оно написано прямо в том комментарии, на который вы только что отвечали:


без расширения сервиса (т.е., обращением на data/table) и строго по HTTP(s).

Откуда она взялось?

Оно было изначально.

Вы ошибаетесь:


Получается, "стандартный" (без вмешательства в код сервиса) механизм этого не позволяет, на каждый новый запрос над существующими сущностями надо писать расширение для сервиса?

Я озвучивал требование невмешательства в развернутый сервер неоднократно за вчерашний день. Если вы за все это время его не заметили и не осознали — это, честное слово, не мои проблемы.

И кто посмел вмешаться в сервис? Его код модифицирован? Нет!

Это уже тоже вчера проходили, именно поэтому, специально для вас, я с тех пор озвучиваю это требование как "без расширения сервиса".

Проходили, верно, сегодня вы снова решили обсудить это еще раз.


Какое требования? Поясните.

Очень простые требования.


Сервис полностью заморожен. В него нельзя вносить никакие изменения. Никакие расширения. Ни одной строчки кода.


Все, что можно — это писать HTTP-запросы.

public class Lair

public String join (String lang, MultivaluedMap<String, String> parameters, ArrayList<HashMap<String, Object>> records, ArrayList<Object> list) throws Exception {
     ...
     return "select ... join ...";
}

}

Далее ../data/query/Lair.join?...


Получите требуемый вам результат.

Противоречит требованию "без расширения сервиса".

какому требованию?

Озвученному прямо в комментарии на который вы отвечаете: "без расширения сервиса". Ваш класс — это расширение сервиса.

Эта ваша блаж, нет такого требования

А не важно, блажь это или нет. Вы либо можете решить задачу с учетом этого требования, либо нет.

обоснуйте ваше требование, чем оно вызвано, почему оно так важно для Вас?

Это все не важно. Вы либо можете его выполнить, либо нет.

Я не понимаю, поясните.

Не понимаете требование? Оно озвучено неоднократно, могу повторить еще раз: никакого вмешательства в сервис (целиком, включая расширения). Проще говоря, все, что можно — это слать к нему HTTP-запросы.

Хотите подробный ответ, дайте подробное описание вашей задачи. Не можете?

Я не хочу подробный ответ, я хочу последовательность HTTP-запросов, делающих то, что мне нужно. Что мне нужно, я описал достаточно подробно.


А вы, простите за прямоту и оценочное суждение, просто всеми силами уходите от того, чтобы прямо признать: нет, этот сервис не может того, что вы запрашиваете.

Я догадался откуда "ноги растут" у вашего требования. Вам дали задание сделать что то подобное, но Вы не знаете как. Подсказываю ...


Делаете так


<form ...>
...
<textarea name="sql"></textarea>
...
</form>

так


{"sql":"select ... join ..."}

или так


<query>
<sql>select ... join ...</sql>
</query>

Принимаете на сервере, выполняете, возвращаете результат.


И начинаете гордится своей дырявой системой.

Вы догадались неправильно.

Пользуйся, не стесняйся

Было бы чем.

:-) Идеей. Вы же меня 2 день пытаете — "хочу произвольный запрос, без модификации"


Я дал вам идею — любой запрос, хоть join, хоть with.
И ни какой модификации сервиса.

Я спрашиваю, как это сделать в вашем сервисе. Он так может? Принять на вход произвольный SQL?

как сделать в моем сервисе, см выше.


Мой предыдущий ответ Вас не устраивает? Это же осуществление вашей мечты.

как сделать в моем сервисе, см выше.

Да, никак.


Мой предыдущий ответ Вас не устраивает?

Нет.


Это же осуществление вашей мечты.

Вы ничего не знаете про мои мечты.

На Вас не угодишь, это не годится, и другое плохо.


Решайте вашу проблему самостоятельно.

Решайте вашу проблему самостоятельно.

Давно решил.


В данном случае я просто очередной раз удостоверился, что ваш сервис поставленную задачу мной не решает.

Отличная новость, вашу душа теперь будет спокойна.

Хорошо! Констатирую — сформулировать требования не можешь или не умеешь!

… раньше вам это не мешало утверждать, что ваш сервис может все выполнить. То, что вы перешли к этому аргументу, для меня достаточно красноречиво говорит, что я был прав, когда вам не поверил.


Нельзя, знаете ли, одновременно говорить "нет такого требования" и "требование непонятно сформулировано".

Наконец то и до Вас дошло, что мой сервис может все. :-)

Нет, не может. Пока что он не может даже простенькие поставленные мной задачи.


И уж тем более он не может некоторые более интересные вещи.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории