电梯运行模拟——三次作业总结

总体遵循的设计思路

逻辑解耦

电梯与调度器解耦

在我的三次电梯作业里,追求的目标都是让电梯运行与调度器分离,电梯只负责按照指令运行,目前的最终版本中,指令有UP、DOWN、OPEN、CLOSE、STILL、STOP六条。

楼层信息的存储和变更与电梯、调度器解耦

从第二次作业开始,我建立了Stage类,负责保存楼层信息;

建立了Instruction类,负责描述电梯运行的指令以及对应的Stage的变化,Instruction类中有一个枚举类型表示指令类型,一个IntFunction类型函数表示楼层索引的变化。

调度器运行流程解耦

从第二次到第三次,我的调度器的逻辑部分都是解耦成如下4个部分:

  1. 获取主请求,也就是分发指令的依据
  2. 根据主请求分发指令
  3. 推送指令和需要进入电梯人员到与电梯交互的数据单元
  4. 检测电梯返还人员,从本调度器处理队列中删除,第三次添加了:如果需要转乘,则重新插入顶层调度器

这是一个轮询机制,顺序循环并分发指令,控制电梯。

返回目录

第一次电梯,蠢笨串行先到先得电梯

类方法复杂度表

Method ev(G) iv(G) v(G)
"Main.main(String[])" 1 1 1
"elevator.Dispatcher.Dispatcher()" 1 1 1
"elevator.Dispatcher.getWaitingQueue()" 1 1 1
"elevator.Dispatcher.printQueue()" 1 1 1
"elevator.Dispatcher.run()" 1 3 4
"elevator.Elevator.Elevator(int|int|int)" 1 1 1
"elevator.Elevator.OutPersonThread.OutPersonThread(int|Vector)" 1 1 1
"elevator.Elevator.OutPersonThread.run()" 1 3 3
"elevator.Elevator.addPassenger(int|int)" 1 1 1
"elevator.Elevator.getStage()" 1 1 1
"elevator.Elevator.getStatus()" 1 1 1
"elevator.Elevator.moveDown()" 1 2 3
"elevator.Elevator.moveTo(int)" 1 5 5
"elevator.Elevator.moveUp()" 1 2 3
"elevator.Elevator.release()" 1 1 1
"elevator.ElevatorOutput.formatOutput(Format|int)" 2 2 4
"elevator.ElevatorOutput.formatOutput(Format|int|int)" 2 2 4
"elevator.Person.Person(int|int|int)" 1 1 1
"elevator.Person.getFrom()" 1 1 1
"elevator.Person.getId()" 1 1 1
"elevator.Person.getTo()" 1 1 1
"elevator.TransferPersonRequest.TransferPersonRequest(Dispatcher)" 1 1 1
"elevator.TransferPersonRequest.run()" 3 2 5
"util.MultiMap.MultiMap()" 1 1 1
"util.MultiMap.get(K)" 1 1 1
"util.MultiMap.put(K|V)" 1 1 2
"util.MultiMap.remove(K)" 1 1 1
"util.MultiMap.toString()" 1 1 1

可见的是,我的方法复杂度都很低,因为类也比较少,没什么衡量价值

返回目录

第二次电梯,可捎带无限容量电梯

第二次电梯运作原理图

sequenceDiagram
main ->> Dispatcher : 启动计时器、电梯调度器,然后结束
transfer ->> Dispatcher : 传递人员请求;结束时发送Person.END
transfer ->> transfer : 输入流截止便关闭
Stage -->> Dispatcher : 拿到楼层信息,计算指令
Dispatcher ->> Elevator : 发送指令,如果是开门指令,则等待人员返还
Dispatcher ->> Stage : 在发送指令后变更楼层
Dispatcher ->> Elevator : 发送待上电梯人员
Elevator -->> Dispatcher : 返还待下电梯人员
Dispatcher ->>Dispatcher : 拿到END且处理队列为空时,发送指令关闭电梯,自己也退出轮询

从第二次电梯开始,我的电梯是按照如上的设计架构完成的,这是让我觉得比较舒服的架构设计,其设计方向是在于模拟,而不是为最优解设计的。

类方法复杂度表

