☰
信贷数据库设计:从借据建模到额度扣减的完整指南
2026/10/14 12:41:19 网站建设 项目流程

简介:《信贷数据库设计说明》是一份面向银行、金融机构及信贷系统开发、数据架构和测试人员的数据库设计文档,完整覆盖信贷业务核心模块。文档以2018年1月最终修订版为准,从总体设计规范出发,明确了数据划分、表/字段/索引设计原则、对象命名规则、安全保密设计等基础内容;再通过概念结构设计梳理客户管理、评级管理、授信申请、审批流程、合同管理、出账日终、贷后管理、减值准备、担保管理等模块的关系;最后以逻辑结构设计提供各模块关系图、表清单与表明细,便于直接指导建库和开发。资源包为单个docx文件,压缩后大小约2.14MB,适合作为信贷类项目数据库设计的参考模板或开发依据。目前已有232人学习下载,内容结构清晰、颗粒度细,尤其适合需要快速理解信贷业务数据模型或编写相似设计说明的读者。

1. 信贷数据库设计说明,解决的是对不上账和并发超放

信贷数据库设计说明,不是一份简单的建表清单,而是把信贷业务规则翻译成库表、字段、约束、索引、账务科目和跑批口径的文档。很多团队开发速度很快,建表半天搞定,但到了月底结息对不上账、两笔放款同时扣额度导致超授信、提前还款后还款计划残留脏数据,才回头翻设计文档,发现关键规则根本没写清楚。

这份说明要回答的问题很具体:一笔借款从授信、放款到还款结清,中间哪些数据必须落库,状态怎么流转,额度怎么扣又怎么恢复,利息按什么口径算,逾期从哪天开始计。它的读者也明确:开发照着建表,DBA 评估容量和分库策略,风控同学抽数核口径,以及对账负责人查每一分钱的来龙去脉。适合正在做信贷核心系统、消费金融系统或网贷平台账务模块的从业者参考。

2. 核心实体怎么拆:从客户到借据的表结构设计

2.1 客户、授信、合同、借据:先定四个主节点

信贷数据库设计和普通业务系统最大的区别,是多了一张「借据」表。电商订单、博客文章都可以围绕单一主实体建模,但信贷系统里,一笔借款从申请到结清,要穿过四条数据链路:客户信息、授信额度、合同借据、交易账务。

常见做法是把这四条链路的物理模型拉开,至少拆成以下这几个主节点:

实体主键业务含义上游关系
客户表 customercust_id借款人主体信息独立入口
授信表 credit_limitcredit_no客户可用总额度按客户 1:N
借据表 loan_agreementagree_no单笔放款凭证按授信 1:N
还款计划表 repay_planplan_id逐期应还本金利息按借据 1:N
交易流水表 repay_transtrans_id实际还款入账明细按计划 1:N

这里的核心决策是「合同」和「借据」到底拆不拆两张表。有些团队直接把合同当作借据,一张表搞定,理由是个人信贷合同就是一次放款。但一旦出现「循环贷」「随借随还」,一个授信合同下会产生多笔借据,不拆表就会让合同信息大量冗余。我一般建议拆开,授信是额度维度,借据是放款维度,合同是法律维度,三者在设计说明里各占一节,别混在一起写。

2.2 借据表 DDL:字段、索引与状态值怎么落

借据表是整份信贷数据库设计说明里最重要的一张表。它连接客户、额度、还款计划和交易流水,所有跑批逻辑都以借据为入口。给出最小可用的建表语句,后面讲字段取舍。

