08.08.2016, 06:43 | #1 |
Участник
|
Statement, запрос (несколько) с транзакцией
Товарищи, имею нижеописанную проблему.
Есть sql-запрос, который я вызываю из Ax обычным способом (Connection, Statement) Запрос состоит из трех частей, завернутых в одну транзакцию (транзакцию внутри запроса, через SQL-операторы BEGIN TRANSACTION, COMMIT TRANSACTION) - 1я часть это некоторый SELECT, потом некоторый INSERT, и третья - некоторый UPDATE. Если я выполняю запрос из Management Studio, я получаю в ответ сообщения вроде Цитата:
1 row affected;
2000 row affected; 3 row affected; Цитата:
1 row affected;
2000 row affected; ошибка такая-то Однако, когда я вызываю запрос из Ax с помощью Statement.executeUpdate(query) то в случае наличия ошибки в третьей (или во второй) части запроса - я об этом никак не узнаю. executeUpdate возвращает 0, getLastError, getLastErrorText - возвращают 0, будто бы операция успешно выполнена (т.к. успешно выполнился первый запрос в транзакции). Можно ли как-то в такой ситуации получить из Statement корректный отчет о выполнении запроса или добиться, чтобы он кидал ошибку в такой ситуации? Рабочим сейчас является следующий вариант: X++: Connection.ttsbegin() Statement.executeUpdate(query1); Statement.executeUpdate(query2); Statement.executeUpdate(query3); Connection.ttsCommit() Текст запроса разбит на 3 части, каждая из который вызывается отдельно внутри транзакции, организованной классом Connection. Если в одной из частей запроса происходит ошибка, то ttsCommit не вызывается - и все три запроса откатываются. Но у этого подхода есть один крупный недостаток: т.к. запросы выполняются отдельно, то, например, в третьем запросе я не вижу переменных, которые я DECLARE в первой части. |
|
08.08.2016, 07:04 | #2 |
Участник
|
А нельзя ли объединить все три части в один Statement и выполнить его за один executeUpdate?
|
|
08.08.2016, 07:08 | #3 |
Участник
|
Как описано в посте, если я объединяю в один Statement, то при наличии ошибки во второй-третьей части запроса (после первого успешного оператора SELECT) - не вызывает ошибку в statement.executeUpdate(), и Ax продолжает работать дальше, думая что запрос отработал корректно.
|
|
08.08.2016, 09:26 | #4 |
Участник
|
оберните свои запросы в блок try/catch внутри T-SQL
X++: begin try begin tran; -- commit tran; end try begin catch rollback tran; throw; end catch
__________________
Axapta v.3.0 sp5 kr2 |
|
|
За это сообщение автора поблагодарили: raz (5), Logger (3), gl00mie (2), Pandasama (1). |
08.08.2016, 10:39 | #5 |
Участник
|
Не помогло
Вот тестовый пример, аналогичный описываемой задаче: X++: public server static void testSQL() { Set permissionSet = new Set(Types::Class); Connection connection; Statement statement; str query; TestTable3798 testTable; //test table (SaveDataPerCompany = No) with one field str[10] named Field1 ; query += "BEGIN TRY \n"; query += "BEGIN TRANSACTION; \n"; query += "SELECT TOP 1 * FROM CustTable; \n"; query += "INSERT INTO TESTTABLE3798 (Field1, RecId) VALUES ('test', 123456); \n" ; query += "SELECT TOP 1 * FROM SYSTEMSEQUENCES WHERE NAME = -1; \n"; //query with error query += "COMMIT TRANSACTION; \n"; query += "END TRY \n"; query += "BEGIN CATCH \n"; query += "ROLLBACK TRANSACTION; \n"; query += "THROW; \n"; query += "END CATCH \n"; connection = new Connection(); statement = connection.createStatement(); permissionSet.add(new SqlStatementExecutePermission(query)); CodeAccessPermission::assertMultiple(permissionSet); statement.executeUpdate(query); CodeAccessPermission::revertAssert(); } Код: BEGIN TRY BEGIN TRANSACTION; SELECT TOP 1 * FROM CustTable; INSERT INTO TESTTABLE3798 (Field1, RecId) VALUES ('test', 123456); SELECT TOP 1 * FROM SYSTEMSEQUENCES WHERE NAME = -1; COMMIT TRANSACTION; END TRY BEGIN CATCH ROLLBACK TRANSACTION; THROW; END CATCH Цитата:
(1 row(s) affected)
(1 row(s) affected) (0 row(s) affected) Msg 245, Level 16, State 1, Line 5 Conversion failed when converting the nvarchar value 'Event' to data type int. |
|
30.11.2022, 21:47 | #6 |
Участник
|
Sorry, подниму здесь простой вопрос, чтобы не создавать новую тему.
Недавно обнаружил, что Statement.executeUpdate не возвращает ничего для простого update. Хотя в документации про return value сказано "An updated row count; otherwise, 0 (zero) for SQL statements that return nothing." X++: server static void test() { ResultSet rs; str sQuery; int qtyUpdated; ; // так, параметры вывода сообщений sQuery = "SELECT CASE WHEN (512 & @@OPTIONS) = 512 THEN 'ON' ELSE 'OFF' END AS a1"; new SQLStatementExecutePermission(sQuery).assert(); rs = new Connection().createStatement().executeQuery(sQuery); if (rs.next()) info(rs.getString(1)); CodeAccessPermission::revertAssert(); sQuery = "update [dbo].[TestTbl] set RecVersion = RecVersion+1;"; new SQLStatementExecutePermission(sQuery).assert(); // проверим, что никто не грохнул запись, пока мы мялись, как школьники у борделя qtyUpdated = new Connection().createStatement().executeUpdate(sQuery); info(int2str(qtyUpdated)); CodeAccessPermission::revertAssert(); } DAX2009 на ss2012r2, всё стоковое с последними хотфиксами и kb. Хотя в трёшке тот же эффект. Это норм или что-то где-то надо туда-сюда? |
|
01.12.2022, 01:35 | #7 |
Участник
|
Это норм. Документация в этой части не корректная.
То число, которое возвращает executeUpdate() - это признак успеха или ошибки 0 - выполнено успешно число - произошла ошибка Собственно, это же работа через ODBC, а драйвер ODBC просто не умеет возвращать количество обработанных строк. Вне зависимости от версии Axapta
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... |
|
|
За это сообщение автора поблагодарили: dim-gin (1), Logger (3). |
Теги |
error, executeupdate, sql, statement, transact sql, transaction |
|
|