From 3fa50e79f12fe2b66ebd5d643ed597c6a121b198 Mon Sep 17 00:00:00 2001 From: muqiuhan Date: Sat, 3 May 2025 10:47:05 +0000 Subject: deploy: a0dad147ccf1d831c5f48d8d0e868160a23cc92c --- .../index.html" | 6 +- .../19/Repository-pattern-in-Typescript/index.html | 4 +- .../index.html" | 7 +- 2025/04/13/uuidv7-rdbms/index.html | 308 +++++++++++++++++++++ 2025/04/20/linux-amd-screen-boom/index.html | 290 +++++++++++++++++++ 5 files changed, 609 insertions(+), 6 deletions(-) create mode 100644 2025/04/13/uuidv7-rdbms/index.html create mode 100644 2025/04/20/linux-amd-screen-boom/index.html (limited to '2025') diff --git "a/2025/02/18/Prisma-\345\205\263\347\263\273\345\236\213\346\225\260\346\215\256\345\272\223\347\232\204-Self-relations/index.html" "b/2025/02/18/Prisma-\345\205\263\347\263\273\345\236\213\346\225\260\346\215\256\345\272\223\347\232\204-Self-relations/index.html" index fda4a344..b69d4397 100644 --- "a/2025/02/18/Prisma-\345\205\263\347\263\273\345\236\213\346\225\260\346\215\256\345\272\223\347\232\204-Self-relations/index.html" +++ "b/2025/02/18/Prisma-\345\205\263\347\263\273\345\236\213\346\225\260\346\215\256\345\272\223\347\232\204-Self-relations/index.html" @@ -213,7 +213,7 @@

一对一的 self-relation 需要两个端点,即使这两个端点是同一条数据。

而在关系型数据库中,一对一的 self-relation 可以用如下 SQL 描述:

-
1
2
3
4
5
6
7
8
9
CREATE TABLE "User" (
id SERIAL PRIMARY KEY,
"name" TEXT,
"successorId" INTEGER
);

ALTER TABLE "User" ADD CONSTRAINT fk_successor_user FOREIGN KEY ("successorId") REFERENCES "User" (id);

ALTER TABLE "User" ADD CONSTRAINT successor_unique UNIQUE ("successorId");
+
1
2
3
4
5
6
7
8
9
CREATE TABLE "User" (
id SERIAL PRIMARY KEY,
"name" TEXT,
"successorId" INTEGER
);

ALTER TABLE "User" ADD CONSTRAINT fk_successor_user FOREIGN KEY ("successorId") REFERENCES "User" (id);

ALTER TABLE "User" ADD CONSTRAINT successor_unique UNIQUE ("successorId");

一对多

1
2
3
4
5
6
7
model User {
id Int @id @default(autoincrement())
name String?
teacherId Int?
teacher User? @relation("TeacherStudents", fields: [teacherId], references: [id])
students User[] @relation("TeacherStudents")
}
@@ -226,7 +226,7 @@

可以通过将 teacher 字段设为 required 来要求每个 User 都有一名 teacher。

用 SQL 描述 User model:

-
1
2
3
4
5
6
7
CREATE TABLE "User" (
id SERIAL PRIMARY KEY,
"name" TEXT,
"teacherId" INTEGER
);

ALTER TABLE "User" ADD CONSTRAINT fk_teacherid_user FOREIGN KEY ("teacherId") REFERENCES "User" (id);
+
1
2
3
4
5
6
7
CREATE TABLE "User" (
id SERIAL PRIMARY KEY,
"name" TEXT,
"teacherId" INTEGER
);

ALTER TABLE "User" ADD CONSTRAINT fk_teacherid_user FOREIGN KEY ("teacherId") REFERENCES "User" (id);

teacherId 没有使用 UNIQUE 约束,这代表着多个 students 可以有同一个 teacher

多对多

1
2
3
4
5
6
model User {
id Int @id @default(autoincrement())
name String?
followedBy User[] @relation("UserFollows")
following User[] @relation("UserFollows")
}
@@ -243,7 +243,7 @@
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
model User {
id Int @id @default(autoincrement())
name String?
followedBy Follows[] @relation("followedBy")
following Follows[] @relation("following")
}

model Follows {
followedBy User @relation("followedBy", fields: [followedById], references: [id])
followedById Int
following User @relation("following", fields: [followingId], references: [id])
followingId Int

@@id([followingId, followedById])
}

