Пул соединений ODP.net: ClientID, Client Identifier никогда не меняется от первого пользователя, который входит в систему - PullRequest
1 голос
/ 23 апреля 2011

Сценарий : у нас есть приложение, которое использует Oracle 10g и последнюю версию ODP.net в приложении ASP.net.Мы используем свойство .ClientID WriteOnly для объекта OracleConnection для передачи определенного идентификатора пользователя в базу данных для целей аудита.Когда пул соединений отключен, это работает отлично.

Когда он включен, первый пользователь, который входит в систему (например, USER1), обновляет запись, и MODIFIED_BY - это USER1, но когда другой пользователь отправляется на веб-сайт после этого, захватывая таким образом объединенное соединение, MODIFIED_BYвсе еще USER1, несмотря на передачу USER2 в ClientID.

Наша логика базы данных выглядит следующим образом:

Мы сохраняем класс в сеансе ASP.net, в котором есть наша логика подключения к базе данных.При первом вызове это наш конструктор:

Public Sub New(ByVal connection As String, Optional ByVal oracleClientID As String = "")
        MyBase.New()
        _oracleConnection = New OracleConnection(connection)
        _clientID = oracleClientID
        End If
    End Sub

Суть кода для открытия и закрытия соединения, распоряжения:

Try
    _OraCmd = New OracleCommand(command, _oracleConnection)
    With _OraCmd
        .BindByName = True
        .Parameters.Clear()
        .CommandType = CommandType.StoredProcedure
        _oracleConnection.Open()
            If _clientID <> "" Then _oracleConnection.ClientId = _clientID
        Dim OraDadpt As New OracleDataAdapter(_OraCmd)
            '' Logic to get data
        OraDadpt.Fill(ds)
    End With
Catch ex As Exception
    Throw ex
Finally

    ClearParameters()
    _OraCmd.Dispose()
    _oracleConnection.Close()
End Try

Суть в том, что, поскольку соединениеВ пуле есть предполагаемый вызов триггера LOGON, который никогда не происходит, и идентификатор клиента никогда не устанавливается снова.В документации ORACLE, однако, говорится, что ClientID используется именно для того, что мы пытаемся сделать.

Есть ли у кого-нибудь какие-либо мысли относительно того, почему для SYS_CONTEXT ('USERENV', 'CLIENT_IDENTIFIER') не установлено значениеновый USERID, который передается в ClientID, когда пул соединений используется в нашем приложении .NET с ODP.net?Это настройка базы данных, настройка слушателя?Мы будем благодарны за любую помощь.

ОБНОВЛЕНИЕ

Мы передали проблему в Oracle.При этом нам пришлось создать небольшое тестовое приложение, которое имитировало проблему.При этом на моем локальном хосте все работало идеально, используя встроенный веб-сервер Cassini в Visual Studio. В IIS проблема возникает.

ОБНОВЛЕНИЕ

Определено, что проблема не в IIS.Переменные пакета не очищались из-за того, что соединения, которые были объединены, были повторно использованы, по сути, то, что пул должен делать.Мы решили это с помощью DBMS_SESSION.MODIFY_PACKAGE_STATE (DBMS_SESSION.REINITIALIZE).

Ответы [ 5 ]

3 голосов
/ 30 апреля 2011

Попробуйте использовать DBMS.Rest_Package перед закрытием соединений.

Я думаю, проблема в том, что при включенном пуле ODP поддерживает соединение, так как каждый пользователь открывает и закрывает соединение с ODP, пул поддерживает сеанспакетные переменные в памяти;до истечения времени ожидания соединения.Однако, поскольку время ожидания истекло, и восстановление соединения из базы данных с пулом происходит только ПОСЛЕ ВОЗВРАТА соединения в пул, вы работаете с данными сеанса другого пользователя.

1 голос
/ 25 апреля 2011

