MySqlConnection을 열 때 예외가 발생하지 않습니까?


14

비동기 및 작업으로 시작하고 코드 처리가 중지되었습니다. 들어오는 네트워크 패킷이 있고 패킷 처리기 내부의 데이터베이스와 통신하려고 할 때 발생합니다.

public class ClientConnectedPacket : IClientPacket
{
    private readonly EntityFactory _entityFactory;

    public ClientConnectedPacket(EntityFactory entityFactory)
    {
        _entityFactory= entityFactory;
    }

    public async Task Handle(NetworkClient client, ClientPacketReader reader)
    {
        client.Entity = await _entityFactory.CreateInstanceAsync( reader.GetValueByKey("unique_device_id"));

        // this Console.WriteLine never gets reached
        Console.WriteLine($"Client [{reader.GetValueByKey("unique_device_id")}] has connected");
    }
}

Handle 메서드는 비동기 작업에서 호출됩니다.

if (_packetRepository.TryGetPacketByName(packetName, out var packet))
{
    await packet.Handle(this, new ClientPacketReader(packetName, packetData));
}
else
{
    Console.WriteLine("Unknown packet: " + packetName);
}

문제를 일으키는 것으로 생각되는 방법은 다음과 같습니다.

public async Task<Entity> CreateInstanceAsync(string uniqueId)
{
    await using (var dbConnection = _databaseProvider.GetConnection())
    { 
        dbConnection.SetQuery("SELECT COUNT(NULL) FROM `entities` WHERE `unique_id` = @uniqueId");
        dbConnection.AddParameter("uniqueId", uniqueId);

        var row = await dbConnection.ExecuteRowAsync();

        if (row != null)
        {
            return new Entity(uniqueId, false);
        }
    }

    return new Entity(uniqueId,true);
}

DatabaseProvider의 GetConnection 메소드 :

public DatabaseConnection GetConnection()
{
    var connection = new MySqlConnection(_connectionString);
    var command = connection.CreateCommand();

    return new DatabaseConnection(_logFactory.GetLogger(), connection, command);
}

DatabaseConnection의 생성자 :

public DatabaseConnection(ILogger logger, MySqlConnection connection, MySqlCommand command)
{
    _logger = logger;

    _connection = connection;    
    _command = command;

    _connection.Open();
}

이 줄을 주석 처리하면 Console.WriteLine

_connection.Open();

3
Oracle의 MySQL Connector / NET (일명 MySql.Data)은 실제로 비동기 작업을 구현하지 않습니다. stackoverflow.com/a/40065501/23633 MySQL에서 비동기 작업을 사용하려면 nuget.org/로
Bradley Grainger

코드에 교착 상태가있는 것 같습니다. 이 경우 Visual Studio 디버거를 중단하고 병렬 스택 창을 여는 것이 좋습니다. 이것이 작업 (또는 일부 동기화 프리미티브)에서 차단되는 호출 스택이있는 하나 이상의 스레드를 표시하면 문제가 무엇인지 알려주거나 질문에 대한 자세한 내용을 편집하여 도움을 줄 수 있기를 바랍니다. 작업에서 스레드가 차단되지 않은 경우 완료되지 않은 작업이 있고 해당 코드를 활성화하지 않은 것일 수 await있습니다. 진단하기가 훨씬 어렵습니다.
Bradley Grainger

DatabaseConnection.DisposeAsync 구현을 추가 할 수 있습니까?
eisenpony

5 분을 기다리면 결국 예외가 발생합니까? Connection.open연결을 시도하는 동안 돌아 가지 않지만 시간 제한이 설정되면 결국 포기합니다. 또는 연결 개체의 시간 초과 값을 0보다 작은 숫자로 변경하고 예외가 있는지 확인할 수 있습니다.
weichch

답변:


1

.NET Core 3.1 콘솔 응용 프로그램에서 MySql.Data 8.0.19 및 MySqlConnector 0.63.2로 100 개의 병렬 작업을 회전시키는 POC 프로젝트를 실행했습니다. 모든 단일 작업의 컨텍스트에 연결을 작성하고 열고 처리합니다. 두 공급자 모두 오류없이 완료됩니다.

라이브러리는 비동기 메소드 서명 (예 : ExecuteReaderAsync () 또는 ExecuteScalarAsync ())을 제공하지만 MySqlConnector는 실제로 비동기 적 으로 실행되지만 MySql.Data 쿼리는 동 기적 으로 실행 됩니다.

다음과 같은 문제가 발생할 수 있습니다.

  • mysql 공급자와 특별히 관련되지 않은 교착 상태
  • 작업 내에서 예외를 올바르게 처리하지 못합니다 (작업 관련 집계 예외를 검사하고 mysql db 로그를 모니터링 할 수도 있습니다)
  • MySql.Data가 동 기적으로 실행될 때 많은 수의 병렬 작업을 실행하는 경우 작동하지 않는다고 가정 할 때 실행이 여전히 차단됩니다 (결과를 반환하지 않음).

0

MySQL 사용한 멀티 스레딩은 독립적 인 연결을 사용해야합니다. 멀티 스레딩은 MySQL의 질문이 아니라 클라이언트 언어 인 C #의 문제입니다.

즉, MySQL에 관계없이 스레드를 빌드 한 다음 쿼리를 수행해야하는 각 스레드에서 연결 작성하십시오. 스레드간에 데이터를 전달 해야하는 경우 어깨에있을 것입니다.

일반적으로 쿼리를 최적화하면 응용 프로그램을 다중 스레드하려는 유혹이 사라집니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.