Який найкращий метод додати поводження з помилками у збережених документах SQL 2005?


11

Який хороший спосіб зробити збережені програми досить надійними, щоб вони могли дуже масштабувати, а також містити обробку помилок?

Окрім того, який найкращий спосіб обробляти кілька сценаріїв помилок у збереженій програмі та мати інтелектуальну систему зворотного зв’язку, яка повертає змістовну інформацію про помилки викликам?


2
Спробуйте використати новіший блок TRY CATCH у SQL Server 2005. sommarskog.se/error_handling_2005.html
Reddy

Привіт @Kacalapy ~ Я хотів би рекомендувати надалі ставити кожне питання самостійно, і таким чином ми можемо мати конкретні відповіді, орієнтовані на одне питання за один раз. Я закликаю вас зробити це з цим питанням.
jcolebrand

Відповіді:


12

Олексій Кузнєцов має велику главу у своїй книзі Захисне програмування баз даних (Глава 8), яка охоплює налаштування T-SQL TRY ... CATCH, транзакції T-SQL та SET XACT_ABORT, а також використовує керування помилками на стороні клієнта. Це дуже допоможе вам вирішити, який із варіантів має найбільш сенс для того, що вам потрібно виконати.

Він доступний безкоштовно на цьому сайті . Я жодним чином не пов’язаний з цією компанією, але в мене є версія на паперовій версії цієї книги.

На цю тему існує дуже багато дрібних деталей, які дуже добре пояснив Олексій.

За запитом Ніка ... (але не все це в главі)

Щодо масштабування, ви повинні бути по-звірячому чесними щодо того, які дії повинні бути в коді db, а які - у програмі. Ви коли-небудь помічали, як швидко виконує код, як правило, повертається до розробки для однієї проблеми за методом?

Найпростіший спосіб спілкування - це власні коди помилок (> 50 000). Це також досить швидко. Це означає, що вам доведеться синхронізувати код DB та код програми. За допомогою спеціального коду помилки ви також можете повернути корисну інформацію в рядку повідомлення про помилку. Оскільки у вас є код помилки виключно для цієї ситуації, ви можете написати аналізатор у коді програми, адаптованому до формату даних про помилку.

Крім того, які умови помилок потребують логіки повторної роботи в базі даних? Якщо ви хочете повторити спробу через X секунд, вам краще попрацювати з цим кодом програми, щоб транзакція не блокувалась так сильно. Якщо ви одразу повторно подаєте операцію DML, повторення її в ІП може бути ефективнішим. Майте на увазі, що для повторної спроби вам, можливо, доведеться дублювати код або додати шар SP.

Дійсно, на даний момент це найбільший біль з TRY ... Логіка CATCH у SQL Server на даний момент. Зробити це можна, але це трохи ой. Подивіться на деякі вдосконалення, що стосуються цього в SQL Server 2012, особливо повторне викидання системних винятків (зберігши початковий номер помилки). Крім того, існує FORMATMESSAGE , який додає певної гнучкості у створенні повідомлень про помилки, особливо для цілей реєстрації.


Чудова порада і дуже хороша книга!
Мар'ян

Red Gate пропонує кілька надзвичайно корисних безкоштовних електронних книг, і ця, безумовно, одна з кращих. Чудова пропозиція.
Метт М

Це роблять не всі їхні книги, але безкоштовна версія книги Кузнецова «Оборонний ...» не містить останніх 2 глави про рівні ізоляції транзакцій та розробляючі модифікації, які виживають одночасно. Для мене. вміст там варто було придбати.
Філ Хельмер

7

Це наш шаблон (журнал помилок видалено)

