还在手动拖拽画 ER 图?这款免费代码神器|DBML 语法 + 企业级实战,10 分钟搞定专业数据库设计!

简介: dbdiagram.io 是一款免费在线ER图工具,支持用简洁DBML语法代码自动生成专业数据库关系图,可导出PNG/PDF/SVG、双向同步SQL,免安装、易分享,大幅提升企业级项目设计效率与协作质量。(239字)

为什么企业开发必须画 ER 图?

首先一个企业级开发的项目是必须要有数据库蓝图设计的~ 目的是为了让表结构、字段、关系一目了然,避免开发混乱

然后是为了方便团队沟通, 产品、前端、后端、DBA快速对齐,减少扯皮的情况~

实际开发之前也可以防止一些坑:也就是提前发现设计漏洞, 比如: 冗余、关联错误、关系混乱等等..

对于项目的后期维护成本降低, 例如: `项目迭代、新人接手时,一看ER图就懂这个项目系统的大致结构~

dbdiagram.io 是什么

今天给大家推荐一个10 秒生成 ER 关系图的方法~ 并且可以免费一键生成高清图片~

它就是 dbdiagram.io 一款代码驱动在线数据库 ER 图设计工具~

简单的说它就是一个免费在线 ER 图工具,用一种类似于 SQL语法DBML写代码并且 自动生成专业 ER 图!

官网地址: https://dbdiagram.io/home

如图


当你点击Create your diagram(创建图表)的时候,就可以直接开始画图了~

如图

这完完全全是专门给开发者、数据分析师、做系统的人量身定做的神器啊~ 太狂喜了!

使用之前,最好注册登录一下~~

核心亮点✨

代码写图,不用手拖

不用像传统画图工具那样拖方框、拉线条,只需要写几行简单的语法,它就自动生成干净、专业的 ER 图,效率拉满~

完全免费,永久可用

2026年主打的就是个免费啊~
这款在线ER图工具你个人用完全免费,支持最多 10 个图表,能导出 PNG、PDF、SVG
还能直接生成建表 SQL, 对于个人项目太友好了~

如图

✅ 免费版完全够用

功能 免费版 对你的用处
代码画 ER 图 ✅ 无限用 写 DBML 代码生成汽修店三表关系图
导出 PNG/PDF/SVG ✅ 支持 截图、导出高清图给员工 / 开发看
SQL 导入 / 导出 ✅ 支持 一键生成 SQL 建表语句,直接用
在线保存图表 ✅ 最多 10 个 存系统的表结构,完全够
公开分享图表 ✅ 支持 发链接给外包开发,不用传文件

💸 付费版一般用不上

付费版是给企业团队、大项目用的,个人项目根本不需要!

唯一需要注意的:免费版最多存 10 个图表,个人小型系统表结构顶天也就 7~10 个!

双向同步,一键生成 SQL

你编写专属语法之后所生成的ER图,也能从图反向导出完整的SQL CREATE TABLE建表语句,简直不要太给力~ 🛠️

直接复制到 相应数据库中 就能用,这就相当于画图 = 写建表代码,完全提高效率了~

一些常见数据库都支持: SQL(SQL Server/MySQL)等等..

如图


当然同时也支持导入 SQL 逆向生成 ER 图

在线即用,不用安装

打开浏览器就能用,不用装客户端,还能一键分享链接给其他需要的人~

dbdiagram.io 完整语法核心 DBML 📚

既然要使用这个ER图工具,我们也要了解一下它的一些创建规则和语法!

它用的是DBML 全称Database Markup Language 数据库标记语言,是专门用来定义数据库结构的极简语法,比 SQL 简单 10 倍

我们在左侧就可以直接开始书写规则~

如图

定义表

语法如下

Table 表名 {
  字段名 数据类型 [约束, 注释]
  字段名 数据类型 [约束, 注释]
}

详细解释

表名支持中文, 注意要加双引号 ,比如:Table "会员表"

数据类型:可以写INT/VARCHAR/MONEY/DATETIME 等,和 SQL 完全对应~学过SQL你自然懂!

常用约束:

语法 作用 案例
pk 代表主键(Primary Key) MID INT [pk]
not null 代表非空 MName VARCHAR [not null]
unique 代表唯一 MPhone VARCHAR [unique]
default: 值 代表默认值 MCreateTime DATETIME [default:GETDATE()]
note: '说明' 代表给字段加说明 最后在ER图里会显示! RMoney MONEY [note: '消费金额']
increment 自增 MID INT [pk, increment]

举个栗子 某汽修店的会员表~

Table "会员表" {
  MID INT [pk, note: '会员ID,主键']
  MName VARCHAR(10) [not null, note: '会员姓名']
  MPhone VARCHAR(11) [unique, note: '联系电话']
  MCreateTime DATETIME [default: `GETDATE()`, note: '开卡时间']
}

这样我们在右侧就能直接看到 效果了!

如图

定义表关系(外键)

这个一般分为三种关系:

< 表示: 一对多(1→N)
> 表示: 多对一(N→1- 表示: 一对一(11

这些关系我在前面的数据库设计中也已经讲解过了,还不懂的 ,赶紧去补一补~

一般我们可以在关联字段上面直接写

✅ 内联写法

直接在字段后加 [ref: 关系标 关联表.关联字段],这样就会自动生成关系线!

例如

Table 用户表{
  id int [pk,note:'用户id']
  username varchar(10) [not null, note:'用户名']
  iphone varchar(13) [not null,note:'手机号码']
}

Table 订单表 {
  id int [pk]
  Ordernumber int [not null,note:'订单号']
  user_id int [ref: > 用户表.id]
}

如图

定义多对多关系(中间表)

那么多对多这种关系,我们知道要用到一个中间表才行~

举个栗子 学生和课程: 一个学生可以选多门课,一门课可以被多个学生选,这就是多对多关系。

那这里的DBML语法结构如下

Table 学生表{
  sid int [pk,note:'学生id']
  uname char [not null,note:'学生姓名']
  age bit [default:'1',note:'学生性别']
}

Table 课程表{
 cid int [pk,note:'课程id']
 cname varchar(10) [not null,note:'课程名称']
}


Table 学生对应课程表{
  sid int [ref: > 学生表.sid]
  cid int [ref: > 课程表.cid]
  indexes { (sid, cid) [pk] } // 联合主键
}

如图

定义复合主键(多对多表用)

这里,我们来回忆以下 多对多关系

举个栗子

之前说过了,比如: 一个会员可以有多辆车,一辆车也可以被多个会员开 → 这就叫多对多

那么在这种多对多关系的情况下,复合主键就是:MID + 车牌 = 唯一标识
把两个标识绑在一起,绝对不重复、不混乱~

就像是租车公司的车辆一样,会员 ↔ 车辆
一个会员可以有好几辆车,一辆车也可以租给 好几个会员开, 这种关系就叫 多对多

但是多对多关系不能直接存在会员表,也不能直接存在车辆表 必须单独建一张 中间关联表~

也就是会员车辆关联表~

创建语法

indexes {
  (主键1, 主键2) [pk,name:'复合主键名称']
}

例如

 indexes {
    (MID, CPlate) [pk, name: 'pk_member_car']
  }

案例

// 1. 会员表(主表1)
Table "会员表" {
  MID INT [pk]
  MName VARCHAR(50)
  MPhone VARCHAR(20)
}

// 2. 车辆表(主表2)
Table "车辆表" {
  CPlate VARCHAR(20) [pk]
  CBrand VARCHAR(50)
  CColor VARCHAR(10)
}

// 3. 会员车辆关联表(多对多中间表,核心!)
Table "会员车辆关联表" {
  MID INT [ref: > "会员表".MID]
  CPlate VARCHAR(20) [ref: > "车辆表".CPlate]
  BindTime DATETIME

  indexes {
    (MID, CPlate) [pk, name: 'pk_member_car']
  }
}

如图

小知识: 复合主键的用途

举个栗子 同一个会员,不能绑定同一个车牌两次!

会员 1001 + 车牌 川 A12345 → 可以存
会员 1001 + 车牌 川 A67890 → 可以存
会员 1002 + 车牌 川 A12345 → 可以存
~
但是:
会员 1001 + 车牌 川 A12345 再存一次 → 直接报错!

这就是复合主键的作用:防止重复绑定!保证数据干净、保证数据唯一、不乱套

就像是你的姓名会和别人的重复,但是你的姓名+你的身份证 = 你的唯一标识~

定义索引

indexes 是专门用来在dbdiagram 里定义索引的代码块!

写在表里面,专门给字段加索引,让查询变快~

语法格式

indexes {
  (字段1, 字段2, ...)  [name: '索引名'] // 索引名必须用单引号包裹!
}

举个栗子

Table 订单 {
  id int [pk]
  user_id int
  status int
  indexes {
    (user_id, status) [name: 'idx_user_status'] 
  }
}

当然,多个字段的索引,也可以分开写成如下形式:

indexes {
   (字段) [name: '索引名']
   (字段) [name: '索引名']
}

例如

indexes {
  (username) [name: 'idx_username']
  (phone) [name: 'idx_phone']
}

实战案例:企业级业务系统多表设计🚀

这里就用商城系统来举例~

表名 描述 作用
users 用户表 存所有注册用户的信息(账号、密码、手机号等)
categories 商品分类表 存商品的分类(比如「手机」「电脑」「配件」,还支持二级分类,比如「手机 - 苹果」)
products 商品表 存所有上架的商品(比如 iPhone 16、华为 Mate 70 这些具体商品)
orders 订单表 存用户下单的订单(比如「2026-04-15 张三买了 1 台 iPhone」这个订单的总信息)
order_items 订单商品明细表 存订单里的每一件商品(比如张三的订单里,除了 iPhone,还买了个手机壳,就拆成 2 条明细)

先创建这5个ER图, 不分先后~

如下

// 用户表
Table users {
  id int [pk, increment]
  username varchar(50) [not null, unique]
  password varchar(64) [not null]
  phone varchar(20) [unique]
  nickname varchar(50)
  status tinyint [default: 1]
  create_time datetime [default: `now()`]
  indexes {
    (username) [name: 'idx_username']
    (phone) [name: 'idx_phone']
  }
}

// 商品分类表
Table categories {
  id int [pk, increment]
  name varchar(50) [not null]
  parent_id int [ref: > categories.id, default: 0]
  sort int [default: 0]
  indexes {
    (parent_id) [name: 'idx_parent']
  }
}

// 商品表
Table products {
  id int [pk, increment]
  category_id int [ref: > categories.id]
  name varchar(100) [not null]
  price decimal(10,2) [not null]
  stock int [default: 0]
  status tinyint [default: 1]
  create_time datetime [default: `now()`]
  indexes {
    (category_id) [name: 'idx_category']
    (name) [name: 'idx_name']
  }
}

// 订单表
Table orders {
  id int [pk, increment]
  order_sn varchar(32) [unique, not null]
  user_id int [ref: > users.id]
  total_amount decimal(10,2) [not null]
  pay_status tinyint [default: 0]
  order_status tinyint [default: 0]
  create_time datetime [default: `now()`]
  indexes {
    (user_id) [name: 'idx_user']
    (order_sn) [name: 'idx_order_sn']
  }
}

// 订单商品表
Table order_items {
  id int [pk, increment]
  order_id int [ref: > orders.id]
  product_id int [ref: > products.id]
  product_name varchar(100) [not null]
  price decimal(10,2) [not null]
  quantity int [not null, default: 1]
  indexes {
    (order_id) [name: 'idx_order']
    (product_id) [name: 'idx_product']
  }
}

如图

表与表之间的关系拆解分析

~

1. 分类表 和 商品表一对多

因为1 个分类 下会存在 多个商品!

举个栗子

一个分类比如 手机下面,可以挂 N 个商品, 比如: iPhone、华为、小米
但是一个商品,比如 iPhone Pro max,只能属于一个手机分类下, 它不能同时属于手机电脑 对吧!

从现实角度来说,分类是商品的归属,用来做商品筛选、分类导航(

比如用户点手机分类,就能看到所有手机的商品,如果不建关系,商品就没地方归类,商城就乱成一锅粥~

ER图中所对应的关系如下描述:

1.商品表.分类id 要关联 分类表.id --> 实现多对一

category_id int [ref: > categories.id]
意思就是:商品表的category_id关联分类表的主键(categories.id),所以商品必须归属于某个分类

分类表商品表,这两个表的关系,我们也就梳理完成了!

如图

2.用户表 和 订单表一对多

1个用户 可以有 多个订单 对吧~

举个栗子

一个用户比如张三,他是不是可以下N个订单, 今天买手机、明天买电脑 对吧~

但一个订单,只能属于一个用户, 你总不能说是一个订单同时是张三和李四、王五的吧~

订单必须绑定用户,才能知道谁买的,用来做订单查询、用户中心、售后维权,等等...

没有用户关联的订单是无效且无意义的~

ER图所对应的关系如下

订单表.用户id 要关联 用户表.id : --> 实现多对一

orders.user_id int [ref: > users.id]

意思是:订单表的user_id,关联用户表的主键id,订单必须属于某个用户~才有意义

如图

3.订单表 和 订单商品明细表 一对多

一对多 1 个订单 可能会存在 多个商品明细!

一个订单, 比如张三的订单,里面可以有 N 件商品 手机 + 手机壳 + 充电器...

而每一件商品都拆成一条明细,但一条明细,只能属于一个订单!

这里我们来举个例子方便理解~

你想: 张三的订单里,买了「手机、手机壳、充电器」3 样东西,就生成 3 条明细。
这 3 条明细,全是张三这个订单的,跟李四、王五的订单半毛钱关系都没有!
不可能出现:一条手机的明细,同时算在·张三·和·李四·两个订单里,那账就彻底乱了~

订单表(orders)只存「总单信息」

只记「张三这个订单」的整体情况:谁买的、订单号、总共花了多少钱、什么时候买的,当然根据需求,也有其他的信息~

id user_id order_sn total_amount create_time
1 1001 DD2026001 6298.00 2026-04-15

订单明细表(order_items)存每一件商品的细节(3 条数据,对应 3 件商品)

id order_id product_id product_name price quantity
1 1 10001 iPhone 16 5999.00 1
2 1 10002 手机壳 99.00 1
3 1 10003 充电器 200.00 1

字段解释:

字段名 人话解释
id 这条明细自己的编号(唯一标识)
order_id 核心! 这条明细属于哪个订单(这里全是 1,说明都属于张三的订单)
product_id 买的是哪个商品(对应商品表的 ID)
product_name 商品名字(冗余存一份,防止商品改名后订单看不到历史名称)
price 下单时这件商品的单价(不是现在的价格,是当时买的价格)
quantity 买了几件(比如买 2 个手机壳,这里就是 2)

所以订单表只记总账,明细表记明细账,每一件商品单独一条记录,清清楚楚,不会乱。

ER图对应关联逻辑如下

订单明细表.订单id 关联 订单表.id --> 实现多对一

order_items.order_id int [ref: > orders.id]

明细表的order_id,关联订单表的主键id,明细必须属于某个订单。

如图


如果不拆明细表,直接把商品存在订单表里:一个订单买 3 件商品,就要存 3 条订单数据,订单号重复,统计、对账全乱~
也没法单独统计某件商品卖了多少, 只能看订单总金额, 如果说后续加商品、改商品、退单个商品,全没法操作。

拆成订单明细表,订单表存总信息,明细表存每件商品的细节,逻辑完全清晰~

4.商品表 和 订单商品明细表 一对多

1 个商品 可能存在 多个明细, 说到这里也可以解释刚刚上面有些问题给大家造成的疑惑~

也就是说一个商品 比如 iPhone 17,可以出现在N个订单明细里被张三买、李四买、王五购买

但一条明细,只能对应一个商品~

订单明细表必须绑定商品,这样才能知道订单里买的是什么商品,

后期用来做商品销量统计、库存扣减、售后换货,

如果没有商品关联的订单明细也是无效的~

这个应该很好理解吧!

ER图关系设计逻辑如下

订单明细表.商品id 要关联 商品表.id --> 实现多对一

order_items.product_id int [ref: > products.id]

如图

5.分类表 和 分类表

这里比较特殊, 这里我们要采取一种通用设计模式,自关联一对多

也就是1 个父分类 下面有 多个子分类~

举个栗子

分类表自己自己关联,这样就可以实现多级分类:也就是俗称的无限极分类

比如: 数码产品父分类,下面有手机、电脑子分类, ~~

然后呢手机又可以当父分类,下面有苹果、华为、三星、小米这些子分类~以此类推

到这里肯定有新手朋友会问,包括曾经的我也问过,为啥这么建? 为什么不用单独建父分类表?

那是因为一张表搞定所有层级,灵活扩展,商城分类想加多少级就加多少级,不用改表结构~

否则分类多了表也会增多,维护成本自然增加~

ER图设计逻辑如下

分类表.父级id 关联 分类表.id

categories.parent_id int [ref: > categories.id, default: 0]

分类表的父级parent_id,关联自己的主键id,0代表顶级分类 比如数码产品

那么非 0 代表子分类: 比如 手机的parent_id是数码产品的id~这样无限极递归下去,

这在我们实际业务代码开发中,就要使用到php、java、python来实现了!

如图

所以通过我们的ER图梳理清楚了表之间的关系之后,完整关系链路图就出来了,在项目开发中我们一眼就能看懂~

用户表(users) 
    ↓ 一对多
订单表(orders) 
    ↓ 一对多
订单商品明细表(order_items) 
    ↓ 多对一
商品表(products) 
    ↓ 多对一
商品分类表(categories) ← 自关联 → 自己(多级分类)

组成完整的业务流

用户 (users) → 下订单 (orders) → 订单里的商品明细 (order_items) → 明细对应商品 (products) → 商品属于分类 (categories)

设计ER图的终极目的

数据不冗余

比如用户信息只存在users表,订单里只存user_id,不用把用户名、手机号重复存到订单里,改用户信息只改一张表,不会出错, 查询通过关联查询就可以了!

业务逻辑清晰

订单、商品、用户完全解耦

后续加功能比如:优惠券、积分、售后,直接在对应表加字段,不影响其他表。

性能最优:

每个表只存自己的核心数据,查询、统计、修改都只操作对应关联的表,不会出现大表卡顿

同时也符合企业级项目数据库设计规范!

下单案例,把ER图逻辑关系彻底串起来

比如

张三(users表 id=1)
在手机分类(categories表 id=2)下面,
买了 1 台 iPhone 16(products表 id=100,价格 5999)
买了 1 个手机壳(products表 id=101,价格 29

那么此时此刻生成订单:

orders表新增一条数据,user_id=1,总金额 6028,订单号20260415123456

同时明细表中生成明细:order_items表新增 2 条数据:

第一条:order_id=刚生成的订单id,product_id=100,价格 5999,数量 1
第二条:order_id=刚生成的订单id,product_id=101,价格 29,数量 1

最后商品归属:products表的category_id=2,对应分类表的手机分类~

✅ 最后总结

以上我讲到的DBML语法也只是一部分常用的

更多语法大家可以参考官方文档~ https://dbml.dbdiagram.io/home

总之dbdiagram.io绝对是你 高效 + 免费 + 专业的企业级开发ER 图设计首选工具~

我个人向大家发出强烈建议:以后做项目先画 ER 图再写代码,结构清晰、少走弯路!

相关文章
|
18天前
|
人工智能 数据可视化 安全
王炸组合!阿里云 OpenClaw X 飞书 CLI,开启 Agent 基建狂潮!(附带免费使用6个月服务器)
本文详解如何用阿里云Lighthouse一键部署OpenClaw,结合飞书CLI等工具,让AI真正“动手”——自动群发、生成科研日报、整理知识库。核心理念:未来软件应为AI而生,CLI即AI的“手脚”,实现高效、安全、可控的智能自动化。
34827 46
王炸组合!阿里云 OpenClaw X 飞书 CLI,开启 Agent 基建狂潮!(附带免费使用6个月服务器)
|
12天前
|
人工智能 自然语言处理 安全
Claude Code 全攻略:命令大全 + 实战工作流(建议收藏)
本文介绍了Claude Code终端AI助手的使用指南,主要内容包括:1)常用命令如版本查看、项目启动和更新;2)三种工作模式切换及界面说明;3)核心功能指令速查表,包含初始化、压缩对话、清除历史等操作;4)详细解析了/init、/help、/clear、/compact、/memory等关键命令的使用场景和语法。文章通过丰富的界面截图和场景示例,帮助开发者快速掌握如何通过命令行和交互界面高效使用Claude Code进行项目开发,特别强调了CLAUDE.md文件作为项目知识库的核心作用。
11394 36
Claude Code 全攻略:命令大全 + 实战工作流(建议收藏)
|
7天前
|
人工智能 JavaScript Ubuntu
低成本搭建AIP自动化写作系统:Hermes保姆级使用教程,长文和逐步实操贴图
我带着怀疑的态度,深度使用了几天,聚焦微信公众号AIP自动化写作场景,写出来的几篇文章,几乎没有什么修改,至少合乎我本人的意愿,而且排版风格,也越来越完善,同样是起码过得了我自己这一关。 这个其实OpenClaw早可以实现了,但是目前我觉得最大的区别是,Hermes会自主总结提炼,并更新你的写作技能。 相信就冲这一点,就值得一试。 这篇帖子主要就Hermes部署使用,作一个非常详细的介绍,几乎一步一贴图。 关于Hermes,无论你赞成哪种声音,我希望都是你自己动手行动过,发自内心的选择!
2389 24
|
29天前
|
人工智能 JSON 机器人
让龙虾成为你的“公众号分身” | 阿里云服务器玩Openclaw
本文带你零成本玩转OpenClaw:学生认证白嫖6个月阿里云服务器,手把手配置飞书机器人、接入免费/高性价比AI模型(NVIDIA/通义),并打造微信公众号“全自动分身”——实时抓热榜、AI选题拆解、一键发布草稿,5分钟完成热点→文章全流程!
45733 157
让龙虾成为你的“公众号分身” | 阿里云服务器玩Openclaw
|
5天前
|
人工智能 弹性计算 安全
Hermes Agent是什么?怎么部署?超详细实操教程
Hermes Agent 是 Nous Research 于2026年2月开源的自进化AI智能体,支持跨会话持久记忆、自动提炼可复用技能、多平台接入与200+模型切换,真正实现“越用越懂你”。MIT协议,部署灵活,隐私可控。
1599 3
|
12天前
|
机器学习/深度学习 存储 人工智能
还在手写Skill?hermes-agent 让 Agent 自己进化能力
Hermes-agent 是 GitHub 23k+ Star 的开源项目,突破传统 Agent 依赖人工编写Aegnt Skill 的瓶颈,首创“自我进化”机制:通过失败→反思→自动生成技能→持续优化的闭环,让 Agent 在实践中自主构建、更新技能库,持续自我改进。
1785 6

热门文章

最新文章

下一篇
开通oss服务