C# 建立数据库连接的最佳方法是什么(静态、抽象、每个请求等)?

C# 建立数据库连接的最佳方法是什么(静态、抽象、每个请求等)?,c#,entity-framework,design-patterns,C#,Entity Framework,Design Patterns,我使用了很多连接到db的模型,在我上一个与C#&entity framework合作的项目中,我为db连接创建了静态类,但我在打开和关闭连接时遇到了问题,因为当超过10-15个请求聚集在一起时,会出现错误,我通过改变连接db的方法解决了这个问题,我现在根据请求连接,并删除了所有静态方法和类 现在我想知道 建立连接的最佳模式是什么? 我应该在每次查询后关闭它并在使用之前打开它还是 静态类中的连接是一个很好的模型(我不需要这样做) 每次都要创造它吗 这个问题有好的设计模式吗 所有这些都是为了同一个问

我使用了很多连接到db的模型,在我上一个与C#&entity framework合作的项目中,我为db连接创建了静态类,但我在打开和关闭连接时遇到了问题,因为当超过10-15个请求聚集在一起时,会出现错误,我通过改变连接db的方法解决了这个问题,我现在根据请求连接,并删除了所有静态方法和类

现在我想知道

建立连接的最佳模式是什么?

  • 我应该在每次查询后关闭它并在使用之前打开它还是
  • 静态类中的连接是一个很好的模型(我不需要这样做) 每次都要创造它吗
  • 这个问题有好的设计模式吗
  • 所有这些都是为了同一个问题,什么是最好的方法 建立数据库连接(静态、抽象、每个请求等)
  • 例如我在短信发送者网络面板上工作时,我应该每秒发送100K条短信,这些短信与其他人一起收集并制作一个包,每个包有1~20条短信,然后我需要每秒发送5K~100K个包,当我发送包时,我应该执行以下步骤:

  • 将单个短信更新为已发送或未发送
  • 如果已交付,则更新用户余额减少useraccounts表中的用户余额
  • 更新用户表中sms发送计数的数目
  • 更新手机号码表中的sms发送计数
  • 更新发件人号码表中sms发送计数的号码
  • 更新包表中已传递和失败的sms的包
  • 更新包,了解线程如何在包表中发送此包
  • 更新线程表,了解有多少sms通过此线程发送,以及有多少失败
  • 在AccountDocument表中添加此交易记录的帐户文档
  • 所有的步骤和很多其他事情,比如日志、用户界面和监控小部件,这些都应该完成,我需要DB连接来完成每一个事务


    现在,连接到DB的最佳模式是什么?通过人工请求、线程请求或每个事务..

    我认为每个请求的伸缩性最好。使用线程安全连接池,并使连接范围与工作单元一致。让负责事务行为和工作单元的服务签出连接,使用它,并在提交或回滚工作单元时将其返回到池中

    更新:

    10-12秒提交状态更新?你做错了别的事。你的书面问题不足以提供合适的答案

    是1.3B个事务,每天8小时的计算结果是每秒约45K个事务。你们的交易量是纳斯达克的两倍。如果你想用一台机器,我会说纳斯达克使用的服务器不止一台


    我还想知道你是否可以不使用ACID更新状态。毕竟。也许更好的解决方案是使用生产者/消费者模式和阻塞队列,在发送状态后尽可能更新这些状态。

    问题的答案:

  • 把它关上。NET在后台为您执行连接池

  • 创造它。每次都使用using(Connection conn=new…)-这样,您将充分利用.NET池机制

  • 您可以使用.NET线程池(或您自己的自定义线程池),将线程池定义为仅并行使用10个线程,并将工作项逐个排队。这样,在同一时间使用的连接不会超过10个,而且可能会更快。 有关自定义线程池的详细信息:

  • 每个实例


  • 以下是我对架构的建议:

  • 为要发送的挂起SMS创建数据库表(队列)

  • 每行将包含sms+当前状态所需的所有信息

  • 创建一个工作进程,可能是一个windows服务,它将不断地对这个表进行采样——比方说,每5秒一次。它将选择状态为“待发送”的前20条短信(应表示为int)。并将状态更新为“正在发送”

  • 每个sms都将使用windows服务端上的自定义线程池发送

  • 在流程结束时,所有已处理的sms状态都将使用CTE更新为“完成”(通用表表达式-您可以发送一个CTE,其中包含所有已处理的sms行ID,以便将“批量更新”状态更新为“完成”)

  • 您可以使状态更新存储过程与“getpending”存储过程相同。通过这种方式,您可以选择无锁更新,并使数据库工作得更快

  • 这样,您可以运行不止一个处理器服务(但随后您必须释放nolock)

  • 记住要尽量避免锁定

    顺便说一句,这也很好,因为您可以从系统中的任何位置发送SMS,只需在挂起的SMS表中添加一行即可


    还有一件事,我不建议为此使用实体框架,因为它有太多的工作要做。这种任务只需调用3-4个存储过程即可。请看一看——它是一个非常轻量级的MicroDal框架,在大多数情况下比EF(实体框架)快10倍以上。我应该在每次查询后关闭它吗?

    .Net会为您这样做,所以让它来处理它,这是一个垃圾收集器任务。所以不要费心手动处理对象,这是Jon Skeet的一个很好的答案:。但是,您可以使用
    using(IDisposable){}
    语句强制GC执行其工作。下面是一篇关于资源重新分配的好文章:

    2。静态类中的连接是否良好?

    从不创建数据上下文
    public class FooContextService {
        private readonly FooContext _ctx;
    
        public FooContext Context { get { return _ctx; } }
    
        public FooContextService() {
            _ctx = new FooContext();
        }
    }
    
    public class UnicornService {
        private readonly FooContext _ctx;
    
        public UnicornService(FooContextService contextService) {
            if (contextService == null)
                throw new ArgumentNullException("contextService");
    
            _ctx = contextService.Context;
        }
    
        public ICollection<Unicorn> GetList() {
            return _ctx.Unicorns.ToList();
        }
    }
    
    public class DragonService {
        private readonly FooContext _ctx;
    
        public DragonService(FooContextService contextService) {
            if (contextService == null)
                throw new ArgumentNullException("contextService");
    
            _ctx = contextService.Context;
        }
    
        public ICollection<Dragon> GetList() {
            return _ctx.Dragons.ToList();
        }
    }
    
    public class FantasyController : Controller {
        private readonly FooContextService _contextService = new FooContextService();
    
        private readonly UnicornService _unicornService;
        private readonly DragonService _dragonService;
    
        public FantasyController() {
            _unicornService = new UnicornService(_contextService);
            _dragonService = new DragonService(_contextService);
        }
    
        // Controller actions
    }
    
    public class FooContextService {
        private readonly FooContext _ctx;
    
        public FooContext Context { get { return _ctx; } }
    
        public FooContextService() : this(true) { }
    
        public FooContextService(bool proxyCreationEnabled) {
            _ctx = new FooContext();
            _ctx.Configuration.ProxyCreationEnabled = proxyCreationEnabled;
        }
    }
    
    (_context as IObjectContextAdapter).ObjectContext.Connection.Open();