Method ev(G) iv(G) v(G)
"Main.main(String[])" 1 1 1
"machine.Dispatcher.Dispatcher()" 1 2 2
"machine.Dispatcher.exec(Instruction)" 1 7 7
"machine.Dispatcher.getNewInstruction()" 6 4 9
"machine.Dispatcher.getNewMajorRequest()" 8 4 11
"machine.Dispatcher.run()" 1 5 5
"machine.Dispatcher.updatePersonMap()" 1 3 3
"machine.elevator.Elevator.Elevator(ReentrantLock)" 1 1 1
"machine.elevator.Elevator.close()" 1 1 1
"machine.elevator.Elevator.move()" 1 1 1
"machine.elevator.Elevator.open()" 1 1 1
"machine.elevator.Elevator.run()" 2 5 8
"machine.elevator.Elevator.setOutsideQueue(MapVisitor<Integer| Person>)" 1 1 1
"machine.elevator.Elevator.setStage(Stage)" 1 1 1
"machine.elevator.Elevator.setToBeExec(List<Instruction>)" 1 1 1
"machine.elevator.Elevator.setToBeRemoved(Queue<Person>)" 1 1 1
"machine.elevator.ElevatorOutput.formatOutput(Format|int)" 2 2 5
"machine.elevator.ElevatorOutput.formatOutput(Format|int|int)" 2 2 4
"machine.elevator.Stage.Stage()" 1 1 1
"machine.elevator.Stage.Stage(int)" 1 1 2
"machine.elevator.Stage.apply(IntFunction)" 1 1 2
"machine.elevator.Stage.checkIndex(int)" 1 1 2
"machine.elevator.Stage.checkStage(int)" 3 1 3
"machine.elevator.Stage.getStage()" 1 1 1
"machine.input.Person.Person(int|int|int)" 1 1 2
"machine.input.Person.equals(Object)" 2 1 2
"machine.input.Person.getFrom()" 1 1 1
"machine.input.Person.getId()" 1 1 1
"machine.input.Person.getSide()" 1 1 1
"machine.input.Person.getStatus()" 1 1 1
"machine.input.Person.getTo()" 1 1 1
"machine.input.Person.transSide()" 1 1 2
"machine.input.TransferPersonRequest.TransferPersonRequest(Queue<Person>)" 1 1 1
"machine.input.TransferPersonRequest.run()" 3 2 4
"machine.input.TransferRequest.TransferRequest(PersonMap)" 1 1 1
"machine.input.TransferRequest.run()" 3 2 4
"machine.instr.Instruction.Instruction(Instr|IntFunction)" 1 1 1
"machine.instr.Instruction.getFunc()" 1 1 1
"machine.instr.Instruction.getInstr()" 1 1 1
"util.MultiMap.MultiMap()" 1 1 1
"util.MultiMap.get(K)" 1 1 1
"util.MultiMap.put(K|V)" 1 1 2
"util.MultiMap.removeByKey(K)" 1 1 1
"util.MultiMap.removeValue(K|V)" 1 2 2
"util.MultiMap.toString()" 1 1 1
"util.PersonMap.PersonMap()" 1 1 1
"util.PersonMap.getFromPerson(int|Status)" 2 2 2
"util.PersonMap.getToPerson(int|Status)" 2 2 2
"util.PersonMap.hasElement(Person)" 3 3 4
"util.PersonMap.isEmpty()" 5 4 7
"util.PersonMap.putPerson(Person)" 2 2 3
"util.PersonMap.removePerson(Person)" 2 4 4
"util.PersonMap.toEnd()" 2 2 2
"util.PersonMap.toString()" 1 1 1

可以看出加粗的三个方法复杂度较高,分别是获取主请求、根据主请求生成新命令、还有personMap的isEmpty方法。

获取主请求由于personMap的不合理,得在遍历时分别获取personMap的两个子map,即fromUp和fromDown两个map,所以复杂度很高。

根据主请求生成命令复杂度高跟上一个函数同理。

personMap的isEmpty方法就是因为personMap内部成员是4个map,对每一个都isEmpty然后与起来,复杂度就高了。

类复杂度表

Class OCavg WMC
"Main" 1.00 1
"machine.Dispatcher" 5.17 31
"machine.elevator.Elevator" 2.22 20
"machine.elevator.Elevator.Format" n/a 0
"machine.elevator.Elevator.Status" n/a 0
"machine.elevator.ElevatorOutput" 4.50 9
"machine.elevator.Stage" 1.67 10
"machine.input.Person" 1.38 11
"machine.input.Person.Side" n/a 0
"machine.input.Person.Status" n/a 0
"machine.input.TransferPersonRequest" 2.00 4
"machine.input.TransferRequest" 2.00 4
"machine.instr.InstrFac" n/a 0
"machine.instr.InstrFac.Instr" n/a 0
"machine.instr.Instruction" 1.00 3
"util.MultiMap" 1.33 8
"util.PersonMap" 2.44 22

