Koa + Prisma 快速入门

news2024/10/6 12:25:57

10分钟掌握 Koa + Prisma 实现数据库 CRUD

前言

Prisma 是号称下一代的 ORM 工具,同样是基于 TypeScript 实现,但是带来了很强的类型安全。

本文使用 Koa.js 搭建一个简单的 Web 服务,配合 MySQL 数据库,来演示如何通过 Prisma 实现数据的增删改查。

Prisma

Prisma 是号称下一代的 ORM 工具,下面是 Prisma 中文网站,可以说是技术类网站中相当优秀的中文站了:

image-20230509200931239

Prisma 是一个开源的数据库工具链项目,不仅仅是一个简单的 ORM 工具。它支持的数据库有 PostgreSQL、MySQL、MongoDB、SQL Server和SQLite,本文以 MySQL 进行演示。

在使用方式上,对于第一次接触它的人来讲,稍微有些繁琐。我总结了以下几个流程:

  • 安装依赖
  • 初始化 Prisma 项目
  • 设计 Prisma Schema(数据库信息和模型)
  • 同步到数据库
  • 生成 Prisma Client
  • 使用 Prisma Client 完成 CRUD

下面我们先去创建一个开发环境,再回过头来继续介绍 Prisma。

初始化环境

使用 Koa 快速搭建一个 Web 服务,首先创建目录,并安装依赖:

$ mkdir koa-prisma
$ cd koa-prisma
$ pnpm init

# 安装 Koa 依赖
$ pnpm add koa @koa/router koa-bodyparser
  • @koa/router:路由中间件,方便集成路由功能
  • koa-bodyparser:解析请求体数据,并放到 ctx.request.body 对象上

然后新建一个 index.js,完成一个简单的 Web 服务:

const Koa = require('koa')
const Router = require('@koa/router')
const bodyParser = require('koa-bodyparser')

const app = new Koa()

// 实例化路由器,并设置公共路由前缀 /users
const router = new Router({
  prefix: '/users'
})

app.use(bodyParser())

// 查询用户列表
router.get('/', async ctx => {
 
})

// 查询单个用户
router.get('/:id', async ctx => {
 
})

// 创建用户
router.post('/', async ctx => {

})

// 更新用户
router.patch('/:id', async ctx => {

})

// 删除用户
router.delete('/:id', async ctx => {

})

// 注册路由中间件
app.use(router.routes()).use(router.allowedMethods())

app.listen(3000, () => {
  console.log('服务器运行在 3000 端口')
})

在上面代码中,定义了5个路由方法,分别对应了数据库的查询、插入、更新和删除操作。稍后完成 Prisma 的初始化,将 Prisma Client 引入,就能实现这几个接口了。

然后使用 nodemon 命令来启动服务,最好是在全局安装此模块,方便使用:

$ nodemon src/index.js

Prisma CLI

首先安装下 Prisma 的两个依赖模块:

$ pnpm add -D prisma 
$ pnpm add @prisma/client

安装的第一个 prisma,它是一个 CLI 命令,主要通过它来调用 Prisma 的各种功能,包括数据库迁移,创建Prisma Client 等等。

执行下面的命令,看一下 prisma 的使用说明:

$ npx prisma --help

image-20230509194858894

可以看到,prisma 提供了 7 个命令:

命令说明
init在应用中初始化 Prisma
generate主要用来生成 Prisma Client
db管理数据库的模式和生命周期
migrate迁移数据库
studio启动一个Web 端的工作台来管理数据
validate检查 Prisma 的模式文件的语法是否正确
format格式化Prisma的模式文件,默认就是 prisma/schema.prisma

并且还给出了示例,我们这里主要使用其中的三个,剩下的大家可以自己去使用看看效果:

image-20230509195654406

初始化 Prisma

执行下面的命令,完成初始化:

$ npx prisma init

image-20230509220945387

这个命令的效果是在命令所在目录,也就是现在的根目录中,创建一个 .env 文件,一个 prisma 目录,并在此目录下创建 schema.prisma 文件,如下:

image-20230509195929494

对于 .env 文件,大家都不会陌生,就是一个放置环境变量的文件,这里面的环境变量通常是一些配置信息。

prisma 目录,用来存放和 Prisma 相关的文件,目前只有一个 schema.prisma 文件,这个文件就是前面提及过的 Prisma 模式文件,我们会在此文件中定义数据库的连接信息和模型。

设计 Prisma Schema

schema.prisma 是使用 Primsa 的主要配置文件,称之为 Prisma schema 文件,它包含三个基本结构:

  • 数据源

  • 生成器

  • 数据模型定义

安装 VSC 插件

在编辑模式文件前,在 VS Code 中安装 Prisma 插件,它针对 .prisma 文件提供了代码高亮、格式化、自动补全、跳转定义和检查的功能。没有这个插件的加持,模式文件就是一个纯文本。

