简体   繁体   中英

ServiceStack: Detect if IDbConnection is “busy” - is a DataReader is open (trying to implement a “connection pool”)

I am testing out ServiceStacks OrmLite. I have previosly used MySql without OrmLite and now I am faced with the problem easiest described in this error message:

There is already an open DataReader associated with this Connection which must be closed first.

Since I have a multi-threaded application, certain threads will be polling the database, while other will insert, update or select "on demand", when needed. This results in the above mentioned exception.

What I need to do is to be able to detect if a connection (IDbHandler) is "busy"; has an open DataReader or something else that. If it is busy, take the next connection (from the "connection pool" i want to implement). The problem is, there is no method or property I can use in the IDbHandler object to determine if it is busy or not.

I have solved this in the "normal" mysql case by simply having a method where I send in the MySqlCommand or just the query string, like:

dbConnections.ExecuteQuery("SELECT * FROM test");
dbConnections.ExecuteQuery(cmd); // cmd == MySqlCommand

and the ExecuteQuery will handle of finding an open connection and just passing on the cmd/query there.

But, since I am using OrmLite it has a lot of extension methods to IDbConnection and I do not want to create "proxy methods" for each one. In the simple mysql case above, there is really only one method needed, that takes in a MySqlCommand, but not so with the many methods in OrmLite.

The first question:

  • How can I detect if a connection is busy? I want to avoid a try-catch situation to detect it.

Second question:

  • Is there some way to pass the entire "method" call, something like:

Example:

dbConnections.Run(iDbHandler.Select<MyObject>(q => q.Id > 10));
// or
dbConnections.Run(iDbHandler.Where<MyObject>(q => q.Id > 10));
// or
dbConnections.Run(iDbHandler.SomeOtherWeirdMetod<MyObject>(q => bla bla bla));

This is by far not the best solution, but it is an approach that I am testing with to see how it handles for my specific case (currently on ver 3.97). Like Ted, I am seeing frequent exceptions of open data readers, or connections being returned as closed.

In my usage all services inherit my parent service (which in turn inherits Service) that handles some common meta-data handling. I have opted to have my base service override the Service's Db property and do a quick check on the Db connection's state and attempt a recovery. One case this fixed immediately was the following:

My MsSql server is running in a failover cluster. When the SQL server flips from node A to node B, there is no built-in mechanism that I found in ServiceStack to detect that its in memory connections are "dirty" and need to reconnect.

Comments and improvements are most welcome.

public override System.Data.IDbConnection Db
{
    get
    {
        try
        {
            var d = base.Db;
            if (d == null || d.State != System.Data.ConnectionState.Open)
                return  ForceNewDbConn();
            else
                return d;
        }
        catch (Exception ex)
        {
            return ForceNewDbConn();
            //throw;
        }
    }
}

private IDbConnection ForceNewDbConn()
{
    try
    {
        var f = TryResolve<IDbConnectionFactory>();
        if (f as OrmLiteConnectionFactory != null)
        {
            var fac = f as OrmLiteConnectionFactory;
            fac.AutoDisposeConnection = true;
            var newDBconn = fac.Open();
            return newDBconn;
        }
        return base.Db;
    }
    catch (Exception ex)
    {
        throw;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM