
简介《[详细完整版]ERP数据库.doc》是一份面向ERP系统学习与数据库设计开发者的中文文档资料围绕生产制造型企业的核心业务完整列出销售预测单、销售订单、主生产计划、物料需求计划、物料清单、工艺路线、工作中心、能力需求计划、出入库单、库存盘点、采购申请、采购订单、车间任务单、加工/派工单等十几类数据表的字段结构包括物料编码、批量规则、计划展望期、提前期、合格率、时区时段、毛需求/净需求、可供销售量等关键属性。同时梳理销售管理、MPS/MRP/CRP管理、采购管理、生产管理、库存管理、数据维护等菜单模块有助于理解ERP各子系统之间的数据流转。资源体积很小压缩包内共1个文件doc格式约30KB便于直接查阅字段定义或作为数据库建模参考。目前已有480人学习适合数据库课程设计、毕业设计以及中小企业ERP/进销存系统开发时快速对照表结构使用。1. 当一份[详细完整版]的 ERP数据库.doc 摆在面前先确认它能带你解决什么一份标着[详细完整版]的ERP数据库.doc通常不是拿来消遣的概念手册而是一张照着建库、配流程、调性能的施工图。它要回答的是三类问题ERP系统的表结构为什么长这样、库存这类高并发场景的数据到底怎么设计才不崩、以及从安装数据库到上线发布期间哪些坑必须绕开。适合的读者是正在做ERP项目的实施顾问、后端开发和对数据库优化有实际需求的技术负责人而不是只想背概念的学生。如果你手里正好有这份文档或者正准备从零搭一套ERP数据库我可以把里面的核心模型拆开再把参数和坑讲透。2. ERP数据库的核心模型从主数据到库存流水表结构为什么这么拆2.1 主数据、单据、流水账三层的拆分逻辑ERP数据库和普通业务系统最大的区别是它必须同时支撑静态档案和动态行为。静态档案是主数据比如物料、供应商、客户、BOM、工艺路线动态行为是单据和流水比如采购订单、销售订单、出入库单、库存流水、凭证。如果把这些混在一张表里随着业务增长很快就变成一张谁都改不动的“大泥巴”。所以成熟的ERP设计会严格分成三层主数据表负责存基础档案单据表负责登记业务过程流水表负责记录每一次数量或金额变化的明细。为什么不直接把库存数量放在物料表里举个最常见的例子物料表有一条记录字段叫current_qty。销售订单审核时减1仓库出库时再减1两个操作同一秒发生这条记录就会被锁住后到的操作只能等。一旦锁等待超时业务就报错。更麻烦的是你想查“这个物料的库存怎么从100变成70的”物料表只给你最终值中间过程全丢了。所以正确做法是物料表只存编码、名称、规格、默认仓库这些静态属性另外建一张库存表存现存量再建一张库存流水表存每一次变动。库存流水表是ERP数据库里最重要的一张表之一。每次出入库、盘点、移库都要插入一条记录字段至少包含物料ID、仓库ID、变动数量正负、变动类型入库/出库/盘盈/盘亏、关联单号、操作时间、操作人。有了这张表库存账才能追溯财务对账才有依据。很多ERP数据库文档会把主数据、单据、流水账画成三层架构你会发现用户在主界面上录入一张销售订单底层可能是同时往sales_orders、sales_order_lines、inventory、inventory_transactions四张表写数据。如果不分层改一个付款条件都要动流水表那谁都不敢改。2.2 库存表设计现存量、可用量与预留量拆开的理由很多初次设计ERP库存表的人会只放一个quantity字段卖出去就减买进来就加。这在单机演示环境下没问题一上生产马上露馅销售订单审核时我们并不想真的把库存减掉只是要把这部分货“预留”给客户真正减库存得等仓库发出商品那一刻。如果用同一个字段既管预留又管实际那么订单审核和出库确认之间其他订单可能会把货卖给第二个人这就是超卖。所以库存表至少要拆成四个量现存量physical_qty表示仓库里实际躺着的数量可用量available_qty等于现存量减去预留量表示还能接新订单的数量预留量reserved_qty表示已经被销售订单或生产订单锁定但还没出库的数量在途量on_transit_qty表示已经发货但还没到货的数量。这四列各管一段业务状态由不同的单据触发销售订单审核时reserved_qty增加available_qty减少出库单确认时physical_qty减少reserved_qty减少available_qty不变因为已经被扣过了。这样设计的好处是业务上每一步都有明确的数量归属财务和仓库对账时不必猜测。如果启用了批次管理或序列号管理库存表还要再扩展批次库存表要增加batch_no、生产日期、保质期、质检状态序列号表则每个单品一条记录记录当前所在仓库和库位。这会让表结构复杂不少但也能让召回、追溯、先进先出变得可行。没有批次表的ERP药品、食品、电子元器件这类行业根本不敢用。所以在看一份ERP数据库文档时先看它有没有把现存量、可用量、预留量分开基本就能判断出作者有没有真正做过生产环境。2.3 用业务单据流串起采购到销售的全过程为了不让你在表名里迷路我习惯用一条业务主线把所有核心表串起来。假设你经营一家贸易公司从下单到收款要经历这样几步先建供应商档案和物料档案然后做采购订单再到货时做收货单收货单审核后生成采购入库单入库单过账时库存表现存量增加同时插入一条库存流水。另一边客户下了销售订单订单审核时库存表预留量增加仓库发货时做销售出库单出库单过账时现存量减少、预留量减少也插入一条库存流水。这些单据在数据库里通常用单号做关联比如采购入库单上挂着一个source_doc_no指向源收货单销售出库单的origin_order_id指向销售订单头。没有这样一层追溯关系后面做供应商对账、客户退款、成本核算时就只能靠人工查Excel那就不叫ERP了。至少这几张表和它们的核心关联字段是必须存在的表名核心字段职责关联关系materialsid, code, name, spec, unit物料主数据被库存表、单据行引用warehousesid, code, name, type仓库主数据被库存表引用inventorymaterial_id, warehouse_id, physical_qty, reserved_qty, available_qty现存量汇总唯一键(material_id, warehouse_id)inventory_transactionsid, material_id, warehouse_id, qty_change, trans_type, source_doc_no, created_at数量变动流水记录所有出入库明细sales_orders / sales_order_linesorder_no, customer_id, material_id, qty, status销售订单及行审核时影响inventory.reserved_qtypurchase_orders / purchase_order_linesorder_no, supplier_id, material_id, qty, status采购订单及行收货后生成入库单为什么文档要单独强调主数据与交易数据分离因为主数据的变更频率远低于交易数据但影响面极大。物料编码一旦调整BOM、成本、报表全部要跟着变。所以ERP项目里主数据一般由专职人员在指定界面维护交易数据则由业务流程自动生成。数据库设计上主数据表用业务主键编码做唯一键交易数据表则多用自增ID两者用外键关联但不混在一张表里。有了这个认知后面的高并发讨论才有立足点因为sales_order_lines审核和inventory表的更新不在同一张表所以才会牵出锁、隔离级别和消息队列的先后问题。3. 库存高并发怎么扛锁、隔离级别与“先写库还是先写MQ”3.1 库存扣减的三种经典写法乐观锁、悲观锁、Redis预扣ERP里最容易被问到的技术点就是库存场景高并发的解决方案。销售订单审核、出库过账、调拨出入库全都在改同一批物料的可用量和现存量。三条路比较常用乐观锁、悲观锁、Redis预扣。乐观锁的做法是给库存表加一列version每次更新时带上旧的version去执行UPDATE。比如扣减10件的SQL写成这样UPDATE inventory SET physical_qty physical_qty - 10, available_qty available_qty - 10, version version 1 WHERE material_id 1001 AND warehouse_id 2 AND version 15;这条UPDATE返回的受影响行数如果是1说明更新成功如果是0说明在这条语句执行之前已经有其他事务把version改掉了你需要重新查一次库存再重试。乐观锁适合冲突概率不高的场景比如库存基数大、同一物料被并发砸单的可能性小。如果冲突概率高重试会变得频繁数据库压力不降反升。悲观锁则用SELECT ... FOR UPDATE把目标行锁住其他事务再读这行就要等。它的好处是事务串行化以后逻辑特别好写扣减、流水、预留写在同一个事务里就行坏处是锁等待会让接口响应时间变长一旦事务里混着外部调用或者慢SQL数据库连接很快会被占满。所以用悲观锁时事务里只能有数据库操作绝对不允许调HTTP接口、等消息队列返回这种操作。Redis预扣是另一条路线先把库存预热到Redis销售订单审核时用DECR原子扣减然后把扣减结果异步落到数据库。这种做法在秒杀、大促场景下确实能把数据库的QPS降下来但ERP和秒杀不一样的地方在于每一笔扣减都必须有单据、有流水、可追溯。Redis预扣需要额外的补偿对账机制防止Redis里的数字和数据库里的库存账漂移。我一般建议ERP里的高并发优先用乐观锁重试必要的时候用悲观锁少用缓存预扣除非你能接受每天对账、冲销误差。3.2 隔离级别怎么选为什么默认隔离级别会在ERP里翻车数据库的隔离级别直接决定并发操作下你看到的数据长什么样。MySQL默认是REPEATABLE READOracle和SQL Server默认是READ COMMITTED。很多从Oracle转过来的团队在MySQL上跑ERP沿用原来的事务代码结果发现死锁特别多原因就在隔离级别上。REPEATABLE READ下InnoDB对范围查询会加间隙锁gap lock两个事务同时向某个区间插入或更新时很容易互相锁住对方的间隙。ERP的库存查询经常带条件SELECT ... WHERE material_id 1001 FOR UPDATE这种等值查询还好但报表类的查询经常按仓库、按物料区间扫间隙锁一多锁等待和死锁就上来了。应对手段有两个一是把库存扣减事务的隔离级别降到READ COMMITTEDInnoDB在READ COMMITTED下只会锁记录不再锁间隙二是确保所有修改库存的SQL都走了唯一索引能用等值条件就别用范围条件。设置事务隔离级别的SQL很简单SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; BEGIN; UPDATE inventory SET available_qty available_qty - 10 WHERE material_id 1001 AND warehouse_id 2; INSERT INTO inventory_transactions(...) VALUES (...); COMMIT;把隔离级别降下来以后还要注意一个配套问题binlog里记录的是ROW格式还是STATEMENT格式。如果是STATEMENT格式一些非确定性SQL在从库回放时可能产生不一致建议生产环境把binlog_format改成ROW。这件事在MySQL数据库优化里属于基础项但很多项目直到出现主从数据不一致才想起来补。3.3 先写数据库还是先写MQ最终一致性的落地顺序ERP系统里到处是“过账后发通知”的场景库存出入库后要通知财务生成凭证采购收货后要通知质检销售出库后要通知物流。实现上通常是写完数据库后往消息队列里发一个事件。问题就来了到底是先写数据库再发MQ还是先发MQ再写数据库先发MQ再写数据库的风险很明显MQ消费者收到消息后去业务库里查单发现单据还不存在只能抛异常或等重试。先写数据库再发MQ的风险在于数据库事务提交了但MQ发送失败后面的财务、报表、物流全都没收到通知。这个问题没有绝对完美的解但工程上最常见的可靠方案是本地消息表把业务数据和待发送消息放进同一个数据库事务里一起提交。具体做法是在业务提交事务时同时往message_outbox表插入一条消息状态为pending事务提交后后台定时任务扫描pending消息发送给MQ收到确认后把状态改成sent。发送失败就按最大次数重试重试仍失败则进入人工修复队列。这样一个事务里两张表要么都成功要么都回滚数据库不会出现“单据有了但消息没有”的状态。MySQL下这段事务大概长这样BEGIN; INSERT INTO sales_order_lines(...) VALUES (...); UPDATE inventory SET reserved_qty reserved_qty 10 WHERE material_id 1001 AND warehouse_id 2; INSERT INTO message_outbox(msg_type, payload, status) VALUES (ORDER_AUDITED, {order_id: 1001}, pending); COMMIT;用这个方案你不需要纠结先写库还是先写MQ的先后来因为业务表和消息表是一起提交的。代价是多了一张消息表和一套定时投递任务换来的是可靠投递。现在的数据库同步工具比如基于binlog的CDC方案也能做类似的事把binlog里的变更解析成消息发出去相当于把数据库日志当成了消息源。但CDC管的是数据变更后的通知管不了“某个业务动作成功后必须发MQ”这种语义所以本地消息表在ERP里仍然是最稳的兜底手段。4. 一份能落地的ERP数据库文档字典、脚本、同步与发布配置4.1 数据库字典该记哪些字段别只记表名和注释一份标着“详细完整版”的ERP数据库文档光有表名和字段名是不合格的。真正能落地的字典必须能回答“这张表为什么存在、这个字段改了会牵连谁”。我见过很多项目的数据库字典就是建表语句的阉割版满屏是“序号、字段名、类型、长度”唯独没有字段的业务含义和关联关系。等上线三个月后要加个字段开发只能靠猜改错一个列名整个报表就废了。我建议的字典模板至少包含这些列表名、表注释、字段名、字段注释、数据类型、长度、允许为空、默认值、主键/外键、关联表与关联字段、更新规则、所属模块、维护人等。这张表不是给DBA看的是给业务顾问和开发一起看的。比如inventory表的reserved_qty注释一定要写明“销售订单审核时增加出库确认时减少不参与可用量计算”如果不写后来的开发很可能把它当成普通数量直接用导致可用量算错。在落地上建议把这份字典直接放进数据库的information_schema里保持代码与文档同步。MySQL可以查information_schema.COLUMNS导出字段清单Oracle可以查DBA_TAB_COLUMNS达梦、金仓也有对应的系统视图。用SQL批量生成字典初稿再手工补业务注释比纯手工写Word快得多。但注意从系统视图导出的注释只能看到物理层信息业务规则还得靠维护人补这也是为什么我会把维护人放进字典模板里——没人维护的字典半年后就没人信了。4.2 从Oracle到达梦/MySQL异构数据库同步的实用姿势国内ERP项目经常遇到一个现实问题老系统用Oracle新项目要求用达梦或者MySQL。迁移不只是把建表语句转换一遍表和表之间还有自增列、序列、触发器、存储过程这些差异。比如Oracle的SYSDATE到达梦可以用CURRENT_TIMESTAMP但Oracle的ROWNUM和达梦的ROWNUM虽然名字一样语义上也有区别。真正动手迁移时我一般走这么几步第一先用数据字典工具导出现有库的表结构生成目标库的建表脚本。第二把字段类型逐个映射VARCHAR2转VARCHARNUMBER(12,2)转DECIMAL(12,2)CLOB转TEXT。第三处理主键和索引特别是Oracle的复合分区表和位图索引到达梦、MySQL后往往要改成BTree索引。第四用ETL工具做全量数据迁移再启动增量同步。全量同步时建议关闭目标库的约束和触发器数据导完后再重新打开否则约束检查会拖慢导入速度。增量同步的常见方案有两种一种是基于时间戳/序列轮的增量查询适合表上有modify_time或自增主键的场景另一种是基于数据库日志的CDC同步比如从Oracle的归档日志读取变更应用到目标库。用CDC的好处是不用改业务表缺点是工具链复杂出错后定位难。同步完之后一定不要只对行数要抽样对比关键表的最后一条流水时间和单据状态不然“同步成功”有可能是假象。Navicat连接达梦这类国产库时注意驱动版本要匹配连接串里的schema名要填对否则明明连上了却看不到表不是玄学是模式名没切换。4.3 工程发布时数据库配置的常见套路连接池、账号与初始化脚本先说连接池。很多ERP系统上线后出现“数据库只能使用40个核心”的怪现象数据库CPU平均使用率不高但业务却说慢。查到最后往往是应用层连接池没配好最大连接数给太小请求全部堵在队列里等连接数据库当然闲着。反过来连接池给太大数据库连接数被占满又会把实例拖垮。经验值是这样的一个应用实例的数据库连接池大小通常不超过CPU核心数乘以2如果有大量的批处理任务再单独开一个连接池给批处理用避免跑批把在线事务的连接全抢走。初始化脚本要按版本管理不要一个update.sql从头追加到尾。项目里约定目录结构为001_schema.sql、002_seed_data.sql、003_indexes.sql配合Flyway或Liquibase这类工具在应用启动时按顺序执行并记录版本号。这样开发、测试、生产三套环境的库结构才可能一致。发布时还要检查配置文件里的连接参数比如MySQL的driver-class-name、url、username、password如果是达梦数据库连接串的格式跟MySQL完全不同别把驱动和方言配错。这里给一张我常用到的参数表对照着改基本不会漏配置项典型值说明maximumPoolSize20单实例最大连接数按CPU*2估算minimumIdle5最小空闲连接connectionTimeout30000获取连接超时单位毫秒validationQuerySELECT 1连接有效性检查Oracle用SELECT 1 FROM DUALinitializationFailTimeout1启动时连接失败立即报错schemaERP达梦/金仓需指定模式名发布当天最容易翻车的不是SQL写错而是账号权限不对。业务账号只需要增删改查结果给了DBA权限这个不只是安全风险还会让应用在启动时误执行某些DDL。反过来账号权限不足初始化脚本执行一半失败数据库结构残缺后面只能手工补。所以发布检查清单里必须有一步用最小权限账号跑一遍启动脚本确认所有表、索引、种子数据都建好。5. ERP数据库实施避坑指南五个真实翻车现场与处理记录这些坑不挑数据库MySQL、Oracle、SQL Server、达梦都遇到过区别只是报错信息不同、定位手段略有差别。下面每一条都按“现象→原因→解决”来写你可以直接对照自己遇到的状况。5.1 现象库存账和总账对不上月底结账差出一大截月底财务跑总账发现原材料科目余额和仓库的库存台账差了十几万的量两边怎么都对不上。原因不是某个人做错了账而是库存过账和财务凭证生成是两条链路库存单据过账成功但生成凭证的接口在某个晚上悄悄失败了没有重试机制也没有对账标记。解决方法是给过账接口加一张对账表记录每个单据的过账状态和凭证状态。库存过账成功往对账表写一条待生成凭证的记录凭证生成成功把状态改成已完成。月末跑一张差异清单把“已过账但未生成凭证”的单据全部捞出来补生成或人工调整。这个坑几乎所有ERP项目都会踩早发现早轻松。具体实现上对账表可以设计成settlement_check(id, doc_type, doc_no, post_status, voucher_status, created_at)由过账程序负责写入由凭证生成服务负责更新。定时任务每半小时扫一次voucher_statusPENDING的记录补发凭证请求。如果补发三次仍失败就推送告警而不是静默丢弃。有了这张表月底对账从“大海捞针”变成“查一张状态表”。5.2 现象数据库CPU只能用到40个核心业务还是卡运维监控显示数据库服务器CPU总使用率只有40%但ERP系统响应就是慢。排查后发现问题不在数据库服务器而在应用层连接池只有10个连接而应用有20个节点高峰期每个节点都在等连接请求全堵在应用线程池里。数据库端看到的是一堆连接在互相等待锁CPU想忙也忙不起来。解决方法是把连接池从10调到40按单节点CPU核数×2估算同时把长事务拆短避免事务里做耗时操作。调完之后CPU利用率上来了TPS也上来了。怎么定位先看应用日志里有没有“connection timeout”或“waiting for connection”字样再看数据库的threads_connected和threads_running如果threads_connected很高但threads_running很低说明连接都占着不用典型的连接池饥饿。查这个状态很简单MySQL执行SHOW STATUS LIKE Threads%再用SHOW PROCESSLIST看每个连接在干什么。如果是大量Sleep状态的连接占着连接池那就是连接池配置或事务未释放问题。这种“CPU利用率低不等于有余量”的错觉在数据库优化讨论里很常见别被表象骗了。5.3 现象死锁日志成堆业务频繁报错系统上线一周后后台死锁日志每几分钟就出一条大量订单审核失败。用SHOW ENGINE INNODB STATUS一看死锁都发生在inventory表和sales_order_lines表之间。原因是两个事务加锁顺序不一致一个事务先改库存表再插入销售订单行另一个事务先插入销售订单行再改库存表两个事务互相等对方释放锁。解决方法是统一所有事务的加锁顺序比如约定“先写单据行再改库存表”并且在代码评审时强制检查。同时把库存扣减的隔离级别从REPEATABLE READ降到READ COMMITTED去掉间隙锁死锁数量从每几分钟一条降到每天零条。自查死锁时不要只看日志文件里的一串十六进制锁ID要关注LATEST DETECTED DEADLOCK段落中的“holding”和“waiting for”部分那会明确告诉你两个事务各自锁了哪张表的哪一行。找到之后把两个事务的源码翻出来按同一个顺序重排加锁逻辑。记住死锁不是玄学只要加锁顺序一致大部分死锁都能消掉。5.4 现象同一个查询昨天跑0.2秒今天跑20秒这种问题在ERP里特别折磨人通常不是SQL变了而是执行计划变了。最常见的原因是统计信息过期优化器选了一个全表扫描。MySQL里可以执行ANALYZE TABLE修复统计信息Oracle里用DBMS_STATS.GATHER_TABLE_STATS。但更根治的办法是给这张表的查询条件建立合适的联合索引。比如库存流水表经常按material_id trans_type created_at查那就建一个这三列的联合索引注意列的顺序等值条件放前面范围条件放后面。ANALYZE TABLE inventory_transactions; ALTER TABLE inventory_transactions ADD INDEX idx_material_type_time (material_id, trans_type, created_at);建完索引后重新执行一遍查询用EXPLAIN确认执行计划走的是预期索引而不是全表扫描。另外每天晚上定时跑一次统计信息更新任务比出了问题再手动ANALYZE要靠谱得多。统计信息过期的根因在于数据分布变化大而优化器拿到的是旧的采样值所以只要表数据量发生明显变化就要及时更新统计信息而不是等慢SQL出现。5.5 现象数据库同步工具跑完了两边行数一样业务就是不对用同步工具把Oracle同步到MySQL校验工具显示行数一致但业务跑起来发现订单状态全是旧值。查了半天才发现同步工具只比对了行数没有比对每行的哈希值。源表有中间状态更新同步任务在“更新”和“插入”两条策略之间切换导致部分行先插入后更新更新事件被当成重复插入忽略掉。解决方法是三点一是给目标表补上主键没有主键的表同步时不要用全字段匹配二是开启同步工具的字段级比对对比每行的SHA256校验值而不只是行数三是对于有状态流转的表同步任务暂停时要保证源和目标都处于静止状态别在业务高峰期做全量校验。实际操作时可以先把源表和目标表按主键排序逐行拼接所有字段生成校验值然后比对两边的校验值集合。发现不一致时用单据号或业务主键拉出源表和目标表的具体记录逐字段看差异。常见问题集中在日期格式、空字符串与NULL的转换、字符集这三个方面比如Oracle的在MySQL里变成NULL导致WHERE条件判断出问题。数据同步这件事永远要用校验值抽样比对双层验证单靠行数等于远远不够。6. 把文档变成自己的方案用五个验证手段确认表结构与性能拿到一份ERP数据库文档别急着照单全收。我习惯先用五个手段验证它值不值得信。第一查数据字典反向核对表结构。用SQL从information_schema或DBA_TAB_COLUMNS导出库里的表和字段和文档里的字典做diff找出“文档有但库里没有”的字段也能发现“库里有但文档没写”的注释。这一步半小时能做完能避免被一份过时文档带到沟里。第二跑物理完整性检查。MySQL用CHECK TABLEOracle用ANALYZE TABLE VALIDATE STRUCTURESQL Server用DBCC CHECKDB。检查有没有索引损坏、页损坏尤其是刚做过迁移或同步的库这一步不能省。第三抓执行计划看核心查询。找文档里描述的高频查询用EXPLAIN看有没有全表扫描、临时表、filesort。ERP性能问题九成出在慢SQL上而慢SQL九成出在索引和统计信息上。把执行计划里rows估算值和实际行数对比偏差超过十倍就说明统计信息不准。第四写并发脚本模拟库存扣减。用两个事务同时扣同一个物料一个乐观锁版本、一个悲观锁版本观察锁等待和死锁情况。我常用Python的concurrent.futures开十几个线程跑同一段更新语句记录成功数和重试次数。这一步能直接检验表结构设计在真实并发下是否站得住。第五做备份恢复演练。这一点最容易被忽略。ERP数据库文档再详细如果备份恢复时间超过业务可接受范围一样是废纸。找一台空机器用最新的备份文件做一次完整恢复记录从开始恢复到库可用的分钟数再把恢复出来的库和原库做行数和校验值对比。只有真正做过恢复演练你才敢在月底结账前给老板拍胸脯。我自己的血泪经验是任何数据库方案只在测试环境跑功能、不跑并发等于没测。上线第一天库存单据卡死在锁等待的教训太深刻后来每改一次表结构都要把并发脚本跑一遍。希望这份从文档到落地的拆解能让你在看任何一份[详细完整版]的ERP数据库资料时第一反应是“我知道该先看什么、改哪里、注意什么”。希望帮到你。本文还有配套的精品资源点击获取