image-20230507161551169

设置生成器

使用 generate 定义生成器,通过 provider 属性声明为 prisma-client-js(目前也只支持这一种)。当执行 prisma generate 命令时就会生成 Prisma Client,使用它完成数据的增删改查。

generator client {
  provider = "prisma-client-js"
}

设置数据源

使用 datasource 是定义数据源,用来设置 Prisma 连接的数据库所需要的一些信息。provider 是连接到的数据库的类型,默认是 postgresql,我们改为要用到的 mysql。 url 是数据库URL,通常为了保持配置分离,会将其单独定义到一个环境变量文件中,也就是 prisma cli 自动生成的 .env 文件。通过 env() 函数,会去读取此文件中的变量。

datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

看一下 .env 文件,默认连接的是 Postgresql:

DATABASE_URL=postgresql://johndoe:mypassword@localhost:5432/mydb?schema=public

这是一个 数据库连接 URL的组成:

Structure of the MySQL connection URL

下面都是必填项:

名称占位符描述
HostHOST数据库 IP 或域名, 例如 localhost
PortPORT数据库端口, 例如 3306
UserUSER数据库用户名, 例如 root
PasswordPASSWORD数据库密码
DatabaseDATABASE数据库名称,例如 mydb

根据这个说明,定义我们自己的 MySQL URL:

DATABASE_URL="mysql://root:root123@localhost:3306/prisma"

定义 User 模型

作为 ORM 工具,肯定少不了模型了。Prisma 的模型主要有以下作用:

  • 构成了应用领域的 实体
  • 映射到数据库的 (关系型数据库,例如 PostgreSQL)或 集合 (MongoDB)
  • 构成 Prisma Client API 中 查询 的基础
  • 在使用 TypeScript 时,Prisma Client 为模型及其 变体 提供 类型定义,保证数据库访问的类型安全

定义模型时会用到形如 @id()@default() 这些 Prisma 内置的工具函数。比如 @id() 用来声明主键,@default() 用来设置默认值,命名都非常语义化,基本就是 SQL 中的一些关键字,非常容易理解。

下面是一个 User 模型的定义:

model User {
  id          Int      @id @default(autoincrement())
  name        String   
  email       String   @unique
  password    String
  createdTime DateTime @default(now()) @map("created_time")
  updatedTime DateTime @updatedAt @map("updated_time")

  @@map("user")
}

需要说明的几点信息:

1.模型的名字默认就是创建的数据表的名字,这里是大写的 User,那么数据表名也就是大写的 User,可以使用 @@map() 来设置映射的表名,改为小写的 user。

2.每个模型的记录都是唯一可识别的,也就是要有主键,可以使用 @id 去声明。

3.字段的类型,比如 Int,String,会经过Prisma 转为数据库对应的类型,也就是 int 和 varchar。

4.@unique 是唯一值约束,所以生成的 user 表的 email 字段的值不能重复。

5.像是创建时间和更新时间,为了符合 JS、TS 中的命名规范,使用了小驼峰命名,为了符合数据库命名规范,在后面使用 @map() 重新映射为了下划线命名。

同步数据库

将Prisma 模型同步到数据库,对于我们这样一个新项目,空项目,可以使用下面的命令:

$ npx prisma db push

如果是一个已经有数据的项目,就不能使用这个命令了,转而使用 prisma migrate 迁移。本文先不涉及。

image-20230509213137705

它会创建数据库的schema,并且使用 Prisma schema 同步数据库,还会“偷偷”执行下 prisma generate 命令来生成 Prisma Client。

来到数据库,刷新一下,已经创建好了 prisma 数据库和一张 user 表:

image-20230509213437412

生成 Prisma client

前面同步数据库时,已经执行了 prisma generate。所以现在不需要再次执行了,但是一旦Prisma Schema 文件发生了变动,比如修改了模型,就需要再来执行下这个命令,重新生成 Prisma Client。

generate 命令执行的流程是:

img

CRUD 增删改查

初始化 Prisma Client

有了 Prisma Client,可以使用它来执行 CRUD 操作。初始化:

const { PrismaClient } = require('@prisma/client')

const prisma = new PrismaClient()

Prisma Client 的实例 prisma ,具备丰富的类型,使用方式是 prisma.模型.CRUD方法

image-20230509214952783

image-20230509215012306

我们先来介绍几个常用的 API:

  • findMany:查询多条记录
  • findUnique:查询单条记录
  • create:创建记录
  • update:更新记录
  • delete:删除记录

使用这几个 API 在路由方法中操作数据库,完成接口的开发。

查询用户列表

findMany 不传入参数,表示查询整张 user 表的所有记录,它返回的是一个数组,是 User 模型的实例集合:

router.get('/', async ctx => {
  const users = await prisma.user.findMany()

  ctx.body = users
})

查询单个用户

findUnique 方法中通过 where 设置查询条件,也就是根据指定的 ID 来查询一条用户记录,该方法只返回一条记录,也就是 User 模型的一个实例:

// 查询单个用户
router.get('/:id', async ctx => {
  const id = parseInt(ctx.params.id)
  const user = await prisma.user.findUnique({
    where: { id }
  })

  ctx.body = user
})

需要注意的一点,从 ctx.params.id 获取的 id 是字符串类型,要转为整数类型再去查询。

创建用户

使用 create 可以插入数据,将从请求体中解析的数据,也就是描述 User模型 的一个对象赋值给 data 属性即可:

router.post('/', async ctx => {
  const user = ctx.request.body
  const newUser = await prisma.user.create({
    data: user
  })

  ctx.body = newUser
})

更新用户

使用 update 方法,通过 where 设置查询条件,查询到一个用户,再将待更新的数据赋值给 data完成更新:

router.patch('/:id', async ctx => {
  const id = parseInt(ctx.params.id)
  const updateUser = ctx.request.body

  const user = await prisma.user.update({
    where: {
      id
    },
    data: updateUser
  })

  ctx.body = user
})

删除用户

使用 delete 方法,直接通过 where 设置删除记录的查询条件即可:

router.delete('/:id', async ctx => {
  const id = parseInt(ctx.params.id)
  const user = await prisma.user.delete({
    where: {
      id
    }
  })

  ctx.body = user
})

注意事项:使用 update 和 delete 时,一定要设置where,否则会更新或者删除数据表的所有记录,非常危险。

测试

创建用户:

image-20230509215720849

查询用户列表:

image-20230509215836753

更新用户:

image-20230509215918093

删除用户:

image-20230509215939149

总结

完整代码在这里。

本文通过一个用户的增删改查的例子,在 Koa 中演示了 Prisma 的基本使用,在此总结一下:

  1. 安装依赖
  2. 初始化 Prisma
  3. 设置 Prisma Schema
  4. 同步数据库
  5. 创建Prisma Client
  6. 使用 Prisma Client 实现 CRUD

Prisma 还有很多优秀的特性,本文抛砖引玉,只介绍了最基本的使用,一个单表的增删改查。推荐大家去阅读中文文档站点了解更多关于 Prisma 的内容。

感谢阅读!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/947612.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【100天精通python】Day47:python网络编程_Web编程

目录 1 网络编程与web编程 1.1 网络编程 1.2 web编程 2 Web开发概述 3 Web开发基础 3.1 HTTP协议 3.2 Web服务器 3.3 前端基础 3.4 静态服务器 3.5 前后端交互的基本原理 4 WSGI接口 4.1 CGI 简介 4.2 WSGI 简介 4.3 定义 WSGI 接口 4.4 运行 WSGI 服务 4.5…

面霸的自我修养-synchronized

今天是《面霸的自我修养》的第3弹,内容是Java并发编程中至关重要的关键字synchronized,作为面试中的“必考题”,这部分是你必须要充分准备的内容,接下来我们就一起一探究竟吧。 数据来源: 大部分来自于各机构&#x…

SpringWeb(SpringMVC)

目录 SpringWeb介绍 搭建 SpringWeb SpringWeb介绍 Spring Web是一个基于 Servlet API 构建的原始 web 框架,用于构建基于MVC模式的Web应用程序。在 web 层框架历经 Strust1,WebWork,Strust2 等诸多产品的历代更选 之后,目前业界普…

研发规范第九讲:通用类命名规范(重点)

研发规范第九讲:通用类命名规范(重点) 无规范不成方圆。我自己非常注重搭建项目结构的起步过程,应用命名规范、模块的划分、目录(包)的命名,我觉得非常重要,如果做的足够好&#xff…

聊聊大厂都怎么防止重复下单?

一、问题背景 最简单的:DB 事务。如创建订单时,同时往订单表、订单商品表插数据,这些 Insert 须在同一事务执行。 Order 服务调用 Pay 服务,刚好网络超时,然后 Order 服务开始重试机制,于是 Pay 服务对同一…

java八股文面试[多线程]——自旋锁

优点: 1. 自旋锁尽可能的减少线程的阻塞,这对于锁的竞争不激烈,且占用锁时间非常短的代码块来说性能能大幅度的提升,因为自旋的消耗会小于线程阻塞挂起再唤醒的操作的消耗 ,这些操作会导致线程发生两次上下文切换&…

【Python自学笔记】Python好用的模块收集(持续更新...)

文章目录 日志模块钉钉机器人命令助手持续更新中,如果您有其他实用好用的模块欢迎留言...日志模块 写代码离不开日志,自定义一个理想的日志对于小白来说可能是一件很反锁的事情,就像我刚学习Python的时候自己写的一个自定义日志,为了解决这个痛点,今天就和大家分享一个可以…