CREATE TABLE `loan_agreement` ( `agree_no` varchar(32) NOT NULL COMMENT '借据号,业务唯一', `cust_id` varchar(32) NOT NULL COMMENT '客户号,对应customer表', `credit_alloc_no` varchar(32) DEFAULT NULL COMMENT '额度占用流水号', `product_code` varchar(16) NOT NULL COMMENT '产品编号', `principal` decimal(20,2) NOT NULL COMMENT '放款本金', `rate` decimal(9,6) NOT NULL COMMENT '年化利率,存小数', `term_type` char(1) NOT NULL DEFAULT 'M' COMMENT '期限单位:D天/M月/Y年', `term` int NOT NULL COMMENT '期限数值', `repay_mode` varchar(8) NOT NULL COMMENT '还款方式:EPL等额本息/DEBX等额本金/XIBX先息后本', `status` tinyint NOT NULL DEFAULT '0' COMMENT '0受理 1已放款 2正常 3逾期 4结清 5核销', `disburse_date` date DEFAULT NULL COMMENT '放款日', `due_date` date DEFAULT NULL COMMENT '到期日', `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`agree_no`), KEY `idx_cust_id` (`cust_id`), KEY `idx_due_status` (`due_date`, `status`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='借据表';

主键直接用业务号 agree_no,在单库阶段没问题,但后面讲分库分表时会说这是坑。利率用 decimal(9,6) 而不是 float,年利率 5.4% 存成 0.054000,6 位小数精度足够覆盖日利率换算的截断误差。term_type 和 term 拆成两个字段,比存一个 term_days 灵活,产品可以定义「12 个月」也能定义「360 天」。联合索引(due_date, status)是每日逾期跑批的核心路径,查询条件是「今天到期且未结清」,把 due_date 放前面,区分度更高。

2.3 状态流转必须画成状态机,不能只留 status 字段

字段注释写「0受理 1已放款 2正常 3逾期 4结清 5核销」,这是最偷懒的做法。它只告诉后来者有哪些枚举值,没告诉谁在什么条件下允许从哪个值变到哪个值。实际生产里最常见的翻车现场,就是状态从「正常」直接跳到了「结清」,核查时谁都说不出这笔核销是谁操作的。

设计说明里必须单独开一节画状态机。借据状态至少要有这样几条路径:受理后放款成功进入正常;正常且到期未还进入逾期;逾期经过减免审批进入核销;正常或逾期还清后进入结清。禁止的状态跳转要明确写出来,比如「逾期必须经过还款或核销动作才能结束,不允许直接改成结清」。状态变更在设计说明里约定走统一接口,由应用层校验流转合法性,不要让每个业务方直接 update status。

3. 额度模型与账务科目:把「还能借多少」和「账怎么平」写清楚

3.1 可用额度等于总额度减已用减冻结:这个公式的并发条件

授信额度表是信贷数据库设计和普通交易系统差异最大的地方。电商库存超卖最多赔个订单,信贷额度超放是直接的资金损失。先看设计说明里必须写死的余额公式:

可用额度 = 授信总额度 - 已用额度 - 冻结额度

其中已用额度是当前在贷本金,冻结额度是已审批通过、尚未放款的部分。这个公式本身不复杂,复杂的是并发下怎么保证不超扣。常见错误是先查余额、应用层判断够不够、再 update,两个请求同时通过判断,就会超放。正确的写法是把判断条件并进 update 语句:

UPDATE credit_limit SET used_amount = used_amount + #{amount}, updated_at = NOW() WHERE cust_id = #{custId} AND total_amount - used_amount - frozen_amount >= #{amount};

这段 SQL 的关键在 where 条件里的不等式,它把「查余额、算余量、扣减」三步压缩成一条原子语句,数据库的行锁保证同一时刻只有一个事务能成功扣减。执行后检查影响行数,返回 1 表示扣减成功,返回 0 表示额度不足,业务侧直接提示用户失败。注意这里不要用「先查后更」,那是竞态条件的标准教材案例。

3.2 额度流水表:每一笔额度变动都要留痕

额度余额可以被 update 直接改写,改写后没有任何痕迹,这是信贷数据库设计里不可接受的。余额是汇总值,流水才是真相。设计说明里必须规定:额度表只允许通过额度流水表归集更新,禁止任何程序直接 update used_amount。

额度流水表建议包含这些字段:流水号、客户号、业务编号(借据号)、变动类型(占用、释放、冻结、解冻)、变动金额、变动前可用额度、变动后可用额度、操作时间、操作员。每次放款扣减额度时,先插入一条占用流水,再更新额度表余额。两个操作放在同一个本地事务里,要么都成功,要么都失败。

我习惯把这个顺序定死:先记流水,再更余额。原因是流水只增不改,是账;余额可以随时被流水重算重建,丢了也能恢复。反过来,余额先改了流水没记上,这笔账就永久消失了。这个原则写进设计说明后,后续做额度对账会省很多事。

3.3 账务设计:借贷分录与 decimal 精度约定

信贷系统的资金账务,靠的是一张科目表和一张分录表。科目表定义「放款本金」「应收利息」「罚息」「已收本金」这些账户,分录表记录每笔业务的借贷动作。借贷必相等是账务的底线,不是说业务上一定同时影响两个科目,而是每笔记账本身必须满足复式记账规则:

  • 放款时:借「发放贷款本金」,贷「资金户」
  • 还款时:借「资金户」,贷「已收本金」和「利息收入」

科目表由参数配置维护,不要在业务代码里写死科目号。按理说账务逻辑可以独立成一个子系统,但对于大多数信贷项目,初期把账务表和业务表放在同一个库里、同一套事务里,一致性最好维护。等到交易量上来,再做账务库分离,用异步对账兜底。

金额字段全库统一 decimal(20,2),禁止 double 和 float。这个约定必须放在设计说明最前面的全局约定里,否则不同表各用各的精度,月底对账就会遇到「差一分钱」的玄学问题。

4. 还款计划、利息与逾期口径:落地表怎么建,口径怎么写

4.1 还款计划落不落表:三种做法与选型

还款计划表是信贷数据库设计里最容易引发争论的地方。不落表派认为,根据借据本金、利率和还款方式,每期应还金额可以随时算出来,落表反而多一份需要维护的数据。落表派认为,催收、对账、销账都需要逐期核对,每次现算是灾难。

三种常见做法:

做法优点缺点适用
完全不落表,实时计算无冗余,无重算问题查询成本高,无法记录已还期数演示项目、极低并发
落表,只生成一份计划查询快,跑批简单提前还款要原地更新,易脏还款方式单一的产品
落表,按批次生成多份计划支持提前还款重算,留痕完整表数据量增长快正规信贷核心系统

第三种做法是主流。给还款计划表加一个 plan_group_id 字段,正常放款生成第一批计划标记为有效;发生提前还款时,把旧批次全部置为作废,按剩余本金和新期限重新生成一批新计划。这样历史每一版还款计划都留痕,对账时能说清楚每一期的本金利息是怎么来的。方案定了,信贷数据库设计说明里就能明确写:还款计划表只增不改,状态靠批次管理。

4.2 等额本息逐期试算与尾差修正:一段可抄的 SQL

等额本息每期应还金额按公式 A = P × r ×(1+r)^n /((1+r)^n - 1)计算,其中 P 是放款本金,r 是月利率(年利率除以 12),n 是总期数。每期利息等于剩余本金乘以月利率,每期本金等于每期应还减去每期利息。

这个公式的问题在于,金额精度有限,逐期计算必然产生尾差。如果每期应还四舍五入到分,最后一期按公式算出来的本金累计和放款本金对不齐,客户还完最后一期,账上还会挂一分钱。所以生成计划后必须做一次尾差修正,把累计误差调整到最后一期本金上:

UPDATE repay_plan SET repay_principal = repay_principal + ( #{principal} - ( SELECT COALESCE(SUM(repay_principal), 0) FROM repay_plan WHERE agree_no = #{agreeNo} AND plan_status = 'N' ) ) WHERE agree_no = #{agreeNo} AND plan_status = 'N' AND period_no = ( SELECT MAX(period_no) FROM repay_plan WHERE agree_no = #{agreeNo} AND plan_status = 'N' );

这个 update 的含义是:先按等额本息公式生成全量计划,再以放款本金为锚点,算出「计划本金累计」和「放款本金」的差值,把差值加在最后一期本金上。plan_status = 'N' 限定只修正当前有效批次,避免提前还款后新旧计划互相干扰。修正之后,sum(应还本金) 必须等于本金,这是还款计划表的一条铁律,应该在设计说明里写成校验规则,每天跑批核对。

4.3 逾期金额、逾期天数与账龄口径:宽限期和日切

逾期口径写不清楚,风控和催收会扯皮。信贷数据库设计说明里要固定三个定义:逾期天数、逾期金额、账龄段。

逾期天数常见口径是自然日:逾期天数 = max(0, 实际还款日 - 应还日 - 宽限期天数)。个人信贷通常给 3 天宽限期,超过宽限才上逾期。注意「应还日」指还款计划表里那天的 24 点,日切跑批在凌晨执行,跑批时客户当天还款仍算正常,跑批之后未还才进入逾期。这个日切时间点要在设计说明里写死,否则不同模块对「今天是否逾期」的判断会不一致。

逾期金额建议统一为「该期应还未还的本金 + 利息 + 罚息合计」,而不是只算本金。账龄段按逾期天数切:M1 是 1 至 30 天,M2 是 31 至 60 天,M3 是 61 至 90 天。逾期天数每天由跑批任务更新进逾期表,而不是在查询时实时算,这样催收系统、征信报送系统拿到的是同一份数据。

5. 信贷数据库设计落地中的五个高频翻车点与排查方法

这一章是血泪经验。以下五类问题在信贷数据库设计评审和生产运维里反复出现,每一条都按「现象 → 原因 → 解决」写清楚,拿去做排查清单正好。

5.1 金额精度不统一,对账永远差几分

现象:月底对账时,还款计划表的累计本金和账务分录入账的本金差几分钱。开发排查半天,发现有的表用 decimal(18,2),有的表用 decimal(20,4),还有老接口查出来是 double 转换过来的。

原因:设计说明没在全局约定里统一金额精度。不同人建表时各自选了精度,decimal 乘法后小数位被截断或四舍五入,误差累积。

解决:全库金额字段统一 decimal(20,2),利率单独用 decimal(9,6)。所有计算在中途用高精度(decimal(20,6))运算,最终入账时才四舍五入到分。这条规则写进数据库设计说明的前三页,并在代码评审里卡死。

5.2 状态乱跳,没有状态机约束的数据像脱缰野马

现象:审计查一笔借据,状态从「正常」直接跳到「核销」,中间没有任何还款、减免或审批记录。问起来谁都不知道是哪个接口更新的。

原因:表里只有 status 字段注释,没画状态机。各业务模块为了省事,直接 update 状态,跳过业务校验。

解决:数据库设计说明单独一章画状态流转图,明确每个状态变更的触发动作、前置条件和目标状态。应用层统一封装状态变更方法,只允许通过这个方法改状态,从入口堵住乱跳。

5.3 并发扣减额度,先查后更导致超授信放款

现象:压测时同一个客户同时发起两笔借款,两笔都放款成功,合计金额超过授信总额。

原因:额度扣减逻辑是「select 出余额 → 应用层判断 → update」,两个请求同时读到相同余额,都判断额度够,都执行了 update。

解决:按 3.1 的条件更新写法,把判断写进 update 的 where 条件里,返回影响行数判断是否成功。这条要在设计说明的时序图里体现出来,不能只在代码层面修。

5.4 提前还款后,还款计划残留脏数据

现象:客户提前结清,借据状态已变为结清,但还款计划表里还有「已还本金大于应还本金」的负数剩余记录。征信报送数据在这些期数上怎么都对不上。

原因:提前还款时对原计划表做了原地更新——把未来期数本金改成 0,而不是将整批计划作废。多次提前还款后,同一期计划被改了多次,历史信息丢失,对账无据可依。

解决:采用 4.1 的批次方案。原计划批次整体置为作废(plan_status 改为 'O'),新生成一批计划接续 plan_group_id。查询报表默认只看有效批次,历史批次留给审计追溯。

5.5 业务号当物理主键,分库分表时现挖坑

现象:业务量增长后按 cust_id 分库,但 loan_agreement 的主键是 agree_no。跨库查询、全局唯一编号生成、数据迁移都变得异常困难,经常出现不同分片生成重复业务号。

原因:设计之初把业务号既当业务标识又当物理主键。单库时没问题,分库后业务号的生成规则被打散,不能再依赖数据库自增保证全局唯一。

解决:在数据库设计说明里区分物理主键和业务号。物理主键用自增 id 或雪花 id,业务号(借据号)单独作为唯一索引存在,由发号器统一生成。这个调整要在设计早期做,后期换主键的成本极高。

6. 设计文档到生产跑批的最后一公里:评审重点与对账验证

6.1 评审时先问三个「谁」:谁创建、谁修改、谁删除

评审信贷数据库设计说明时,与其逐字段检查类型长度,不如先问三个问题:这张表的每一行由谁创建,创建后哪些字段允许被修改,什么条件下允许删除。客户表基本信息只能由客户中心写入,额度流水只能追加不允许修改,借据表的 status 只能通过状态机接口变更,还款计划一旦生成不允许原地改金额。

这三个问题问完,表设计的缺陷基本都能暴露出来。我习惯在评审前做一张字段权限表,把核心表的每个字段按「创建 / 修改 / 删除」填上归属模块,填不出来的字段就是设计没说清楚的地方,必须回头补文档。

6.2 一条对账 SQL 让还款计划与实收明细当场对平

设计说明写得再好,落地后还是要靠数据校验兜底。还款计划表和还款交易流水表对账是每月必做的动作,把计划应还本金与实际入账本金按期数做比对:

SELECT p.period_no, SUM(p.repay_principal) AS plan_principal, COALESCE(SUM(t.actual_principal), 0) AS actual_principal FROM repay_plan p LEFT JOIN repay_trans t ON p.agree_no = t.agree_no AND p.period_no = t.period_no WHERE p.plan_status = 'N' GROUP BY p.period_no HAVING SUM(p.repay_principal) <> COALESCE(SUM(t.actual_principal), 0);

这段 SQL 的用法是找出「计划应还本金」和「实际入账本金」不一致的期数。left join 保留所有计划期数,coalesce 把未入账的空值转成 0,group by period_no 按期数聚合,having 过滤出差异行。跑出来有结果,说明该期存在部分还款、减免或入账错误,需要人工核对;跑出来为空,说明当期账面是平的。

做信贷数据库设计这些年,我最深的体会是:文档里多写一句口径,生产上就少熬一个通宵。还款计划生成、额度扣减、逾期判断,这些逻辑看起来是代码问题,根子全在设计说明有没有把规则定死。每次评审,我会把「谁在什么时候写入、谁在什么时候修改」写在每张表的注释里,这比任何字段字典都管用。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询