让存储库手动打开和关闭数据库连接是不是一种糟糕的做法

本文关键字:一种 是不是 数据库连接 存储 | 更新日期: 2023-09-27 18:24:15

环境:ASP.NET MVC3 C#

假设我有一些存储库(semi-psuedo):

public interface IRepository
{
 create();read();update();delete();opendb();closedb();
}
public class CarRepository : IRepository
{
 private DbContext namedDbContext;
 public void opendb()
 {
  namedDbContext = new DbContext();
 }
 public void closedb()
 {
  namedDbContext.dispose();
 }
}

然后在控制器中,存储库被注入并按如下方式用于手动控制数据库连接寿命:

public class SomeController : Controller
{
    private IRepository CarRepository;
    public void SomeController(IRepository _carRepository)
    {
        CarRepository = _carRepository;
    }
    public ActionResult SomeAction(int CarId)
    {
        CarRepository.opendb();
        var car = CarRepository.read(CarId);
        CarRepository.closedb();
    }
}

这是否被认为是一种糟糕的做法,因为它从存储库中获取连接的控制权并将其放置在控制器中?我担心使用依赖项注入会导致内存泄漏,并希望确保不会打开重复的连接,也不会长时间运行和未使用。

让存储库手动打开和关闭数据库连接是不是一种糟糕的做法

是。当然大多数ADO.NET驱动程序都使用连接池,因此实际的连接过程并没有那么繁重。您有TransactionScope,它可以处理多个连接上的事务,但它不会像一个连接上一个事务那样快。

我担心使用依赖项注入会导致内存泄漏,并希望确保不会打开重复的连接,也不会长时间运行和未使用。

IoC将保证清理连接(大量用户已经确保了这一点)。不能保证程序员会在所有地方进行清理。

假设模式提供了持久层的抽象。它不应该公开任何持久性细节,比如数据库连接。如果存储是xml文件或云存储,该怎么办?

所以,是的,这是一种糟糕的做法。如果你想要更多的控制,你可以让存储库使用工作单元模式,这样更高的级别应该决定何时提交事务,但仅此而已。存储库不应该公开数据库的任何信息。

至于内存泄漏,请使存储库隐含IDispable(关闭任何未完成的打开连接),并确保DI容器管理每个请求的存储库实例,它将对其调用Dispose。

存储库的一部分是抽象持久性的细节。

我看到你的提议有两个问题:

  1. 通过将这些方法命名为"opendb"answers"closedb"和
  2. 如果按此路线进行,则应该从opendb()方法返回IDisposable(连接对象),并将该操作封装在using块中,以确保连接关闭

通常,您可以让存储库为每个方法创建一个连接,所以您只需要在存储库方法中正确地进行连接。当您想要对存储库执行多个操作,而不需要对每个部分使用单独的连接时,就会遇到挑战。

为了实现这一点,您可以从存储库中公开工作单元的概念。您的工作单元将实现存储库方法的接口,因此您不能在工作单元之外调用它们。它还将实现IDisposable,因此无论何时调用存储库,都将使用using块。在内部,存储库将管理连接,但既不会公开连接,也不会"谈论它"

例如:

public ActionResult SomeAction(int CarId)
{
     using (var repo = CarRepository.BeginUnitOfWork())
     {
        var car = repo.read(CarId);
        // do something meaningful with the car, do more with the repo, etc.
     }
}