prisma在node中的基本使用

3,466 阅读8分钟

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

这应该添加prismadevDependencies您的package.json. 然后,您可以使用带有前缀的命令调用本地安装的 CLI npx

npx prisma 

generate这是调用命令的示例:(先不要执行,在文章的下面在执行)

npx prisma generate

Yarn (1.19.2+)

使用Yarn安装:

yarn add prisma --dev

这应该添加prismadevDependencies您的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个文件:

image.png

prisma/schema.prisma文件的样子如下

image.png

.env文件的样子如下

image.png

.gitignore文件的样子如下

image.png

配置.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 就可以,但是使用后提示,这东西不是个命令

运行后提示如下信息:

image.png

// 大概意思就是说在你的schema.prisma文件中,没有发现任何的models,所以不会产生任何东西  
// 你可以这样定义一个模型:【模型就是关系型数据库中的表名,非关系型数据库中集合】
model User {  
  id    Int     @id @default(autoincrement())  
  email String  @unique  
  name  String?  
}

接下来按照提示 在schema.prisma文件中写入上面的提示的代码

image.png

接下来再运行一次yarn prisma generate 来生成 Prisma 客户端

image.png

这样一来 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官网链接

sqlectron、DBeaver MySql等软件的下载链接 【提取码: 9ghb

mysql下载和安装详细教程

推荐看这个MySQL 8.0.27 下载、安装与配置 超详细教程(Windows64位)

DBeaver连接mysql驱动下载失败怎么办?

DBeaver出现“Public Key Retrieval is not allowed”错误的解决办法

1、用sqlectron链接一个数据库

image.png

如果配置好后,点击 Test 提示:Error invoking remote method 'DB_CONNECT': Error: connect ECONNREFUSED 127.0.0.1:3306。查看下方链接:

blog.ttionya.com/article-170…

链接数据库的方式

www.prisma.io/docs/concep…

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()
})

其他的查询条件可以参考官网地址:

www.prisma.io/docs/concep…

  • 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字段关联起来了

image.png

image.png

接下来可以查看一下刚才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()
})

结果如下:

image.png

其他的各种高级crud操作,查看官网链接:

www.prisma.io/docs/concep…

4、点击查看Prisma的基本概念

5、生成数据库

npm install @prisma/client // 安装api链接器
npx prisma generate // 生成调用方式
npx prisma migrate dev --name init // 根据模型生成数据库表