Примітки:

  • Без XACT_ABORT всі TXN, які починаються та виконуються / повертаються, повинні бути спарені
  • Декрети комісії @@ TRANCOUNT
  • Відкат повертає @@ TRANCOUNT до нуля, щоб ви отримали помилку 266
  • ЗВЕРНІТЬ тільки поточний шар (наприклад, декремент @@ TRANCOUNT при відкаті)
  • XACT_ABORT пригнічує помилку 266
  • Кожна збережена програма повинна відповідати одному шаблону, щоб кожен виклик був атомним
  • Перевірка на відкат насправді є зайвою через XACT_ABORT. Однак мені стає краще, виглядає дивно без, і дозволяє створювати ситуації, коли ти цього не хочеш
  • Це дозволяє використовувати клієнтські TXN (наприклад, LINQ)
  • У Ремуса Русану є аналогічна оболонка, яка використовує точки збереження. Я віддаю перевагу атомному виклику БД і не використовую часткових оновлень, як їхня стаття

... тому не створюйте більше TXN, ніж вам потрібно

Однак,

CREATE PROCEDURE [Name]
AS
SET XACT_ABORT, NOCOUNT ON

DECLARE @starttrancount int

BEGIN TRY
    SELECT @starttrancount = @@TRANCOUNT

    IF @starttrancount = 0
        BEGIN TRANSACTION

       [...Perform work, call nested procedures...]

    IF @starttrancount = 0 
        COMMIT TRANSACTION
END TRY
BEGIN CATCH
    IF XACT_STATE() <> 0 AND @starttrancount = 0 
        ROLLBACK TRANSACTION
    RAISERROR [rethrow caught error using @ErrorNumber, @ErrorMessage, etc]
END CATCH
GO

що робити, якщо @@ TRANCOUNT більше 0? Ви не робите жодної роботи чи маєте відгуки?
kacalapy

@kacalapy: немає такої речі, як вкладена транзакція, тому ми не запускаємо ще одну scribd.com/doc/49579859/33/Nested-Transaction-Are-Real
gbn

3

Я використовую Try / Catch, але також збираю якомога більше інформації і записую її до журналу помилок ПІСЛЯ відката. У цьому прикладі "LogEvent" - це збережена процедура, яка записується в таблицю EventLog, що містить подробиці того, що сталося. GetErrorInfo () - виклик функції, який повертає точне повідомлення про помилку.

Коли виникає помилка, інформація збирається, процедура пропускається до розділу з обробкою помилок і видає відкат. Інформація записується в журнал, після чого процедура виходить.

Враховуючи додаткові процедури / функціонування дзвінків, які задіяні, це здається трохи вище. ЯКЩО цей метод надзвичайно корисний при спробі налагодження проблеми.

exec LogEvent @Process, @Database, "Спроба вставити бла-бла-бла"
ПОЧАТИ Спробувати
  вставити в MyTable
  виберіть Значення
    від MyOtherTable

  виберіть @rowcount = @@ ROWCOUNT
ЗАКОННИЙ Спробуйте
- ErrorHandling
ПОЧАТИТИ СЛОВА
  виберіть @error = ERROR_NUMBER (),
         @rowcount = -1,
         @TableAction = 'вставити',
         @TableName = @Database + '.MyTable',
         @AdditionalInfo = '(Спроба вставити бла-бла-бла)' + dbo.GetErrorInfo ()
   GOTO TableAccessError
ЗАКРІЙНИЙ КЛЮЧ

.
.
.
.

TableAccessError:
ЯКЩО (@@ TRANCOUNT> 0) ПОВЕРНЕННЯ
виберіть @output = верхній (@TableAction) + 
       "ПОМИЛКА. Під час" + "сталася помилка 
       випадок (@TableAction)
         коли 'оновити', то 'оновити'
         коли 'видалити', то 'видалити'
         else @TableAction + 'ing'
       кінець + 
       'записи' + 
       випадок (@TableAction) 
         коли "вибрати", то "з" 
         коли 'оновити', то 'в' 
         коли "вставити", то "в"
         ще 'від'   
         кінець + 
         "таблиця" + @TableName + "."
виберіть @output = @output + '@@ ПОМИЛКА:' + конвертувати (varchar (8), @ помилка) 
виберіть @output = @output + '@@ ROWCOUNT:' + конвертувати (varchar (8), @ rowcount) 

виберіть @output = @output + isnull (@AdditionalInfo, '')
exec LogEvent @Process, @Database, @Output
RAISERROR (@ вихід, 16,1) з журналом
виберіть @ReturnCode = -1
GOTO THE_EXIT


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.