可以看出,加粗的Dispatcher类和ElevatorOutput类复杂度较高,后者不说了,这个很难避免,前者复杂度高的原因是,目前大部分的逻辑处理部分在这一层,实现了轮询生成指令并分发,又有前述的两个方法加成,所以复杂度很高,当然,这个还与我的数据结构设计有一定的关系,personMap设计得很糟糕,如果改进数据结构并分离一些逻辑,想必复杂度会降下去的吧。

返回目录

第三次电梯,可达楼层、运行速度和容量均不相同的多电梯

第三次电梯运作原理图

sequenceDiagram
main ->> Scheduler : 启动计时器、电梯调度器,然后结束
transfer ->> Scheduler : 传递人员请求
transfer ->> transfer : 输入流截止便关闭
Scheduler ->> Dispatcher : 启动三部电梯的调度器
Scheduler ->> Dispatcher : 发送人员请求
Dispatcher ->> Elevator : 启动电梯
Stage -->> Dispatcher : 拿到楼层信息,计算指令
Dispatcher ->> Elevator : 发送指令,如果是开门指令,则等待人员返还
Dispatcher ->> Stage : 在发送指令后变更楼层
Dispatcher ->> Elevator : 发送待上电梯人员
Elevator -->> Dispatcher : 返还待下电梯人员
Dispatcher -->> Scheduler : 返还需要转乘的人员请求
Scheduler ->> Dispatcher : 在电梯没有处理任务、scheduler没有处理任务且拿到END时,传递结束指令

这里实际上scheduler是给三个Dispatcher发送不同的人员请求但是为了说明的简易,只画了一个Dispatcher、Stage、Elevator组。

类方法复杂度表

