private static void TryFinallyLeak()
{
var connection = new SqlConnection("Server=DBSRV;Database=SampleDB");
try
{
connection.Open();
var command = new SqlCommand("select count (*) from Blogs", connection);
command.ExecuteScalar(); // in case of exception here, connection won't be closed
connection.Close();
}
catch(Exception e)
{
// handle exception
}
}
private static void TryFinallyLeak()
{
var connection = new SqlConnection("Server=DBSRV;Database=SampleDB");
try
{
connection.Open();
var command = new SqlCommand("select count (*) from Blogs", connection);
command.ExecuteScalar();
}
catch(Exception e)
{
// handle exception
}
finally
{
connection.Close(); // connection is closed in any case
}
}
private static void ReaderLeak()
{
var reader = GetReader();
while (reader.Read())
;
reader.Close(); // closing the reader doesn't close the connection
}
private static SqlDataReader GetReader()
{
var connection = new SqlConnection("Server=DBSRV;Database=SampleDB");
connection.Open();
var command = new SqlCommand("select * from Blogs", connection);
// the created reader doesn't close the connection as
// it doesn't use CommandBehavior.CloseConnection
return command.ExecuteReader();
}
private void nPlus1(int count)
{
using var dbContext = new BlogContext();
var blogs = dbContext.Blogs.ToList(); // get list of blogs (1 query)
// for each blog get all posts (N queries)
foreach (var blog in blogs)
{
Console.WriteLine($"Posts in {blog}:");
foreach (var post in blog.Posts)
Console.WriteLine($"{post}");
}
}
public class BlogContext: DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
// ...
}
上述代码将导致 N+1 查询,其中 N 是帖子总数(选择所有博客 + 从每个博客中选择帖子)。
修正方法
您应该尝试通过单个请求从数据库获取所有所需数据。 例如:
private void nPlus1(int count)
{
using var dbContext = new BlogContext();
var blogs = dbContext.Blogs
.Include(b => b.Posts) // get all posts to memory (1 query)
.ToList();
// the code below works locally (0 queries)
foreach (var blog in blogs)
{
Console.WriteLine($"Posts in {blog}:");
foreach (var post in blog.Posts)
Console.WriteLine($"{post}");
}
}
数据库记录
如果数据库命令返回的记录数量超过阈值,DPA 会将运行该命令的代码标记为 DB 连接 问题。 在某些情况下,获取大量记录是设计使然。 但有时,这可能是由于次优代码模式意外导致的。