Действительно ли эта хранимая процедура ориентирована на многопотоковое исполнение? (или независимо от того, что equiv находится на SQL Server),

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

я полагаю, что часть проблемы имеет отношение, должен ли GC удалить старые Экземпляры класса от генерала перманента, или нет. Как правило, каждый раз, когда Вы горячий развертываетесь, новые экземпляры класса добавляются к пулу памяти PermGen, и старые, теперь неиспользованные, обычно не удаляются. По умолчанию JVMs Sun не выполнит сборку "мусора" в PermGen, но это может быть включено с дополнительными аргументами команды "Java".

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

, Если Ваше веб-приложение не закрывается полностью при неразвертывании - если оно оставляет выполнение Потока, например - тогда, все Экземпляры класса, используемые тем веб-приложением, будут прикреплены в пространстве PermGen. Вы повторно развертываете и теперь имеете другую целую копию всех этих Экземпляров класса, загруженных в PermGen. Вы не развертываетесь, и Поток продолжает идти, прикрепляя ДРУГОЙ набор экземпляров класса в PermGen. Вы повторно развертываете и загружаете целый сетевой набор копий..., и в конечном счете Ваш PermGen заполняется.

можно иногда фиксировать это:

  • аргументы команды Предоставления к недавней JVM Sun для включения GC в PermGen и классов. Это: -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled
  • Используя другую JVM, которая не нанимает фиксированный размерный PermGen или это делает GC на загруженных классах

, Но это поможет только [1 120], если Ваше веб-приложение закроется полностью и чисто, не оставляя живые ссылки ни на один из Экземпляров класса никакого Класса загруженными загрузчиками Класса для того веб-приложения.

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

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

6
задан OMG Ponies 27 September 2009 в 16:46
поделиться

4 ответа

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

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

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

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

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

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

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

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

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

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

17
ответ дан 8 December 2019 в 03:27
поделиться
CREATE PROCEDURE [dbo].[usp_NewTicketNumber]
    @NewID int OUTPUT
AS
BEGIN
    SET NOCOUNT ON;
    BEGIN TRY
        BEGIN TRANSACTION
        INSERT INTO 
            [dbo].[TicketNumber] ([CreatedDateTime], [CreatedBy])
        VALUES
            (GETDATE(), SUSER_SNAME())

        SET @NewID = SCOPE_IDENTITY()

        COMMIT TRANSACTION;
    END TRY
    BEGIN CATCH
        IF XACT_STATE() <> 0
            ROLLBACK TRANSACTION;
        SET @NewID = NULL;
    END CATCH
END

I would not use RETURN for meaningful use data: either recordset or output parameter. RETURN would normally be used for error states (like system stored procs do in most cases):

EXEC @rtn = EXEC dbo.uspFoo
IF @rtn <> 0
    --do error stuff

You can also use the OUTPUT clause to return a recordset instead.

This is "thread safe", that is it can be run concurrently.

3
ответ дан 8 December 2019 в 03:27
поделиться

First off - why don't you just return the new ticket number instead of 0 all the time? Any particular reason for that?

Secondly, to be absolutely sure, you should wrap your INSERT and SELECT statement into a TRANSACTION so that nothing from the outside can intervene.

Thirdly, with SQL Server 2005 and up, I'd wrap my statements into a TRY....CATCH block and roll back the transaction if it fails.

Next, I would try to avoid specifying the database server (TestDB42) in my procedures whenever possible - what if you want to deploy that proc to a new server (TestDB43) ??

And lastly, I'd never use a SET NOCOUNT in a stored procedure - it can cause the caller to erroneously think the stored proc failed (see my comment to gbn below - this is a potential problem if you're using ADO.NET SqlDataAdapter objects only; see the MSDN docs on how to modify ADO.NET data with SqlDataAdapter for more explanations).

So my suggestion for your stored proc would be:

CREATE PROCEDURE [dbo].[usp_NewTicketNumber]
AS
BEGIN
  DECLARE @NewID INT

  BEGIN TRANSACTION
  BEGIN TRY
    INSERT INTO 
      [dbo].[TicketNumber]([CreatedDateTime], [CreatedBy])
    VALUES
      (GETDATE(), SUSER_SNAME())

    SET @NewID = SCOPE_IDENTITY()

    COMMIT TRANSACTION
  END TRY
  BEGIN CATCH
    ROLLBACK TRANSACTION
    SET @NewID = -1
  END CATCH

  RETURN @NewID
END

Marc

1
ответ дан 8 December 2019 в 03:27
поделиться

Я согласен с ответом Дэвида Холла, я просто хочу немного рассказать о том, почему в данной ситуации IDENT_CURRENT абсолютно не подходит.

У нас был разработчик, который его использовал. Вставка из клиентского приложения произошла в то же время, когда база данных импортировала миллионы записей посредством автоматического импорта. Возвращенный ему id был из одной из записей, импортированных моим процессом. Он использовал этот идентификатор для создания записей для некоторых дочерних таблиц, которые теперь были прикреплены не к той записи. Что еще хуже, сейчас мы не знаем, сколько раз это происходило, прежде чем кто-то не мог найти информацию, которая должна была быть в дочерних таблицах (его изменение производилось в течение нескольких месяцев). Мой автоматический импорт мог не только повлиять на его код, но другой пользователь, вставивший запись в это время, мог бы сделать то же самое. Ident_current никогда не следует использовать для возврата идентификатора только что вставленной записи, поскольку он не ограничен процессом, который ее вызывает.

1
ответ дан 8 December 2019 в 03:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: