业务场景是这样的,要编写一个webapi程序,去调用存储过程。项目使用EFcore,我右键点击EFcore工具,再选择反向工程,自动生成了调用存储过程的方法,如果存储过程有返回值,还会自动生成一个对应要返回的数据库表的实体类。
问题来了,有一些存储过程运行时间很长,会导致超时。一旦发生超时的异常,线程就终止,而数据库正在执行的存储过程也会终止。底仓的原理无法知晓,通过一些测试,确实是这样。第一想到的是设置超时时间,这个超时是调用数据库存储过程的对象产生的超时,因为很长时间没有从数据库得到回应。在EF core里是对DbContext.Database执行SetCommandTimeout方法,也就是对命令执行的时间进行设置。这样设置之后,超时的问题解决了。
问题又来了,上级要我把同步改为异步。大概是以下的写法
[Route("UpdateOrderPlanShort")] public Task<List<Update_OrderPlan_ShortResult>> UpdateOrderPlanShort() { List<Update_OrderPlan_ShortResult> list = new List<Update_OrderPlan_ShortResult>(); Task.Factory.StartNew(async () => { list = await _storeprocedureService.CallUpdateOrderPlanShort(); }, TaskCreationOptions.LongRunning); return Task.FromResult(list); }
我不是太懂async,await,暂且不评论。我发现改成这样后,还是有问题。很快响应请求,但是存储过程没有往下执行。其实一开始我是有疑虑的,担心请求返回之后,子线程会不会就结束了。但是,同事也是这样写的,那说明子线程应该还会继续执行。子线程是属于webapi这个进程,而不是属于某个请求。那是什么原因呢?一开始我完全很懵懂,后来才想到一种可能性,会不是是子线程发生了异常,导致线程终止了,然后数据库不执行存储过程?我查了一下,果然子线程发生的异常,调用线程是无法捕获的,于是我在子线程执行的代码块加了try...catch。果然很快就捕获到了异常:
System.ObjectDisposedException:“无法访问已释放的上下文实例。此错误的常见原因是释放从依赖注入解析的上下文实例,然后稍后尝试在应用程序的其他位置使用同一上下文实例。如果对上下文实例调用”Dispose“,或将其包装在using语句中,则可能会发生这种情况。如果正在使用依赖注入,则应让依赖注入容器负责处理上下文实例。
大概意思是说,EF core里的上下文被释放掉了,所以不能使用了。我使用IOC容器来实例化上下文实例,不太清楚是怎样释放掉的。注册的时候使用的是services.AddScoped,也就是一个请求使用的都是同一个实例。我猜想,可能是使用多线程后,快速地响应了请求,所以IOC认为这个请求已经结束了,从而释放掉了上下文对象。这个上下文对象,不管我在Controller类还是_storeprocedureService实例所属的类里,使用依赖注入初始化,都产生这个异常。所以,我猜想,当请求成功响应,IOC会对所有由它创建的的上下文进行销毁。最后,只能通过其他的方法来创建上下文实例,我使用DbContextOptionsBuilder的方式来创建,其实就是传一个连接字符串给DbContextOptionsBuilder实例,把DbContextOptionsBuilder实例作为上下文类的构造函数的第一个参数,其他参数设置为null就可以。经过这样折腾一番,问题解决了,子线程终于可以调用存储过程了。
后来又发现一个问题,子线程调用存储过程,仍然会超时,数据库的存储过程仍然终止执行,想想也是,主线程和子线程,本质上都是线程,既然主线程会超时,为什么子线程就不会超时呢?也就是说,大费周章之后,仍然要设置超时时间
当我把webapi线程关闭之后,数据库的存储过程仍然终止执行。我的理解是,线程是依托于进程,使用进程的资源的,进程关掉了,那么线程就释放掉了,所以数据库的操作也停止了。
那么我做这个多线程有什么用呢,我感觉没啥用。就是快速地回应请求,回应的结果都是不对的,因为存储过程还没执行完,是什么结果还不知道。只是发送请求的客户端不用等待了,可以再次发送请求,这样webapi可以接收更多的请求。但是从业务来看,并不是一个高并发的场景啊,而且对失效性的要求也不高。这样做的唯一意义是,防止请求超时。这个玩意我也不太清楚,好像就没有试过请求超时的。
标签:webApi,存储,调用,请求,实例,一连串,上下文,线程,超时 From: https://www.cnblogs.com/drew/p/17013278.html