五、先看看若依从前端(vue)到数据库(mybatis + mysql)的整个数据访问流程
我们就以最简单的《通知公告管理》 Notice 作为分析的切入点:
(1)前端请求过程:打开通知公告,然后编辑单条数据,会经过前端的代理设置指向后台的
http://localhost:8080/system/notice/2
(2)后台 SysNoticeController 接收到请求,会通过 noticeService 获取数据
(3)noticeService 是通过 springboot @Autowired 注入进来的 Interface
其实现在 SysNoticeServiceImpl
(4)SysNoticeServiceImpl 又通过 SysNoticeMapper 实现 OR-Mapping ,也就是这些 Mapper 类实现从数据获取到包装成 domain 类 SysNotice 的过程
(5)SysNoticeMapper 也是个 Interface,它的具体实现是由 MyBatis 自动完成的
(6)MyBatis 实现上面接口的依据,是通过解析 SysNoticeMapper.xml
以上就是一个完整的数据访问链条。
当然,所有的前提是要先建立数据库访问连接,springboot 的数据库连接这部分,对用户几乎是透明的,只要装好库,设置好配置文件里的参数就行了,具体的调用都是由 springboot 自动装配的。
六、通过中间件(middleware)建立 SQLAlchemy 的数据库连接
FastAPI 支持很多种 OR-Mapping 的方案,但是它的官方入门教程选的就是 SQLAlchemy,所以我也不费那精神去选来选去了。
官方文档地址:
https://fastapi.tiangolo.com/zh/tutorial/sql-databases/
1、第一步,我先按照教程建立一个连接试试
可以在 main.py 里写一个测试函数
可以看到,sqlalchemy 先通过指定的 DB_URI 连接参数建立连接,
engine = create_engine(core.Config.DB_URI)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
SessionLocal 应该是个用来生成 Session 的 Factory
使用的时候,session = SessionLocal() 就创建了一个会话
notice = session.query(SysNotice).filter(SysNotice.noticeId == noticeId).first()
查询完成后,要
session.close()
执行前,还要准备一下:
(1)core.Config 的内容:
(2)models.SysNotice 是 domain 类,可以先手工导入,下一步我再说怎么批量导入,
在命令行下执行 sqlacodegen:
sqlacodegen mysql+pymysql://ruoyi:admin@localhost:3306/ruoyi?charset=utf8 --tables sys_notice --outfile models/sys_notice.py
参数说明:
sqlacodegen {Config.DB_URI} {tables} --outfile {model_filename}
(3)好了,可以执行 main.py
访问:
http://localhost:8080/test/notice/1
可以看到,返回数据了。
2、第二步,批量导入model 类
其实就是把上面的 sqlacodegen 命令,通过遍历数据库里的表名来循环调用,
代码都放在 utils/gen_model.py 里了,
生成完 model 文件,我还做了一下后处理,因为我没找到 sqlacodegen 里可以修改类属性名的参数,所以只能手工转换:
起因是字段名是 snake_case,例如 user_id
但是类属性是 camel_case ,例如 userId
所以需要转换一下。这就是 change_columns 函数的作用。
3、第三步,用中间件和 ContextVar 来获取数据库访问
官方文档和作者写的应用框架里都是用依赖注入(Depends)的方式来使用数据库连接的,但是我觉得每个函数的参数都得挂上依赖,看起来好啰嗦,所以在网上找到一个简洁的方法,用中间件来获取数据库会话。
https://github.com/mfreeborn/fastapi-sqlalchemy
里面代码不多,我没用 pip 安装,直接把代码copy 过来了,
放到了 core/db_middleware.py 里,其实现原理就是每次用户请求过来,都会创建一个数据库会话,并保存到 ContextVar 里
用的时候,通过 db.session 获取。
具体用法:
虽然说,写在中间件里会影响性能,但我也没机会用 FastAPI 做什么大系统,所以方便第一。
至此,数据库连接搞定了,下一步该把菜单数据给查出来了。
代码可以访问:
https://github.dev/crazybill/ruoyi-fastapi