Работает нормально как при включении, так и при выключении пула. ClientId и ClientInfo в сеансе Oracle не обновляются до тех пор, пока не будет выполнена команда.

Не могли бы вы подтвердить правильность заявления if? Если _clientID <> "" Тогда _oracleConnection.ClientId = _clientID. Даже если вы закроете соединение, clientId останется прежним. Не уверен, где вы устанавливаете / получаете _clientId, когда вы передаете это в свой метод.

class Program
{
    static void Main(string[] args)
    {
        TestClientId test = new TestClientId();
        test.DoSomething("FirstClientId");
        test.DoSomething("ChangedClientId");
    }
}

public class TestClientId
{
    /// <summary>
    /// The connection string. 
    /// </summary>
    private const string ConnString = "DATA SOURCE=//server:port/service_name;USER ID=user;PASSWORD=pswd;";

    /// <summary>
    /// The oracle connection.
    /// </summary>
    private OracleConnection connection;

    /// <summary>
    /// The oracle session id.
    /// </summary>
    private long sid;

    /// <summary>
    /// Initializes a new instance of the <see cref="TestClientId"/> class.
    /// </summary>
    public TestClientId()
    {
        this.connection = new OracleConnection(ConnString);
    }

    /// <summary>
    /// Changes the client id of the oracle connection.
    /// </summary>
    /// <param name="clientId">The client id.</param>
    public void DoSomething(string clientId)
    {            
        this.connection.Open();
        this.sid = this.GetSessionId(this.connection);

        if (!string.IsNullOrEmpty(clientId))
        {
            this.connection.ClientInfo = clientId;
            this.connection.ClientId = clientId;                
        }

        OracleCommand command = new OracleCommand("select * from dual", this.connection);
        command.ExecuteNonQuery();

        this.connection.Close();
    }

    /// <summary>
    /// Gets the session id.
    /// </summary>
    /// <param name="con">The connection object.</param>
    /// <returns>The current oracle session id.</returns>
    public int GetSessionId(OracleConnection con)
    {
        OracleCommand cmd = new OracleCommand();
        cmd.Connection = con;
        cmd.CommandText = "select SYS_CONTEXT('USERENV','SID') from dual";
        object sid = cmd.ExecuteScalar();
        return Convert.ToInt32(sid);
    }
}
1 голос
/ 26 апреля 2011

ClientId сбрасывается только при закрытии соединения, а если вы закрываете, то его привязка должна быть сброшена.

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

Так что было бы хорошо установить идентификатор сеанса с помощью DBMS_SESSION.SET_IDENTIFIER

Надеюсь, это поможет

0 голосов
/ 30 апреля 2011

Когда пул соединений включен, что является хорошим и, конечно же, правильным способом в сценарии ASP.NET (и фактически в большинстве сценариев), вы не должны хранить любое соединение БД. Вы должны открывать и закрывать соединения, когда вам это нужно.

Вот ссылка на SQL Server, но это то же самое с Oracle, которая объясняет это: SqlConnection Class

Таким образом, код, который вам нужно использовать при вызове Oracle, должен быть примерно таким, где угодно в вашем приложении, когда вам это нужно:

Using connection As New OracleConnection(connectionString)
    connection.Open()
    ' Do work here; connection closed on following line.
End Using

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

0 голосов
/ 25 апреля 2011

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

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

Кроме того, триггер LOGON, вероятно, выполняется только тогда, когда соединение с базой данных создается в первый раз, но не выполняется снова, когдаСоединение используется повторно для другого запроса или другого пользователя.

Чтобы устранить проблему, захватите соединение с базой данных в начале каждого запроса и явно установите идентификатор клиента (и / или выполните код, выполняемый командойЛОГОН триггер).Затем используйте это соединение на время запроса.Но не храните его где-нибудь после завершения запроса.

Таким образом, ваше соединение всегда правильно инициализируется в контексте текущего пользователя.И вы придерживаетесь правил пула соединений.

...