ORM
ORM(Object relational mappers) 的含义是,将数据模型与 Object 建立强力的映射关系,这样我们对数据的增删改查可以转换为操作 Object(对象)。
Prisma 是一个现代 Nodejs ORM 库,根据 Prisma 官方文档 可以了解这个库是如何设计与使用的。
Prisma概述
Prisma 提供了大量工具,包括 Prisma Schema、Prisma Client、Prisma Migrate、Prisma CLI、Prisma Studio 等,其中最核心的两个是 Prisma Schema 与 Prisma Client,分别是描述应用数据模型与 Node 操作 API。
与一般 ORM 完全由 Class 描述数据模型不同,Primsa 采用了一个全新语法 Primsa Schema 描述数据模型,再执行 prisma generate 产生一个配置文件存储在 node_modules/.prisma/client 中,Node 代码里就可以使用 Prisma Client 对数据增删改查了
prisma@4.1.0: 需要的node版本是>=14.17的,否则安装会报如下的错误:
The engine "node" is incompatible with this module. Expected version ">=14.17". Got "14.15.5"
本地安装(推荐)
Prisma CLI 通常作为开发依赖项安装,这就是为什么在下面的命令中使用--save-dev(npm) 和--dev(Yarn) 选项的原因。
npm
使用npm安装:
npm install prisma --save-dev
这应该添加prisma到devDependencies您的package.json. 然后,您可以使用带有前缀的命令调用本地安装的 CLI npx:
npx prisma
generate这是调用命令的示例:(先不要执行,在文章的下面在执行)
npx prisma generate
Yarn (1.19.2+)
使用Yarn安装:
yarn add prisma --dev
这应该添加prisma到devDependencies您的package.json. 然后,您可以使用带有前缀的命令调用本地安装的 CLI yarn:
yarn prisma
generate这是调用命令的示例:(先不要执行,在文章的下面在执行)
yarn prisma generate
建议保持prisma 和 @prisma/client的包的版本一致以避免任何意外错误或行为的发生
全局安装(不推荐)
虽然建议在本地安装Prisma CLI,但您也可以在您的计算机上全局安装它
警告:如果您的机器上有多个 Prisma 项目,全局安装可能会导致这些项目之间的版本冲突
prisma 安装完后,进行初始化
npx prisma init 或者 yarn prisma init // 初始化
执行结果如下:
PS C:\Users\qwd\Desktop\666\qwdMonorepo\packages\server> npx prisma init
✔ Your Prisma schema was created at prisma/schema.prisma
You can now open it in your favorite editor.
Next steps:
1. Set the DATABASE_URL in the .env file to point to your existing database. If your database has no tables yet, read https://pris.ly/d/getting-started
2. Set the provider of the datasource block in schema.prisma to match your database: postgresql, mysql, sqlite, sqlserver, mongodb or cockroachdb.
3. Run prisma db pull to turn your database schema into a Prisma schema.
4. Run prisma generate to generate the Prisma Client. You can then start querying your database.
More information in our documentation:
https://pris.ly/d/getting-started
生成如下4个文件:
prisma/schema.prisma文件的样子如下
.env文件的样子如下
.gitignore文件的样子如下
配置.env文件中的数据库链接
DATABASE_URL="mysql://username:password@localhost:3306/test_prisma" (例如链接mysql)
prisma/schema.prisma的配置文件
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}
用npm 安装@prisma/clientnpm 包:
npm install @prisma/client
用yarn安装@prisma/clientnpm 包:
yarn add @prisma/client
@prisma/client安装完成后,使用以下命令生成 Prisma 客户端:
npx prisma generate 或者 yarn prisma generate
// 官网说直接用 prisma generate 就可以,但是使用后提示,这东西不是个命令
运行后提示如下信息:
// 大概意思就是说在你的schema.prisma文件中,没有发现任何的models,所以不会产生任何东西
// 你可以这样定义一个模型:【模型就是关系型数据库中的表名,非关系型数据库中集合】
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
}
接下来按照提示 在schema.prisma文件中写入上面的提示的代码
接下来再运行一次yarn prisma generate 来生成 Prisma 客户端
这样一来 Prisma 客户端 就生成了,然后就可以在代码里面使用Prisma 客户端来操作数据库crud了
Prisma 客户端的默认位置
如果没有在 prisma/schema.prisma文件内自定义output,则默认generator将 Prisma 客户端(Prisma Client) 生成到文件夹/node_modules/.prisma/client中
自定义output路径
可以在schema.prisma文件中配置output,意思是指定自定义路径generator,例如(假设您的schema.prisma文件位于默认prisma文件夹下):
generator client {
provider = "prisma-client-js"
output = "../src/generated/client"
}
为该模式文件运行prisma generate命令后,Prisma 客户端包将位于:
./src/generated/client
要从自定义位置导入PrismaClient(例如,从名为 的文件./src/script.ts):
import { PrismaClient } from './generated/client'
const prisma = new PrismaClient()
// use `prisma` in your application to read and write data in your DB
实例化客户端,也就是是使用Prisma客户端
通过将 Prisma Client 生成node_modules/.prisma/client并从中导出@prisma/client,您可以将其导入并在代码中实例化客户端,如下所示:
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
//在你的应用程序中使用' prisma '来读写你的数据库中的数据
或者
const { PrismaClient } = require('@prisma/client')
const prisma = new PrismaClient()
//在你的应用程序中使用' prisma '来读写你的数据库中的数据
如何链接数据库
Prisma如何和数据库链接起来呢?
1、首先自己的电脑要有一个数据库才行
2、然后可以使用数据库的客户端桌面/终端软件sqlectron 或者DBeaver来链接数据库
sqlectron、DBeaver MySql等软件的下载链接 【提取码: 9ghb】
推荐看这个MySQL 8.0.27 下载、安装与配置 超详细教程(Windows64位)
DBeaver出现“Public Key Retrieval is not allowed”错误的解决办法
1、用sqlectron链接一个数据库
如果配置好后,点击 Test 提示:Error invoking remote method 'DB_CONNECT': Error: connect ECONNREFUSED 127.0.0.1:3306。查看下方链接:
链接数据库的方式
2、向数据库中新建表
首先在你的schema.prisma文件中,建一个模型(model)也就是数据库的表名和对应的字段
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
}
然后执行命令: yarn prisma db push 或者 npx prisma db push
将
prisma/schema.prisma文件中的模型 User (model User)也就是关系型数据库中的表名User, 推送到数据库,简言之就是在数据库中建立了一个User表(关系型数据库)或者User集合(非关系型数据库)这样一来就完成了通过prisma客户端向mysql数据库添加表的功能了
3、prisma client 来对数据库中的表进行删除、添加、修改、查看数据 等操作
- 3-1 新增数据:向user表中一次性添加一条数据
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient({
// 显示日志信息的简写形式,不直观,LogDefinition其中的值emit始终为stdout
// log: ['query', 'info', 'warn', 'error']
// 推荐使用这种,LogDefinition其中的值emit设置为event就是显示在控制台的
log: [
{ level: 'query', emit: 'event' }, // 在控制台显示
{ level: 'info', emit: 'stdout' }, // 不在控制台显示
// { level: 'info', emit: 'event' }, // 在控制台显示
{ level: 'warn', emit: 'event' }, // 在控制台显示
{ level: 'error', emit: 'event' },// 在控制台显示
],
})
// 将4种日志信息显示在控制台
prisma.$on('query', (e: any) => {
console.log(e)
})
// prisma.$on('info', (e: any) => {
// console.log(e)
// })
prisma.$on('warn', (e: any) => {
console.log(e)
})
prisma.$on('error', (e: any) => {
console.log(e)
})
// 新增数据: 向user表中一次性添加一条数据
async function CreateUser() {
await prisma.user.create({
data: {
email: 'elsa@prisma888.io',
name: 'Elsa Prisma888',
},
})
}
CreateUser().catch((e) => {
throw e
}).finally(async () => {
await prisma.$disconnect()
})
新增数据: 向user表中一次性添加多条数据
async function CreateUser() {
// const createMany = await prisma.user.createMany({
await prisma.user.createMany({
data: [
{ name: 'Bob', email: 'bob@prisma.io' },
{ name: 'Bobo', email: 'bob@prisma.io' }, // 邮箱要唯一,这里就重复了,只会添加一条
{ name: 'Yewande', email: 'yewande@prisma.io' },
{ name: 'Angelique', email: 'angelique@prisma.io' },
],
// 不能插入具有唯一字段或 ID 字段已存在的记录,简言之不能插入重复数据
skipDuplicates: true,
})
}
CreateUser().catch((e) => {
throw e
}).finally(async () => {
await prisma.$disconnect()
})
- 3-2 查询数据
查询数据:通过 ID 或唯一标识符查询表数据
async function CreateUser() {
const user = await prisma.user.findUnique({
where: {
email: 'yewande@prisma.io',
},
})
console.log(user);
}
CreateUser().catch((e) => {
throw e
}).finally(async () => {
await prisma.$disconnect()
})
查询数据:通过 复合/组合ID 查询表数据,创建表复合/组合ID有问题,无法添加数据,后期再找原因
//1、在schema.prisma文件中新建一个数据库表,表名叫做people
model User4 {
id Int @id @default(autoincrement()) //这个id不能写
email String @unique
firstName String
lastName String
// 复合/组合ID,这个字段就相当于id了,同时firstName、lastName必须是必填项
// 不能写成 firstName String? 和 lastName String?
@@id([firstName, lastName])
}
然后执行命令: yarn prisma db push 或者 npx prisma db push去创建该表
查询数据:获取某一个表的所有记录
async function CreateUser() {
const users = await prisma.user.findMany()
console.log(users);
}
CreateUser().catch((e) => {
throw e
}).finally(async () => {
await prisma.$disconnect()
})
查询数据:获取某一个表的所有记录,并且进行过滤和排序
// 以下查询返回`email`字段包含的所有记录`Prisma`,并按字段对结果进行排序`title`。
// 查询跳过前 200 条记录并返回记录 201 - 220
async function CreateUser() {
const results = await prisma.user.findMany({
skip: 200,
take: 20,
where: {
email: {
contains: 'Prisma',
},
},
orderBy: {
title: 'desc',
},
})
console.log(results);
}
CreateUser().catch((e) => {
throw e
}).finally(async () => {
await prisma.$disconnect()
})
其他的查询条件可以参考官网地址:
- 3-3 更新数据
更新数据: 更新单条记录
async function updateUser() {
const updateUser = await prisma.user.update({
where: {
email: 'viola@prisma.io',
},
data: {
name: 'Viola the Magnificent',
},
})
console.log(updateUser);
}
updateUser().catch((e) => {
throw e
}).finally(async () => {
await prisma.$disconnect()
})
更新数据: 更新多条记录
async function updateManyUser() {
// 更新 user表中 email字段中包含prisma.io的全部数据,找到这些数据后,
// 更新的是数据中的name字段值,更新为ADMIN
const updateUsers = await prisma.user.updateMany({
where: {
email: {
contains: 'prisma.io',
},
},
data: {
name: 'ADMIN',
},
})
console.log(updateUsers);
}
updateManyUser().catch((e) => {
throw e
}).finally(async () => {
await prisma.$disconnect()
})
更新数据: 更新或创建数据
async function updateManyUser() {
// 找到user表中使用viola@prisma.io电子邮件的一条数据,
// 把数据中的name字段的值变成Viola the Magnificent
// 如果user表中没有使用viola@prisma.io电子邮件的数据,则会创建该数据
const upsertUser = await prisma.user.upsert({
where: {
email: 'viola@prisma.io',
},
update: {
name: 'Viola the Magnificent',
},
create: {
email: 'viola@prisma.io',
name: 'Viola the Magnificent',
},
})
console.log(upsertUser);
}
updateManyUser().catch((e) => {
throw e
}).finally(async () => {
await prisma.$disconnect()
})
更新数据: 更新某一个表中的所有数据中的数字字段
async function updateManyUser() {
//根据当前值 更新数字字段 例如,递增或乘法。以下查询将`views`和`likes`字段递增`1`:
const updatePosts = await prisma.user.updateMany({
data: {
views: {
increment: 1,
},
likes: {
increment: 1,
},
},
})
console.log(updatePosts);
}
updateManyUser().catch((e) => {
throw e
}).finally(async () => {
await prisma.$disconnect()
})
更新数据: 更新某一个表中的某一条数据中的数字字段
async function updateManyUser() {
//根据当前值 更新数字字段 例如,递增或乘法。以下查询将`views`和`likes`字段递增`1`:
const updatePosts = await prisma.user.update({
where: {
email: 'bob@prisma.io',
},
data: {
total: {
increment: 1,
},
// likes: {
// increment: 1,
// },
},
})
console.log(updatePosts);
}
updateManyUser().catch((e) => {
throw e
}).finally(async () => {
// 查询完数据之后断开链接
await prisma.$disconnect()
})
- 3-4 删除数据
删除数据: 删除单条数据
async function deleteUser() {
const deleteUser = await prisma.user.delete({
where: {
email: 'bert@prisma.io',
},
})
console.log(deleteUser);
}
deleteUser().catch((e) => {
throw e
}).finally(async () => {
await prisma.$disconnect()
})
删除数据: 删除多条数据
async function deleteUsers() {
const deleteUsers = await prisma.user.deleteMany({
where: {
email: {
contains: 'prisma.io',
},
},
})
console.log(deleteUsers);
}
deleteUsers().catch((e) => {
throw e
}).finally(async () => {
await prisma.$disconnect()
})
删除数据: 删除所有数据
async function deleteUsers() {
const deleteUsers = await prisma.user.deleteMany({})
console.log(deleteUsers);
}
deleteUsers().catch((e) => {
throw e
}).finally(async () => {
await prisma.$disconnect()
})
- 3-5 两个表如何关联起来
// 1、在schema.prisma文件中写入下面的代码
// 数据库的Project表和对应的字段
model Project {
id Int @id @default(autoincrement())
proName String @unique
proIntroduction String
proLeader String
proId String @unique
proInfo String
proMembers String
// ErrorInfos ErrorInfo[] 是为了创建和ErrorInfo 模型 相关联,必须添加的
ErrorInfos ErrorInfo[]
}
// 通过 prisma client 建立数据库中2个表的联系
// ErrorInfo表中名为projectId的外键列,对应的外键链接是Project表中名为ProId的主键列
// 在 Prisma 模式中,外键/主键关系由字段@relation上的属性表示author
// 下面2段代码的大致意思如下:
// 把 Project 模型中的ProId列作为ErrorInfo模型中projectId列的外键
// author Project @relation(fields: [projectId], references: [proId])
// projectId: String
model ErrorInfo {
id Int @id @default(autoincrement())
author Project @relation(fields: [projectId], references: proId])
projectId String
errorMsg String
errorMsgId String
}
// 2、在执行文件index.ts中写入下面的代码
async function saveErrorInfo() {
// 创建一条project记录和两条关联的errorInfo记录:
const userAndPosts = await prisma.project.create({
data: {
proName: '前端项目111',
proIntroduction: '前端项目的简介111',
proLeader: '前端项目负责人111',
proId: '前端项目的项目id111',
proInfo: '前端项目的项目信息111',
proMembers: '小红,小丽,小美,小花,小翠',
// 数据库中错误信息表ErrorInfo,添加的数据
errorInfos: {
create: [
// project表中的ProId字段和ErrorInfo表中的projectId自动就关联起来了,在model里面配置好了
{ errorMsg: 'Prisma Day 2020', errorMsgId: '01' },
{ errorMsg: 'How to write a Prisma schema', errorMsgId: '02' },
],
},
},
})
console.log(userAndPosts);
// 把数据返回给前端展示
}
saveErrorInfo().catch((e) => {
throw e
}).finally(async () => {
// 关闭数据库的链接
await prisma.$disconnect()
})
这样2个表就通过 project表中的proid字段关联起来了
接下来可以查看一下刚才2个表关联的数据
async function saveErrorInfo() {
// 查询指定项目 id 的错误信息列表
const allErrorInfo = await prisma.project.findMany({
where: {
proId: '前端项目的项目id111',
},
include: {
errorInfos: true,
},
})
console.log(allErrorInfo);
// 把数据返回给前端展示
}
saveErrorInfo().catch((e) => {
throw e
}).finally(async () => {
await prisma.$disconnect()
})
结果如下:
其他的各种高级crud操作,查看官网链接:
4、点击查看Prisma的基本概念
5、生成数据库
npm install @prisma/client // 安装api链接器
npx prisma generate // 生成调用方式
npx prisma migrate dev --name init // 根据模型生成数据库表