Method ev(G) iv(G) v(G)
"Main.main(String[])" 1 1 1
"machine.Scheduler.Scheduler()" 1 1 1
"machine.Scheduler.dispatchPerson()" 1 1 1
"machine.Scheduler.putPersonToElevator(Person)" 1 2 2
"machine.Scheduler.run()" 1 4 4
"machine.elevator.Dispatcher.Dispatcher(Stage,String,long,int,ReentrantLock)" 1 1 1
"machine.elevator.Dispatcher.exec(Instruction)" 1 5 5
"machine.elevator.Dispatcher.getNewInstruction()" 11 7 13
"machine.elevator.Dispatcher.getNewMajorRequest()" 1 3 5
"machine.elevator.Dispatcher.getPeopleMap()" 1 1 1
"machine.elevator.Dispatcher.run()" 1 5 5
"machine.elevator.Dispatcher.setToBePut(PeopleVector)" 1 1 1
"machine.elevator.Dispatcher.update()" 1 3 3
"machine.elevator.Elevator.Elevator(ReentrantLock,String,long,int)" 1 1 1
"machine.elevator.Elevator.close()" 1 1 1
"machine.elevator.Elevator.move()" 1 1 1
"machine.elevator.Elevator.open()" 1 1 1
"machine.elevator.Elevator.processInside()" 1 1 1
"machine.elevator.Elevator.processOutside()" 2 1 2
"machine.elevator.Elevator.run()" 2 5 8
"machine.elevator.Elevator.setOutsideQueue(MapVisitor<Integer, Person>)" 1 1 1
"machine.elevator.Elevator.setStage(Stage)" 1 1 1
"machine.elevator.Elevator.setToBeExec(List<Instruction>)" 1 1 1
"machine.elevator.Elevator.setToBeRemoved(Queue<Person>)" 1 1 1
"machine.elevator.Stage.Stage(int[])" 1 2 3
"machine.elevator.Stage.apply(IntFunction)" 1 2 2
"machine.elevator.Stage.checkIndex(int)" 1 1 2
"machine.elevator.Stage.couldStall()" 1 1 1
"machine.elevator.Stage.getStage()" 1 1 1
"machine.elevator.Stage.initStage(int)" 1 2 2
"machine.elevator.Stage.isReachable(int)" 1 1 1
"machine.elevator.Stage.isReachableByIndex(int)" 2 2 2
"machine.elevator.Stage.stageToIndex(int)" 3 1 4
"machine.elevator.Stage.toString()" 1 1 1
"machine.input.Person.Person(int,int,int)" 1 1 2
"machine.input.Person.equals(Object)" 2 1 2
"machine.input.Person.getDestination()" 2 1 2
"machine.input.Person.getFrom()" 1 1 1
"machine.input.Person.getId()" 1 1 1
"machine.input.Person.getSide()" 1 1 1
"machine.input.Person.getStatus()" 1 1 1
"machine.input.Person.getTo()" 1 1 1
"machine.input.Person.hashCode()" 1 1 1
"machine.input.Person.isOutside()" 1 1 1
"machine.input.Person.isUp()" 1 1 1
"machine.input.Person.needGetInside(int)" 1 1 2
"machine.input.Person.needGetOutside(Stage)" 3 2 3
"machine.input.Person.setMid(Stage,Stage)" 6 6 12
"machine.input.Person.toString()" 1 1 1
"machine.input.Person.transSide()" 1 1 2
"machine.input.Person.wantOne()" 3 4 7
"machine.input.TransferRequest.TransferRequest(PeopleVector,ReentrantLock)" 1 1 1
"machine.input.TransferRequest.run()" 3 3 5
"machine.instr.Instruction.Instruction(Type,IntFunction)" 1 1 1
"machine.instr.Instruction.getFunc()" 1 1 1
"machine.instr.Instruction.getType()" 1 1 1
"machine.output.Output.format(Format,int,String)" 2 2 5
"machine.output.Output.format(Format,int,int,String)" 2 2 4
"machine.util.PeopleMap.PeopleMap()" 1 2 2
"machine.util.PeopleMap.getCapcity()" 1 1 1
"machine.util.PeopleMap.getMap(Type)" 1 1 1
"machine.util.PeopleMap.getPerson(Type,int)" 1 1 1
"machine.util.PeopleMap.hasElement(Person)" 3 4 5
"machine.util.PeopleMap.isEmpty()" 1 2 2
"machine.util.PeopleMap.put(Type,Integer,Person)" 1 1 1
"machine.util.PeopleMap.putPerson(Person)" 3 2 5
"machine.util.PeopleMap.remove(Type,Integer,Person)" 1 1 1
"machine.util.PeopleMap.removePerson(Person)" 2 2 4
"machine.util.PeopleMap.toEnd()" 1 2 2
"machine.util.PeopleMap.toString()" 1 1 1
"machine.util.PeopleVector.PeopleVector()" 1 1 1
"machine.util.PeopleVector.putPerson(Person)" 1 2 2
"machine.util.PeopleVector.putPerson(Person,String)" 1 2 3
"machine.util.PeopleVector.toEnd()" 1 3 3
"util.MultiMap.MultiMap()" 1 1 1
"util.MultiMap.get(K)" 1 1 1
"util.MultiMap.isEmpty()" 1 1 1
"util.MultiMap.put(K,V)" 1 2 3
"util.MultiMap.removeByKey(K)" 1 1 1
"util.MultiMap.removeValue(K,V)" 1 2 2
"util.MultiMap.toString()" 1 1 1
"util.MultiMap.values()" 1 1 1

加粗的两个方法复杂度飘红了,还是蛮高的,一个是与之前一样的getNewMajorRequest方法,获取新的主请求,因为遍历对象,还有判断person的逻辑比较复杂,所以复杂度很高;

相比上回的改进是getNewInstruction方法复杂度已经没那么高了,因为将一部分逻辑引导到了person类中。

另一个是person类的setMid方法,其作用是设置person的中转目的地,因为拿取了两个stage对象并循环调用对象isReachable函数判断,所以复杂度较高,但并不是太高,只是刚刚超出。

类复杂度表

Class OCavg WMC
"Main" 1.00 1
"machine.Scheduler" 1.75 7
"machine.elevator.Dispatcher" 3.88 31
"machine.elevator.Elevator" 1.91 21
"machine.elevator.Elevator.Format" n/a 0
"machine.elevator.Stage" 1.70 17
"machine.elevator.StageFac" n/a 0
"machine.input.Person" 1.94 33
"machine.input.Person.Side" n/a 0
"machine.input.Person.Status" n/a 0
"machine.input.TransferRequest" 2.00 4
"machine.instr.Instr" n/a 0
"machine.instr.Instr.Type" n/a 0
"machine.instr.Instruction" 1.00 3
"machine.output.Output" 4.50 9
"machine.util.PeopleMap" 1.92 23
"machine.util.PeopleMap.Type" n/a 0
"machine.util.PeopleVector" 1.50 6
"util.MultiMap" 1.38 11

