J'ai besoin de conseils concernant une application que j'ai écrite. Les problèmes que j'ai sont dû à ma DAL et aux connexions à ma base de données SQL Server 2008 n'étant pas fermées, cependant j'ai regardé mon code et chaque connexion est toujours fermée.C# Application multithread et connexions SQL help
L'application est une application multithread qui récupère un ensemble d'enregistrements et pendant qu'elle traite un enregistrement, elle met à jour les informations à son sujet.
Voici le flux:
L'administrateur a la possibilité de définir le nombre de threads à exécuter et le nombre d'enregistrements par thread pour tirer.
Voici le code qui fonctionne après avoir cliqué sur démarrer:
adaptateurs sont des abstractions à mon DAL est un échantillon ici de ce qu'ils ressemblent:
public class UserDetailsAdapter: IDataAdapter<UserDetails>
{
private IUserDetailFactory _factory;
public UserDetailsAdapter()
{
_factory = new CampaignFactory();
}
public UserDetails FindById(int id){
return _factory.FindById(id);
}
}
Dès que le _factory est appelé traite le SQL et ferme immédiatement la connexion.
code pour App Fileté:
private int _recordsPerthread;
private int _threadCount;
public void RunDetails()
{
//create an adapter instance that is an abstration
//of the data factory layer
var adapter = new UserDetailsAdapter();
for (var i = 1; i <= _threadCount; i++)
{
//This adater makes a call tot he databse to pull X amount of records and
//set a lock filed so the next set of records that are pulled are differnt.
var details = adapter.FindTopDetailsInQueue(_recordsPerthread);
if (details != null)
{
var parameters = new ArrayList {i, details};
ThreadPool.QueueUserWorkItem(ThreadWorker, parameters);
}
else
{
break;
}
}
}
private void ThreadWorker(object parametersList)
{
var parms = (ArrayList) parametersList;
var threadCount = (int) parms[0];
var details = (List<UserDetails>) parms[1];
var adapter = new DetailsAdapter();
//we keep running until there are no records left inthe Database
while (!_noRecordsInPool)
{
foreach (var detail in details)
{
var userAdapter = new UserAdapter();
var domainAdapter = new DomainAdapter();
var user = userAdapter.FindById(detail.UserId);
var domain = domainAdapter.FindById(detail.DomainId);
//...do some work here......
adapter.Update(detail);
}
if (!_noRecordsInPool)
{
details = adapter.FindTopDetailsInQueue(_recordsPerthread);
if (details == null || details.Count <= 0)
{
_noRecordsInPool = true;
break;
}
}
}
}
Les accidents d'application, car il semble y avoir des problèmes de connexion à la base de données. En regardant dans mes fichiers journaux pour le DAL je vois ceci:
Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached
Quand je lance ce dans un thread, il fonctionne très bien. Je devine quand je cours son dans plusieurs fils je fais évidemment trop de connexions à la DB. Toute réflexion sur la façon dont je peux continuer à courir dans plusieurs threads et assurez-vous que la base de données ne me donne pas d'erreurs.
Mise à jour: Je pense que mes problèmes peuvent être des blocages dans ma base de données. Voici le code dans SQL qui exécute whe je reçois une erreur de blocage:
WITH cte AS (
SELECT TOP (@topCount) *
FROM
dbo.UserDetails WITH (READPAST)
WHERE
dbo.UserDetails where IsLocked = 0)
UPDATE cte
SET
IsLocked = 1
OUTPUT INSERTED.*;
Je n'ai jamais eu des problèmes avec ce code avant (dans d'autres applications). J'ai réorganisé mes index car ils étaient fragmentés à 99%. Cela n'a pas aidé. Je suis à perte ici.
C'est une bonne idée .... – DDiVita
L'appel '.Close()' ne ferme pas réellement la connexion quand le pooling est en cours d'utilisation. L'appel '.Dispose()' ne ferme pas non plus la connexion. La connexion est libérée dans le pool en appelant '.Close()' ou '.Dispose()' ('.Dispose()' appellera '.Close()' s'il n'est pas appelé avant d'être éliminé). TOUJOURS appeler '.Dispose()' (préférablement en utilisant une instruction using), et éventuellement appeler '.Close()' si la fantaisie vous prend. – Mark
C'est ce que je voulais dire par "il n'y a pas besoin de les fermer explicitement" (je ne savais pas que '.Close()' * still * ne les fermerait pas explicitement, cependant). Le bloc 'using' s'occupera de' .Dispose() 'une fois qu'il aura quitté la portée, et un DataAdapter devrait s'ouvrir implicitement. –