Грамотно обработать исключения при работе c SQL Server
От: Ranger_XL  
Дата: 10.01.07 13:06
Оценка:
Добрый день.
Хочу посоветоваться с уважаемыми коллегами по следующему вопросу.

Некоторое время назад передо мной была поставлена задача написать программу,
осуществляющую пакетное преобразование файлов из внутреннего
формата некоторого приложения X в БД MSSQL Server. Обстоятельства
функционирования таковы, что программа должна будет ежедневно "доливать"
в готовую базу примерно по 1 млн. новых записей.
Также было предложено реализовать все это на платформе .NET.

Поскольку до этого я программировал в основном под Win32 на C++, то и писать стал
на С++. Но вскоре, испытав отвращение ко всем наворотам, введенным в VC++ для поддержки
.NET, я решил, что лучше, проще и элегантнее написать это на C#.

Но так как многих деталей C# я еще не знаю, есть некоторые сложности.

Самый неясный момент для меня сейчас: как грамотно организовать обработку исключений
(и запись их в журнал!) при работе с SQL server и при этом освободить ресурсы (connection)
в случае ошибки?


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

Вот фрагмент кода, но что-то подсказывает мне, что он еще далек от идеала


using System;
using System.Collections.Generic;
using System.Data.SqlClient;

//
// Записать все записи из памяти в БД одной транзакцией!
//
// В случае успеха все записи добавляются в таблицу cdr_records,
// а имя файла добавляется в таблицу cdr_files (COMMIT)
//
// В случае неудачи - ничего не происходит и делается запись в журнал (ROLLBACK)
//
static void WriteRecordsToDB (
    string shortFilename,            // in: имя CDR-файла
    List<CdrRecord> cdrRecordsList    // in: массив записей, прочитанных из CDR-файла
)
{
    try {
        // вариант с using(...) из примера MSDN
        using (SqlConnection connect = new SqlConnection (DBCONNECTION_STRING)) {

            // установить соединение с SQL сервером - может бросить исключение!
            connect.Open ();
            SqlTransaction transaction = connect.BeginTransaction ("MyTransaction");

            try {
                SqlCommand cmd = connect.CreateCommand ();
                cmd.Connection = connect;
                cmd.Transaction = transaction;
                cmd.CommandType = System.Data.CommandType.Text;

                // записать все записи из массива в БД
                for (int i = 0; i < cdrRecordsList.Count; ++i) {
                    CdrRecord rec = cdrRecordsList[ i ];

                    StringWriter strWriter = new StringWriter ();
                    strWriter.Write ("'{0}', '{1}', '{2}', '{3}', '{4}'",
                        rec.data_type, rec.field_a, rec.field_b, , rec.field_c, rec.field_d
                    );

                    cmd.CommandText = "INSERT INTO cdr_records " +
                        "(data_type, rec.field_a, rec.field_b, , rec.field_c, rec.field_d) " +
                        "VALUES (" + strWriter.ToString () + ")";
                    cmd.ExecuteNonQuery ();
                }

                // записать имя обработанного файла в БД
                cmd.CommandText = "INSERT INTO cdr_files (fname) VALUES ('" + shortFilename + "')";
                cmd.ExecuteNonQuery ();

                // попытаться завершить транзакцию
                transaction.Commit ();
            }
            catch (Exception ex) {
                LogMessage ("WriteRecordsToDB(): " + shortFilename + " is not processed.", ex);

                // попытать откатить транзакцию
                try {
                    transaction.Rollback ();
                }
                catch (Exception ex2) {
                    LogMessage ("WriteRecordsToDB(): transaction.Rollback() failed.", ex2);
                }
            }
        }
    }
    catch (Exception ex) {
        // перехват connect.Open(), BeginTransaction()
        LogMessage ("WriteRecordsToDB(): " + shortFilename + " is not processed.", ex);
    }
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.