I have this issue in production with MySQL connections where the connection is either being used or it's not opened error comes up frequently. I think when multiple requests hit the method then this issue is happening. I got stats from production were 80 different instances hit the Graphql method. I am using Sqlkata to make DB calls. When there are no parallel calls then it works fine.
ConnectionManager.cs
public IDbConnection GetConnection
{
get
{
if (_iDbConnection != null)
{
if (_iDbConnection.State != ConnectionState.Open)
{
_iDbConnection.Open();
return _iDbConnection;
}
}
if (_iDbConnection != null && _iDbConnection.State == ConnectionState.Open)
{
// close the previous connection
_iDbConnection.Close();
// open new connection
_iDbConnection.Open();
return _iDbConnection;
}
try
{
string connectionString = Configuration.GetConnectionString("seasonal");
// Register the factory
DbProviderFactories.RegisterFactory("MySqlConnector", MySqlConnectorFactory.Instance);
// Get the provider invariant names
IEnumerable<string> invariants = DbProviderFactories.GetProviderInvariantNames();
var factory = DbProviderFactories.GetFactory(invariants.FirstOrDefault());
var conn = factory.CreateConnection();
if (conn != null)
{
conn.ConnectionString = connectionString;
conn.Open();
_iDbConnection = conn;
}
}
catch (Exception e)
{
throw;
}
return _iDbConnection;
}
}
Service (constructor)
public OutboundRecordService(IConnectionManager connectionManager) : base(connectionManager)
{
IDbConnection connection = connectionManager.GetConnection;
if (connection.State != ConnectionState.Open)
{
_logger.Error($"Connection is not open, current state: {connection.State}");
}
_queryFactory = new QueryFactory(connection, new MySqlCompiler());
_logger = LogManager.GetLogger(typeof(OutboundRecordService<T>));
}
public async Task<CareMetx.Service.Models.PaginationResult<OutboundRecord>> GetAllByCriteria(OutboundRecordSearchCriteria searchCriteria)
{
try
{
// START - Test code
var arrayTask = new List<Task>();
int i = 10;
for (int c = 0; c < i; c++)
{
arrayTask.Add(Task.Factory.StartNew(() => GetDataFromDB(searchCriteria)));
}
Task.WaitAll(arrayTask.ToArray());
Console.WriteLine("All threads complete");
return await Task.FromResult<CareMetx.Service.Models.PaginationResult<OutboundRecord>>(null);
// END - Test code
}
catch (Exception ex)
{
var message = ex.Message;
}
return null;
}
private async Task<List<OutboundRecord>> GetDataFromDB(OutboundRecordSearchCriteria searchCriteria)
{
Query dbQuery = _queryFactory.Query("SELECT * FROM OutboundRecords Where BatchId = 1");
// Clone the query and get the total count
var totalCountQuery = dbQuery.Clone();
totalCountQuery = totalCountQuery.AsCount();
// Log Record Count SQL
LogSqlQuery(totalCountQuery);
// Get the total record count
var totalRecords = await totalCountQuery.FirstOrDefaultAsync<int>();
}
Exception
Related
I send SQL command to ODBC to be able to insert into another application's database.
Looping in selected forms and its rows, I create command.
"OnTransactionCommand" simply returns an sql string of related row to be sent to ODBC for table 'STOCKTRN'
But the problem is that my integration function sometimes returns the error below:
ERROR [HY000] [TOD][ODBC][GENESIS]VISION: Cannot insert into 'STOCKTRN',No locks available
I am not sure but it is probably about the number of execution. With similar data when I test it with 15-20 records it works nicely. But Working with +50 records it returns error.
Is there any kind of limit or I am missing another part ?
My function:
private void MTransaction(MyGridView gvList)
{
try
{
var m_Integration = ctx.Integration.Take(1).FirstOrDefault();
if (m_Integration != null)
{
DbProviderFactory mFactory= DbProviderFactories.GetFactory(m_Integration.ServerType);
using (DbConnection dbcon = mFactory.CreateConnection())
{
dbcon.ConnectionString = m_Integration.ConnString;
for (int i = 0; i < gvList.RowCount; i++)
{
if (Convert.ToBoolean(gvList.GetRowCellValue(i, "Select")))
{
dbcon.Open();
int m_TransactionId = Convert.ToInt32(gvList.GetRowCellValue(i, "Id"));
MTransaction m_Transaction = ctx.Transaction.Where(c => c.Id == m_TransactionId).FirstOrDefault();
using (DbTransaction dbtr = dbcon.BeginTransaction())
{
try
{
using (DbCommand dbcmd = dbcon.CreateCommand())
{
dbcmd.Transaction = dbtr;
if (m_Transaction != null)
{
int TransactionRowCounter = 1;
foreach (var item in m_Transaction.TransactionRow)
{
dbcmd.CommandText = OnTransactionCommand(m_Transaction, item, TransactionRowCounter);
dbcmd.ExecuteNonQuery();
TransactionRowCounter++;
}
}
dbtr.Commit();
}
}
catch (Exception err)
{
dbtr.Rollback();
dbcon.Close();
XtraMessageBox.Show(err.Message);
continue;
}
}
dbcon.Close();
}
}
}
}
}
catch (Exception err)
{
SuccessMessage = "Error:\n" + err.Message;
}
}
I have a android app created with xamarin.
This is the code that crashes, not the first time, but often on the second time!
public void InsertOrUpdateInventoryWithoutEntries(Inventory inventory)
{
_logger.Debug("Enter");
try
{
var db = _dataBaseConnection.GetSqLiteConnection();
using (db)
{
var existingDbInventory = db.Find<DbInventory>(dbInventory => dbInventory.Code ==
inventory.Code);
if (existingDbInventory != null)
{
if (!existingDbInventory.Finished ) // do not update if finished.
{
existingDbInventory.Description = inventory.Description;
existingDbInventory.OpenTime = inventory.OpenTime;
existingDbInventory.Finished = inventory.Finished ;
existingDbInventory.UseInventoryList = inventory.UseInventoryList;
existingDbInventory.PostedToServer = inventory.PostedToServer;
existingDbInventory.InventoryListIsDownloaded =
inventory.InventoryListIsDownloaded;
UpdateInventory(existingDbInventory,db);
}
}
else
{
db.Insert(DbInventory.FromInventory(inventory));
}
db.Close();
}
}
catch
(SQLiteException ex)
{
_logger.Error(ex);
throw;
}
}
private void UpdateInventory(DbInventory inventory, SQLiteConnection db)
{
_logger.Debug("Enter");
try
{
var result = db.Update(inventory);
}
catch (SQLiteException ex)
{
_logger.Error(ex);
throw;
}
}
public bool InsertOrUpdateInventoryEntry(InventoryEntry inventoryEntryModel,
SQLiteConnection db=null)
{
_logger.Debug("Enter");
bool disposeFlg = false;
//detta då sqllite inte klarar av samtidiga anrop så bra, så man skall bara använda en
connection i taget !
if (db == null)
{
db = _dataBaseConnection.GetSqLiteConnection();
disposeFlg = true;
}
var existingDbInvetoryRow = db.Find<DbInventoryEntry>(dbInventoryRow =>
dbInventoryRow.ItemId == inventoryEntryModel.ItemId && dbInventoryRow.InventoryCode ==
inventoryEntryModel.InventoryCode);
if (existingDbInvetoryRow != null)
{
existingDbInvetoryRow.Cost = inventoryEntryModel.Cost;
existingDbInvetoryRow.Quantity = inventoryEntryModel.Quantity;
db.Update(existingDbInvetoryRow);
}
else
{
db.Insert(DbInventoryEntry.FromInventoryEntry(inventoryEntryModel));
}
if (disposeFlg)
{
db.Close();
db.Dispose();
}
return true;
}
private bool InsertInventoryRows(IEnumerable<InventoryEntry> inventoryEntryModels)
{
_logger.Debug("Enter");
var dbRows = inventoryEntryModels.Select(entry =>
(DbInventoryEntry.FromInventoryEntry(entry)));
var db = _dataBaseConnection.GetSqLiteConnection();
using (db)
{
db.InsertAll(dbRows);
db.Close();
}
return true;
}
The error I get is:
SQLite.SQLiteException: 'database is locked' or SQLite.SQLiteException: 'database is busy'
I found the solution thanks to Jason - github.com/praeclarum/sqlite-net/issues/700
I would advise you to keep a single SQLiteConnection for your app and cache it to take advantage of the type mapping caching strategy. Opening it with the Create | ReadWrite | FullMutex flags will ensure all operations are multithread-wise serialized. Don't forget to Dispose the connection whenever your app closes
This worked perfectly and speeded up the app ! Thanks Jason !
What i did was to handle one static connection that i held open all the time !
I have a series of asynchronous functions that are cascaded, but when it finishes executing the last, it does not return the values to the previous ones.
This is where my first call is run. This is a WebAPI function and always comes to an end.
[HttpGet]
[Route("integracao/iniciar")]
public IHttpActionResult FazerIntegrar()
{
try
{
Integrar objIntegrar = new Integrar();
return Ok(objIntegrar.Integra());
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}
so my function is in my library is called. Within my function I have a for executing only once. The flow is never resumed by it to continue the loop
public async Task<bool> Integra()
{
var files = Directory.GetFiles(#"C:\inetpub\wwwroot\Atendup\Arquivos\Backup\");
bool retorno = false;
if (files != null)
{
foreach (var item in files)
{
retorno = false;
using (StreamReader sr = new StreamReader(item))
{
if (sr != null)
{
while (sr.EndOfStream == false)
{
string line = await sr.ReadLineAsync();
string[] grupo = line.Split(new[] { "#*#" }, StringSplitOptions.None);
procData objProc = new procData();
objProc.proc = grupo[0];
objProc.name = JsonConvert.DeserializeObject<List<string>>(grupo[1]);
objProc.valor = JsonConvert.DeserializeObject<List<object>>(grupo[2]);
objProc.tipo = JsonConvert.DeserializeObject<List<Type>>(grupo[3]);
_context = new IntegrarRepository("online_pedidopizza");
retorno = await _context.IntegrarAsync(objProc);
//retorno = await _context.IntegrarAsync(objProc);
}
}
}
if (retorno == true)
{
await DeleteAsync(item);
}
}
}
return retorno;
}
I have a third function just to mediate with the repository
public async Task<bool> IntegrarAsync(procData objProc)
{
return await this.SendIntegrarAsync(objProc);
}
And finally, communication with the database, all code is executed correctly. Debugging you can get to the end of this fourth function but then the debug stop and does not go back to the beginning
protected async Task<bool> SendIntegrarAsync(procData parametro)
{
bool retorno = false;
using (SqlConnection conn = new SqlConnection(""))
{
using (SqlCommand cmd = new SqlCommand(parametro.proc, conn))
{
cmd.CommandType = CommandType.StoredProcedure;
if (parametro != null)
{
for (int i = 0; i < parametro.name.Count; i++)
{
AdicionaParametro(cmd, parametro.name[i], parametro.valor[i], parametro.tipo[i]);
}
}
try
{
cmd.CommandTimeout = 300;
await conn.OpenAsync().ConfigureAwait(false);
var resultado = await cmd.ExecuteScalarAsync().ConfigureAwait(false);
if (resultado != null)
{
retorno = Convert.ToBoolean(resultado);
}
}
catch (Exception ex)
{
Logs objLog = new Logs()
{
metodo = MethodBase.GetCurrentMethod().Name,
classe = this.GetType().Name,
dados = parametro,
data = DateTime.Now,
mensagem = ex.Message,
exception = ex.InnerException == null ? "" : ex.InnerException.ToString()
};
objLog.Adiciona();
string name = DateTime.Now.ToBinary().ToString();
using (StreamWriter sw = new StreamWriter(#"C:\inetpub\wwwroot\Atendup\Arquivos\Backup\" + name + ".txt"))
{
string line = "";
line += parametro.proc + "#*#";
line += JsonConvert.SerializeObject(parametro.name) + "#*#";
line += JsonConvert.SerializeObject(parametro.valor) + "#*#";
line += JsonConvert.SerializeObject(parametro.tipo) + "#*#";
sw.WriteLine(line);
}
}
}
}
return retorno;
}
What should I have to do? Thanks
Your Web Api call is not async try changing it to:
[HttpGet]
[Route("integracao/iniciar")]
public async Task<IHttpActionResult> FazerIntegrar()
{
try
{
Integrar objIntegrar = new Integrar();
return Ok(await objIntegrar.Integra());
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}
I use following script to get data from external service and store in dB. In certain rare cases less than 1% records gets updated with null values. In below code, the "re.status=fail" we see null. let us know if any thots.
public void ProcessEnquiries()
{
List<req> request = new List<req>();
var options = new ParallelOptions { MaxDegreeOfParallelism = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["MaxDegreeOfParallelism"]) };
try
{
Parallel.ForEach(request, options, currentRequest =>
{
ProcessedRequest processedRequest = null;
processedRequest = CommunicateToWS(currentRequest); // Here we call to webservice
});
}
catch (AggregateException exception)
{
foreach (Exception ex in exception.InnerExceptions)
{
// Handle Exception
}
}
}
public ProcessedRequest CommunicateToWS(req objReq)
{
ProcessedRequest re = new ProcessedRequest();
using (WebCall obj = new WebCall())
{
re.no = refnu;
try
{
retval = obj.getValue(inval);
objProxy.Close();
//get data
// parse and store to DB
}
catch (Exception e)
{
re.status = "fail";
//update DB that request has failed
//Handle Exception
obj.Close();
}
}
}
I hava access DB, one of my function(C#.net) need to Exec a SQL more than 4000 times with transaction.
It seems that after execution the DB file stay opened exclusively. because there is a *.ldb file, and that file stay there for a long time.
Is that caused by dispose resources incorrectly???
private int AmendUniqueData(Trans trn)
{
int reslt = 0;
foreach (DataRow dr in _dt.Rows)
{
OleDbParameter[] _params = {
new OleDbParameter("#templateId",dr["Id"].ToString()),
new OleDbParameter("#templateNumber",dr["templateNumber"].ToString())
};
string sqlUpdateUnique = "UPDATE " + dr["proformaNo"].ToString().Substring(0,2) + "_unique SET templateId = #templateId WHERE templateNumber=#templateNumber";
reslt = OleDBHelper.ExecSqlWithTran(sqlUpdateUnique, trn, _params);
if (reslt < 0)
{
throw new Exception(dr["id"].ToString());
}
}
return reslt;
}
the transaction:
using (Trans trn = new Trans())
{
try
{
int reslt=AmendUniqueData(trn);
trn.Commit();
return reslt;
}
catch
{
trn.RollBack();
throw;
}
finally
{
trn.Colse();
}
}
forget closing the database connection.