在关系型数据库中,可以用如下 SQL 描述:

-
1
2
3
4
5
6
7
8
CREATE TABLE "User" (
id integer DEFAULT nextval('"User_id_seq"'::regclass) PRIMARY KEY,
name text
);
CREATE TABLE "_UserFollows" (
"A" integer NOT NULL REFERENCES "User"(id) ON DELETE CASCADE ON UPDATE CASCADE,
"B" integer NOT NULL REFERENCES "User"(id) ON DELETE CASCADE ON UPDATE CASCADE
);
+
1
2
3
4
5
6
7
8
CREATE TABLE "User" (
id integer DEFAULT nextval('"User_id_seq"'::regclass) PRIMARY KEY,
name text
);
CREATE TABLE "_UserFollows" (
"A" integer NOT NULL REFERENCES "User"(id) ON DELETE CASCADE ON UPDATE CASCADE,
"B" integer NOT NULL REFERENCES "User"(id) ON DELETE CASCADE ON UPDATE CASCADE
);

在同一模型上建立多个 self-relations

1
2
3
4
5
6
7
8
9
model User {
id Int @id @default(autoincrement())
name String?
teacherId Int?
teacher User? @relation("TeacherStudents", fields: [teacherId], references: [id])
students User[] @relation("TeacherStudents")
followedBy User[] @relation("UserFollows")
following User[] @relation("UserFollows")
}
diff --git a/2025/02/19/Repository-pattern-in-Typescript/index.html b/2025/02/19/Repository-pattern-in-Typescript/index.html index bdd29669..d5509d8e 100644 --- a/2025/02/19/Repository-pattern-in-Typescript/index.html +++ b/2025/02/19/Repository-pattern-in-Typescript/index.html @@ -217,10 +217,10 @@
  • IGenericRepository 中定义的函数是每个 Repository 公开的通用存储函数。
  • 以上这些就是对业务中的实体的 Repository 抽象,这样就隔离开了业务和存储逻辑,例如使用 MongoDB,可以实现一个 MongoGenericRepository:

    -
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    import { Model } from 'mongoose';
    import { IGenericRepository } from '../../../core';

    export class MongoGenericRepository<T> implements IGenericRepository<T> {
    private _repository: Model<T>;
    private _populateOnFind: string[];

    constructor(repository: Model<T>, populateOnFind: string[] = []) {
    this._repository = repository;
    this._populateOnFind = populateOnFind;
    }

    getAll(): Promise<T[]> {
    return this._repository.find().populate(this._populateOnFind).exec();
    }

    get(id: any): Promise<T> {
    return this._repository.findById(id).populate(this._populateOnFind).exec();
    }

    create(item: T): Promise<T> {
    return this._repository.create(item);
    }

    update(id: string, item: T) {
    return this._repository.findByIdAndUpdate(id, item);
    }
    }
    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    import { Model } from 'mongoose';
    import { IGenericRepository } from '../../../core';

    export class MongoGenericRepository<T> implements IGenericRepository<T> {
    private _repository: Model<T>;
    private _populateOnFind: string[];

    constructor(repository: Model<T>, populateOnFind: string[] = []) {
    this._repository = repository;
    this._populateOnFind = populateOnFind;
    }

    getAll(): Promise<T[]> {
    return this._repository.find().populate(this._populateOnFind).exec();
    }

    get(id: any): Promise<T> {
    return this._repository.findById(id).populate(this._populateOnFind).exec();
    }

    create(item: T): Promise<T> {
    return this._repository.create(item);
    }

    update(id: string, item: T) {
    return this._repository.findByIdAndUpdate(id, item);
    }
    }

    然后实现一个 MongoDataServices:

    -
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    import { Injectable, OnApplicationBootstrap } from '@nestjs/common';
    import { InjectModel } from '@nestjs/mongoose';
    import { Model } from 'mongoose';
    import { IDataServices } from '../../../core';
    import { MongoGenericRepository } from './mongo-generic-repository';
    import {
    Author,
    AuthorDocument,
    Book,
    BookDocument,
    Genre,
    GenreDocument,
    } from './model';

    @Injectable()
    export class MongoDataServices
    implements IDataServices, OnApplicationBootstrap
    {
    authors: MongoGenericRepository<Author>;
    books: MongoGenericRepository<Book>;
    genres: MongoGenericRepository<Genre>;

    constructor(
    @InjectModel(Author.name)
    private AuthorRepository: Model<AuthorDocument>,
    @InjectModel(Book.name)
    private BookRepository: Model<BookDocument>,
    @InjectModel(Genre.name)
    private GenreRepository: Model<GenreDocument>,
    ) {}

    onApplicationBootstrap() {
    this.authors = new MongoGenericRepository<Author>(this.AuthorRepository);
    this.books = new MongoGenericRepository<Book>(this.BookRepository, [
    'author',
    'genre',
    ]);
    this.genres = new MongoGenericRepository<Genre>(this.GenreRepository);
    }
    }
    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    import { Injectable, OnApplicationBootstrap } from '@nestjs/common';
    import { InjectModel } from '@nestjs/mongoose';
    import { Model } from 'mongoose';
    import { IDataServices } from '../../../core';
    import { MongoGenericRepository } from './mongo-generic-repository';
    import {
    Author,
    AuthorDocument,
    Book,
    BookDocument,
    Genre,
    GenreDocument,
    } from './model';

    @Injectable()
    export class MongoDataServices
    implements IDataServices, OnApplicationBootstrap
    {
    authors: MongoGenericRepository<Author>;
    books: MongoGenericRepository<Book>;
    genres: MongoGenericRepository<Genre>;

    constructor(
    @InjectModel(Author.name)
    private AuthorRepository: Model<AuthorDocument>,
    @InjectModel(Book.name)
    private BookRepository: Model<BookDocument>,
    @InjectModel(Genre.name)
    private GenreRepository: Model<GenreDocument>,
    ) {}

    onApplicationBootstrap() {
    this.authors = new MongoGenericRepository<Author>(this.AuthorRepository);
    this.books = new MongoGenericRepository<Book>(this.BookRepository, [
    'author',
    'genre',
    ]);
    this.genres = new MongoGenericRepository<Genre>(this.GenreRepository);
    }
    }

    Sunday, March 30, 2025 7:58 PM:

    diff --git "a/2025/04/02/N-1-selects-problem-\344\270\216-Prisma-ORM/index.html" "b/2025/04/02/N-1-selects-problem-\344\270\216-Prisma-ORM/index.html" index 2df41efe..ac98e832 100644 --- "a/2025/04/02/N-1-selects-problem-\344\270\216-Prisma-ORM/index.html" +++ "b/2025/04/02/N-1-selects-problem-\344\270\216-Prisma-ORM/index.html" @@ -211,7 +211,7 @@

    Prisma ORM 在设计上就考虑了 N+1 问题,并提供了一种既方便开发者又高效的解决方案。当使用 Prisma Client 查询数据并需要包含关联模型时,Prisma 会自动优化查询,避免产生 N+1 查询,主要通过关系查询(Relation Queries)中的 include 选项或嵌套读取(nested reads)来实现这一点:

    假设想获取所有用户及其发布的帖子,使用 Prisma Client,可以这样写:

    -
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    import { PrismaClient } from '@prisma/client'

    const prisma = new PrismaClient()

    async function getUsersWithPosts() {
    const usersWithPosts = await prisma.user.findMany({
    include: {
    posts: true, // 指示 Prisma 加载关联的 posts
    },
    })
    // usersWithPosts 包含了用户列表,每个用户对象中都有一个 posts 数组
    console.log(usersWithPosts)
    }

    getUsersWithPosts()
    .catch((e) => {
    throw e
    })
    .finally(async () => {
    await prisma.$disconnect()
    })
    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    import { PrismaClient } from '@prisma/client'

    const prisma = new PrismaClient()

    async function getUsersWithPosts() {
    const usersWithPosts = await prisma.user.findMany({
    include: {
    posts: true, // 指示 Prisma 加载关联的 posts
    },
    })
    // usersWithPosts 包含了用户列表,每个用户对象中都有一个 posts 数组
    console.log(usersWithPosts)
    }

    getUsersWithPosts()
    .catch((e) => {
    throw e
    })
    .finally(async () => {
    await prisma.$disconnect()
    })

    当执行上述查询时,Prisma 不会 生成 N+1 个 SQL 查询。而是首先会分析请求,并将其转化为数量非常有限的高效 SQL 查询。对于上面这个一对多关系的 include 查询,Prisma 通常会执行以下两步(类似于批量加载策略):

      @@ -234,6 +234,11 @@