2016-12-09 6 views
7

Я написал код в C# 6.0 .NET 3.5 CLR с уровнем безопасности = external_access.Можно ли изменить статические переменные readonly в C# SQLCLR?

Уменьшенный код:

public static readonly DataTable warnings_table = init_warnings_table(); 

public static void set_warning(string msg) 
{ 
     var row = warnings_table.NewRow(); 
     row[1] = DateTime.Now; 
     row[2] = msg; 
       ... 
     warnings_table.Rows.Add(row); 
} 
[Microsoft.SqlServer.Server.SqlProcedure] 
public static SqlInt32 wrapper_func(SqlInt32 param) 
{ 
    return big_func(Param.Value); 
} 

int big_func(int param) 
{ 
    SqlBulkCopy bulkcopy; 
    .... 
    set_warning("Message"); 
    .... 
    write_warnings(bulkcopy); 
    warnings_table.Clear(); 
} 

Что будет происходить с warnings_table если wrapper_func будет вызываться из 2-х или более различных соединений/сессий одновременно? Существуют операции записи в статическое поле warnings_table. Итак, я полагаю, но не уверен, это приведет к состоянию гонки данных здесь.

Другими словами:

  1. ли static read-only переменные в SQLCLR уникальный для каждого соединения SQL/SQL запросов/транзакций или же они обмена данными между различными вызовами процедур SQLCLR?

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

+0

Инстинкт кишки должен сказать, что нет - единственное глобальное состояние, в котором вы должны работать в рамках системы баз данных, должно быть таблицами. На данный момент не могу дать вам главу и стих о конкретной документации. –

ответ

6

ли static read-only переменные в SQLCLR уникальный для каждого соединения SQL/SQL запросов/транзакций или же они обмена данными между различными вызовами процедур SQLCLR?

сборочной проживающих внутри SQL Server (т.е. SQLCLR) загружается в один App домена, который является общим для всей всех сессий. Могут существовать несколько доменов приложений, поскольку они специфичны для каждой базы данных и владельца (т. Е. Авторизации). Но любой конкретный объект SQLCLR будет находиться только в одной конкретной Ассамблее, поэтому все обращения к нему действительно разделяют этот единственный экземпляр. Вот почему все методы SQLCLR должны быть static, поскольку они не являются сеансами. Итак, да, статические переменные-члены/класс являются общими, поэтому их нужно объявить как readonly, иначе у Ассамблеи должно быть PERMISSION_SET из UNSAFE, если статическая переменная класса не помечена как readonly.

Возможно ли иметь безболезненное глобальное состояние, безопасное от других вызовов процедур SQLCLR?

Нет, по крайней мере, не в любой простой, встроенной моде. Статическую переменную класса, которая представляет собой коллекцию, можно рассматривать как реальную таблицу, созданную в tempdb (не такую ​​как глобальная временная таблица - ##Table). После создания переменной он останется и не исчезнет после завершения «сеанса», который его создал, но доступен для всех сеансов. Поэтому, если вам нужно иметь разделение по сеансу, тогда вам нужно, чтобы свойство статической коллекции было дифференциатором - что-то, что бы рассказать каждую сессию отдельно. И вы могли бы получить текущий session_id/@@ SPID и использовать его, если вы очищаете все записи, имеющие тот же самый session_id, в начале каждого процесса, поскольку значения session_id повторно используются SQL Server. Но невозможно очистить записи для значений session_id, которые не используются повторно, если только вы не сделаете это как последний шаг в конце процесса (шаг, который не может быть вызван, если процесс запускается в исключение). Так что это не невозможно, но займет немного, но работы и много тестирования :-).

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

Пожалуйста, обратите внимание, один нюанс, который вы должны знать в отношении статических переменных и как SQL Server управляет памятью является:

Иногда SQL Server, если она запущена из физической памяти, может принять решение для разгрузки одного или нескольких доменов приложений. Вы можете увидеть это поведение в журнале ошибок SQL Server с помощью функции поиска для «давления памяти», так как там будет записей в виде: (. {Имя_б_д} {owner_name} [время выполнения] .Y)

AppDomain X обозначается для разгрузки из-за давления памяти.

Разгрузка домена приложения устраняет статические переменные. Когда он будет перезагружен при следующем вызове объекта SQLCLR, статические переменные будут созданы снова.

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

Если вам нужен на-сессия глобальное состояние, то вам необходимо использовать сервера SQL встроенных механизмов выполнения T-SQL заявления с использованием Context Connection = true; в строке подключения. Вы можете использовать:


Для получения дополнительной информации о работе с SQLCLR в целом , см. серию, которую я пишу по этой теме в SQL Server Central (требуется бесплатная регистрация):

Stairway to SQLCLR