Linux开发板下检查及配置串口(波特率/数据发送接收等)的操作

在linux开发板上如何设置和编辑串口波特率、开启指定的uart口? 下面演示常用的命令操作 1)编辑开启指定串口的配置文件 ls -l /boot/uEnv/ sudo vim /boot/uEnv/xxx.txt 2)检查串口是否开启成功 ls /dev/tty* 3)查看串口波特率…

每天 26,315 美元罚款?交通安全局要求特斯拉提供 Autopilot数据

根据美国国家公路交通安全管理局(NHTSA)最近的特别命令,特斯拉公司被要求提供关于其自动驾驶功能Autopilot的相关信息。这一命令是继NHTSA于2021年8月启动初步评估后,在2022年6月升级为正式调查的一部分,NHTSA近期对特…

电子电路学习笔记之NCP304LSQ37T1G ——超低电流电压检测器

超低电流电压检测器是一种专门用于检测极小电流值的设备。它们常用于电子元件或电路中,用于监测电流的存在和程度。这些检测器通常具有高灵敏度和高精度,能够测量微安级别或更小的电流。 超低电流电压检测器的应用领域广泛,例如电池管理系统…

宏昌转债上市价格预测

宏昌转债 基本信息 转债名称:宏昌转债,评级:A,发行规模:3.8亿元。 正股名称:宏昌科技,今日收盘价:30.5元,转股价格:29.62元。 当前转股价值 转债面值 / 转股…

Python绘图系统11:绘制极坐标图像

文章目录 旧代码整改投影下拉选框绘图逻辑源代码 Python绘图系统: 📈从0开始实现一个三维绘图系统自定义控件:坐标设置控件📉坐标列表控件📉支持多组数据的绘图系统📉极坐标绘图图表类型和风格&#xff1a…

C#,《小白学程序》第九课:堆栈(Stack),先进后出

1 文本格式 /// <summary> /// 《小白学程序》第九课&#xff1a;堆栈&#xff08;Stack&#xff09; /// 堆栈与队列是相似的数据形态&#xff1b;特点是&#xff1a;先进后出&#xff1b; /// 比如&#xff1a;狭窄的电梯&#xff0c;先进去的人只能最后出来&#xff1…

【教程】DGL中的子图分区函数partition_graph讲解

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] 目录 函数形式 函数作用 函数内容 函数入参 函数返参 使用示例 实际上官方的函数解释中就已经非常详细了。 函数形式 def partition_graph(g, graph_name, num_parts, out_path, num_hops1, part…

聚观早报|OpenAI宣布推出企业版ChatGPT;苹果公司开设8家新店

【聚观365】8月30日消息 OpenAI宣布推出企业版ChatGPT 比亚迪上半年净利润109.5亿元 歌尔股份上半年净利润4.22亿元 一起教育科技Q2营收6925万元 苹果公司今年开设8家新店 OpenAI宣布推出企业版ChatGPT 据外媒报道&#xff0c;当地时间周一&#xff0c;美国人工智能研究…

用XSIBackup为VMware ESXi打造完美备份方案

文章目录 VMware ESXi 备份方案引言XSIBackup安装步骤1. XSIBackup软件安装2. SSH连接3. 定位到xsibackup目录4. 修改文件权限5. 安装cron查看crontab列表6. 配置备份任务结论VMware ESXi 备份方案 引言 数据就像是我们的生命线,一旦丢失,可能会带来无法挽回的损失。对于那…

2024王道408数据结构P144 T16

2024王道408数据结构P144 T16 思考过程 首先看题目&#xff0c;要求我们把二叉树的叶子结点求出来并且用链表的方式存储&#xff0c;链接时用叶结点的右指针来存放单链表指针。我们很清楚可以看出来能用中序遍历递归的方式实现&#xff0c;因为第一个叶子结点在整棵树的最左下…

2024年java面试--集合篇

文章目录 前言ListSetMapCollectionListSetMapJDK1.7 HashMap&#xff1a;JDK1.8 HashMap&#xff1a; 一、ArrayList和LinkedList的区别二、HashSet的实现原理&#xff1f;三、List接口和Set接口的区别四、hashmap底层实现五、HashTable与HashMap的区别六、线程不安全体现七、…

基于Java+SpringBoot+Vue前后端分离医药管理系统设计和实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

无涯教程-Android - List fragments函数

框架的ListFragment的静态库支持版本&#xff0c;用于编写在Android 3.0之前的平台上运行的应用程序&#xff0c;在Android 3.0或更高版本上运行时,仍使用此实现。 List fragment 的基本实现是用于创建fragment中的项目列表 List in Fragments 示例 本示例将向您说明如何基于…