Dispatcher类有点积重难返的意思,目前架构是这样了,当然,Dispatcher类完全可以把功能分散到其他类中,最后让他起组合搭桥的作用,就是把之前就描述的DIspatcher类的四个函数分离开来,变成新的类的处理逻辑,这样,应该可以显著减少他的复杂度把;

Person类WMC过高的原因是方法太多了,获取成员、判断进出、判断上哪一个电梯,这么多内容夹杂在一起,内部还有其他的工具函数,导致Person类复杂度很高,如果重构,可以把新的person类变成几个接口的组合,一个获取ID、FROM、TO的借口,一个判断进出相关工具函数的接口,或者单独开个类,处理人员是否需要进出和向上哪一个电梯的类,后者让person专职其责,也能降低复杂度,更好一点把。

Output类。。不用说了。

第三次电梯的所有类图景

返回目录

作业bug分析

从架构上来说,我的程序在线程间的数据安全上,是没有问题的,所以bug主要出现在我某一个步骤没有完成,比如在写的过程中de出的一个bug,人从电梯里出来要从电梯内部的队列中删除,如果没有删除,导致一个人会出电梯数次,诸如此类,我犯得bug都是这样的错误,这些bug的主要原因是我的数据结构类设计的不够好,使用时头脑也不清晰,可变数据的坏处就在这,必须时时考虑数据该怎么变化迁移,或是添加或是删除。

除了上述说的,我还犯得的一个bug就是主请求选择bug,第三次电梯里,主请求选择没有考虑人满员的状况,选了outside的人,导致电梯日门,哭。/(ㄒoㄒ)/~~

多线程作业感想

我从表达式求导作业完成后,就一直比较在意这个问题,就是程序的架构,还有代码的复杂度,所以在电梯作业的编写中,我就一直做着我反复说的东西,就是分离分离再分离,将逻辑分散开来,当然,不能是随意地平行散列逻辑,应该是有所关联结构,按照层次化的方式构建起来的,不断将逻辑解耦,就是我在写程序中反复思考的内容,为此,我写这部分程序动辄删除或者重写,但是由于经验和能力的不足,依然没有设计出真正健壮、低耦合、复杂度低的架构,比如我的数据结构类,设计的还是让我很不满意,也增添了我其他使用该类的方法的复杂度,这是今后需要改进的,另外我的OO工程写得实在是太慢了,从周六晚写到周二早,第二次电梯第三次电梯都是这样,第一次也少不了多少,,还是小将想指挥全军,能力不足啊。

OO_JAVA_电梯运行模拟_单元总结的更多相关文章

  1. OO_JAVA_表达式求导_单元总结

    OO_JAVA_表达式求导_单元总结 这里引用个链接,是我写的另一份博客,讲的是设计层面的问题,下面主要是对自己代码的单元总结. 程序分析 (1)基于度量来分析自己的程序结构 第一次作业 程序结构大致 ...

  2. OO_JAVA_JML系列作业_单元总结

    OO_JAVA_JML系列作业_单元总结 (1)梳理JML语言的理论基础.应用工具链情况 简单梳理 以下三者是jml规格里的核心,对一个方法功能和属性的限制: requires子句:规定方法的前置条件 ...

  3. OO_多线程电梯_单元总结

    概述: 面向对象的第二单元是多线程电梯.第一次实现一部傻瓜电梯,每次只送一个人:第二次实现一部可稍带电梯:第三次实现三部可稍带电梯. 一.设计策略 1.第5.6次作业设计思路 第5.6次作业的架构相似 ...

  4. Spark运行模式_本地伪集群运行模式(单机模拟集群)

    这种运行模式,和Local[N]很像,不同的是,它会在单机启动多个进程来模拟集群下的分布式场景,而不像Local[N]这种多个线程只能在一个进程下委屈求全的共享资源.通常也是用来验证开发出来的应用程序 ...

  5. Update(Stage4):Spark原理_运行过程_高级特性

    如何判断宽窄依赖: =================================== 6. Spark 底层逻辑 导读 从部署图了解 Spark 部署了什么, 有什么组件运行在集群中 通过对 W ...

  6. 快餐店运行模拟C++程序源码代写

    某快餐店供应若干种快餐和饮料(5种以上),早晨6:00开始营业,晚上11:00打烊.前一天已经安排了若干工人上班,快餐店的用餐位是固定的,每种食物的成本和销售价格是确定的,每种食物的总量是确定的,储存 ...

  7. 03_天气查询_socket方式模拟_多线程方式

    [简述] 要重视Socket开发,企业后台服务特长使用Socket. 1.服务端要有可持续运行能力,保证线程一致在运行 2.并发处理能力,使用多线程 [工程截图] [WeatherRunner.jav ...

  8. OO_多项式求导_单元总结

    概述: 面向对象第一单元的作业是三次难度依次递增的多项式求导.第一次作业是仅包含带符号整数和幂函数的多项式求导,例如:-1+xˆ233-xˆ06:第二次是在前面的基础上增加了三角函数的求导,例如:-1 ...

  9. Jmeter_前端RSA加密下的登陆模拟_引用js文件实现

    版权声明:本文为博主原创文章,未经博主允许不得转载. 在一次项目实战中,前端登录使用了RSA加密,使用LoadRunner压测的第一步,就是模拟用户登录,可惜loadRunner11并不能录制前端的加 ...

随机推荐

  1. Nginx:无处不在的Nginx的八个应用场景与配置

    --- 阅读时间约 15 分钟 --- Nginx概述 众所周知,互联网已经离不开  WEB服务器  ,技术领域中  WEB服务器  不止  Nginx  一个,其他还有很多如  Apache  . ...

  2. Redis-初见

    目录 启动and连接 JRedis 宝塔 Redis.conf RDB AOF(Append Only File) 发布和订阅 主从复制 一主二从 复制原理 宕机后的手动配置主机 哨兵模式 Redis ...

  3. TypeScript 中命名空间与模块的理解?区别?

    一.模块 TypeScript 与ECMAScript 2015 一样,任何包含顶级 import 或者 export 的文件都被当成一个模块 相反地,如果一个文件不带有顶级的import或者expo ...

  4. PyTorch学习笔记6--案例2:PyTorch神经网络(MNIST CNN)

    上一节中,我们使用autograd的包来定义模型并求导.本节中,我们将使用torch.nn包来构建神经网络. 一个nn.Module包含各个层和一个forward(input)方法,该方法返回outp ...

  5. 【C++周报】第一期2021-8-1

    [C++周报]第一期 2021-8-1 这一期我们来看这道题目:https://vijos.org/p/1058 这道题是一道非常好的模拟题.题目如下: 描述 我们用文本处理器来处理一个特殊的文本文件 ...

  6. CS:APP Chapter-6 存储器层次系统-读书笔记

    存储器层次系统 笔记,应该不是一个大而全的文件,笔记应该是提纲挈领,是对思想的汇总浓缩,如果追求详实的内容反而是丢了初心. 计算机是抽象的,它的设计者努力让计算机变得简单,在设计上高度抽象,而计算机的 ...

  7. 谷歌浏览器chrome安装插件报"程序包无效: CRX_HEADER_INVALID"错误

    今天参加需求评审,看到原来可以谷歌浏览器查看Axure原型文件,真是只有想不到,没有做不到(自己孤陋寡闻了,第一次接触Axure). 需求评审后,我百度"如何使用谷歌浏览器查看Axure原型 ...

  8. Jemter请求乱码解决方案

    1:jemeter查看结果树乱码 (1)在jmeter的bin目录下找到jmeter.properties这个文件,添加上 sampleresult.default.encoding=utf-8 (2 ...

  9. webpack工具学习 构建简单vue项目(不依赖vue-cli) webpack4.0

    目的用webpack构建简单前端项目 1.npm init   (npm init -y)  形成package.json 2.npm install --save-dev webpack  形成 n ...

  10. SQL Server附加数据库错误5120处理方法

    SQL Server附加数据库5120错误 当我们从另外一台服务器复制过来的数据库,可能会有如下错误: 解决方法 1.给数据库所在文件夹增加用户Everyone并赋予完全控制权限 2.以管理员身份运行 ...