mysql的登陆设置

mysql数据类型

数值类型(Numeric Types)
1.1 整数类型
数据类型 存储大小 范围(有符号) 范围(无符号) 说明
TINYINT 1 字节 -128 ~ 127 0 ~ 255 适合小范围整数
SMALLINT 2 字节 -32,768 ~ 32,767 0 ~ 65,535 适用于较小整数
MEDIUMINT 3 字节 -8,388,608 ~ 8,388,607 0 ~ 16,777,215 中等大小整数
INT(INTEGER) 4 字节 -2,147,483,648 ~ 2,147,483,647 0 ~ 4,294,967,295 常用整数类型
BIGINT 8 字节 -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 0 ~ 18,446,744,073,709,551,615 超大整数
补充:

UNSIGNED(无符号):移除负数,使正数范围翻倍。
ZEROFILL:前导零填充(不推荐,已废弃)。
1.2 浮点类型
数据类型 存储大小 说明
FLOAT(M, D) 4 字节 单精度浮点数(近似值,适合小数计算)
DOUBLE(REAL) 8 字节 双精度浮点数(近似值,适合科学计算)
DECIMAL(NUMERIC)(M, D) 变长 精确小数,适用于货币计算
补充:

M 代表总位数,D 代表小数位数(如 DECIMAL(10,2))。
DECIMAL 存储精确值,比 FLOAT 和 DOUBLE 更适合货币计算。
2. 日期和时间类型(Date & Time Types)
数据类型 存储大小 格式 说明
DATE 3 字节 YYYY-MM-DD 仅存储日期
DATETIME 8 字节 YYYY-MM-DD HH:MM:SS 日期+时间(适合记录精确时间)
TIMESTAMP 4 字节 YYYY-MM-DD HH:MM:SS 自动存储 UTC 时间(适用于日志)
TIME 3 字节 HH:MM:SS 仅存储时间
YEAR 1 字节 YYYY 存储年份(1901~2155)
补充:

TIMESTAMP 会受时区影响,适用于存储 UTC 时间。
DATETIME 不受时区影响,适用于存储本地时间。
MySQL 5.6+ 开始支持 DATETIME(3)(精确到毫秒)。
3. 字符串(文本)类型(String Types)
3.1 固定长度字符串
数据类型 最大长度 说明
CHAR(M) 255 字符 固定长度,适用于定长数据(如性别、国家代码)
补充:

CHAR 适合存储长度固定的数据,查询时速度较快(避免碎片化)。
CHAR(1) 适合存储 Y/N、M/F 之类的固定值。
3.2 可变长度字符串
数据类型 最大长度 说明
VARCHAR(M) 65535 字符 变长,适用于大部分文本数据
补充:

VARCHAR(M) 适合存储长度不确定的数据。
VARCHAR(255) 是最常见的用法,避免超长索引影响性能。
3.3 文本类型(大块文本存储)
数据类型 最大存储大小 说明
TINYTEXT 255 字符 小文本
TEXT 65,535 字符(64 KB) 标准文本
MEDIUMTEXT 16,777,215 字符(16 MB) 中等大小文本
LONGTEXT 4,294,967,295 字符(4 GB) 超大文本
补充:

TEXT 类型不能创建索引(除非是前缀索引 INDEX(text_column(100)))。
如果需要索引,尽量使用 VARCHAR 代替 TEXT。
3.4 二进制数据
数据类型 最大存储大小 说明
TINYBLOB 255 字节 小二进制数据
BLOB 65,535 字节(64 KB) 标准二进制数据
MEDIUMBLOB 16,777,215 字节(16 MB) 中等大小二进制数据
LONGBLOB 4,294,967,295 字节(4 GB) 超大二进制数据
适用于存储图片、视频、PDF 等二进制文件,但一般建议存储文件路径,而非直接存 BLOB 数据。

  1. JSON 类型
    数据类型 说明
    JSON 存储 JSON 格式数据(MySQL 5.7+ 支持)
    特点:

JSON 类型可以存储 结构化数据,并支持 JSON 查询 (JSON_EXTRACT、JSON_ARRAY 等)。
适用于存储动态结构化数据,例如用户配置、日志、标签等。
5. 空间类型(GIS 数据类型)
数据类型 说明
GEOMETRY 存储任何几何数据
POINT 存储单个点(经纬度)
LINESTRING 存储线
POLYGON 存储多边形
适用于地理信息系统(GIS),如存储地图坐标、区域等。

  1. 选择数据类型的最佳实践
    主键:使用 BIGINT UNSIGNED(自增 ID)或 UUID(唯一标识)。
    金额/货币:使用 DECIMAL(10,2),避免 FLOAT 误差。
    时间戳:使用 DATETIME(本地时间)或 TIMESTAMP(UTC)。
    短字符串:用 CHAR(长度固定)或 VARCHAR(长度可变)。
    长文本:使用 TEXT,但避免索引字段。
    二进制数据:尽量存储文件路径,而非 BLOB。

nextjs

import { NextApiRequest, NextApiResponse } from “next”; 是什么?
NextApiRequest 和 NextApiResponse 是 Next.js API 路由 (pages/api/ 目录下的文件) 里用于处理 HTTP 请求和响应的 TypeScript 类型。

📌 作用:

NextApiRequest 👉 表示 API 请求对象(类似 req)。
NextApiResponse 👉 表示 API 响应对象(类似 res)。
它们帮助你 在 TypeScript 中获得更好的代码提示和类型安全。
✅ NextApiRequest 和 NextApiResponse 的作用
在 普通 Express.js API 中,你通常会这样写:

1
2
3
4
5
6
7
8
9

import express from "express";

const app = express();

app.get("/api/user", (req, res) => {
res.json({ message: "Hello User!" });
});
✅ 在 Next.js API 里,相当于这样:
1
2
3
4
5
6

import { NextApiRequest, NextApiResponse } from "next";

export default function handler(req: NextApiRequest, res: NextApiResponse) {
res.status(200).json({ message: "Hello, Next.js API!" });
}

📌 NextApiRequest 和 NextApiResponse 主要作用:

✅ 提供 TypeScript 类型检查
✅ 确保 req.body / req.query / req.method 类型正确
✅ 让 res.status() / res.json() / res.send() 有正确的类型提示

Next.js API 路由 vs Express.js:哪个更好?
Next.js 自带 API 路由 (pages/api/ 或 app/api/),但它和 Express.js 这样的传统后端框架 在功能和使用方式上有一些区别。下面我们来 详细对比 Next.js 后端和 Express.js,并分析 适用场景。

✅ 1. 主要区别
对比项 Next.js API(app/api/) Express.js
架构 前后端一体化(Fullstack) 传统后端(Backend only)
是否依赖 Node.js 服务器 不需要(可以部署到 Vercel) 需要(必须运行 Node.js 服务器)
中间件 支持部分,但不如 Express 灵活 完全支持
路由 基于文件(app/api/*.ts) 手动定义(app.get(“/“, handler))
WebSockets / 实时功能 不原生支持 支持 WebSockets(如 socket.io)
性能 静态优化、自动 Edge 处理 更灵活,但优化需手动
适合的项目类型 前后端一体化的项目 独立后端 API / 微服务
✅ Next.js API 适合小型、前后端一体化的应用(如博客、个人项目)。
✅ Express 适合复杂的后端系统(如 REST API、微服务、WebSocket)。

🚀 2. 路由对比
📌 Next.js API(基于文件的路由)
Next.js 不需要手动定义路由,你只要在 app/api/ 目录里创建文件即可:

ts
复制
编辑
// 📂 app/api/hello.ts
import { NextApiRequest, NextApiResponse } from “next”;

export default function handler(req: NextApiRequest, res: NextApiResponse) {
res.status(200).json({ message: “Hello, Next.js API!” });
}
✅ 访问 http://localhost:3000/api/hello 就能调用 API。
✅ 自动处理路由,无需 app.get() 之类的代码。

📌 Express.js API(手动定义路由)
Express 需要手动创建服务器,并 定义路由:

ts
复制
编辑
import express from “express”;

const app = express();
const PORT = 5000;

app.get(“/api/hello”, (req, res) => {
res.json({ message: “Hello from Express!” });
});

app.listen(PORT, () => console.log(🚀 Server running on http://localhost:${PORT}));
✅ Express 需要手动管理 app.get() 路由。
✅ 更灵活,适合 REST API 和微服务架构。

🚀 3. 中间件支持
📌 Next.js(支持部分中间件,如 cors)
ts
复制
编辑
import { NextApiRequest, NextApiResponse } from “next”;
import Cors from “cors”;

const cors = Cors({ origin: “*” });

export default function handler(req: NextApiRequest, res: NextApiResponse) {
cors(req, res, () => res.status(200).json({ message: “CORS enabled” }));
}
❌ 但 Next.js 不能直接使用 Express 的 app.use(middleware),中间件支持较弱。

📌 Express.js(支持完整中间件,如 body-parser、cors)
ts
复制
编辑
import express from “express”;
import cors from “cors”;

const app = express();
app.use(cors()); // 允许跨域请求
app.use(express.json()); // 解析 JSON 请求体

app.post(“/api/data”, (req, res) => {
res.json({ received: req.body });
});
✅ Express 的中间件功能更强大,可以用 app.use() 全局添加中间件。
✅ 适合需要复杂认证、日志、跨域配置的后端。

🚀 4. WebSockets / 实时通信
📌 Next.js(原生不支持 WebSockets)
Next.js 默认不支持 WebSocket,你只能使用 外部 WebSocket 服务器(如 socket.io)。
解决方案:单独使用 Express + WebSocket。
📌 Express.js(可以直接用 socket.io)
ts
复制
编辑
import express from “express”;
import { createServer } from “http”;
import { Server } from “socket.io”;

const app = express();
const server = createServer(app);
const io = new Server(server);

io.on(“connection”, (socket) => {
console.log(“User connected:”, socket.id);
socket.on(“message”, (msg) => io.emit(“message”, msg));
});

server.listen(5000, () => console.log(🚀 WebSocket Server running on port 5000));
✅ Express.js 可以直接搭建 WebSocket 服务器,而 Next.js 不能。

🚀 5. 适合的场景
项目类型 使用 Next.js API 使用 Express.js
SSR & API 整合(博客、个人项目) ✅ 适合 ❌ 不推荐
简单 CRUD API ✅ 适合 ✅ 也可以
REST API / 后端服务 ❌ 适合 Express ✅ 更好
GraphQL API ❌ 适合 Apollo Server ✅ 更好
WebSockets / 实时应用 ❌ 不能用 ✅ 适合
微服务架构 ❌ 不能用 ✅ 更适合
✅ Next.js API 适用于小型、前后端一体化的应用。
✅ Express.js 适用于更复杂的后端,比如 REST API、WebSockets、微服务。

🔥 结论
特点 Next.js API Express.js
是否依赖 Node.js 服务器 ❌ 不需要 ✅ 需要
性能 🚀 高(自动优化) 🔥 取决于优化
中间件支持 ❌ 部分支持 ✅ 完全支持
WebSockets ❌ 不支持 ✅ 直接支持
适合项目 小型 Web 应用、全栈项目 REST API、WebSockets、微服务

server/routers/ 只是存放业务逻辑,并不能直接作为 API,你需要:

在 server/routers/ 里写业务逻辑(比如 borrow.ts 处理借书)。
在 app/api/ 里创建 API 端点,并调用 server/routers/ 里的逻辑。
前端请求 app/api/ 里的 API,后端再执行 server/routers/ 里的逻辑。
🚀 2. 让 server/routers/ 和 app/api/ 连接
📌 你的 server/routers/borrow.ts(处理借书逻辑)
📍 server/routers/borrow.ts

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

import { db } from "~/server/db";
import { NextApiRequest, NextApiResponse } from "next";

// 获取所有借书记录
export async function getBorrowRecords(req: NextApiRequest, res: NextApiResponse) {
const records = await db.borrowRecord.findMany({
include: { book: true, card: true, admin: true },
});
return res.status(200).json(records);
}

// 处理借书请求
export async function borrowBook(req: NextApiRequest, res: NextApiResponse) {
const { cardId, bookId, adminId } = req.body;
if (!cardId || !bookId) {
return res.status(400).json({ error: "cardId 和 bookId 必须提供" });
}

const book = await db.book.findUnique({ where: { id: bookId } });
if (!book || book.stoke <= 0) {
return res.status(400).json({ error: "书籍库存不足" });
}

const newRecord = await db.borrowRecord.create({
data: { cardId, bookId, borrowDate: new Date(), adminId },
});

await db.book.update({
where: { id: bookId },
data: { stoke: book.stoke - 1 },
});

return res.status(201).json(newRecord);
}

✅ 这个文件只负责逻辑,不暴露 API 端点!

📌 app/api/borrow.ts(暴露 API 端点,让前端可以访问)
📍 app/api/borrow.ts

1
2
3
4
5
6
7
8
9
10

import { NextApiRequest, NextApiResponse } from "next";
import { getBorrowRecords, borrowBook } from "~/server/routers/borrow";

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === "GET") return getBorrowRecords(req, res);
if (req.method === "POST") return borrowBook(req, res);

res.status(405).json({ error: "Method Not Allowed" });
}

✅ 现在 app/api/borrow.ts 是 API 端点,可以调用 server/routers/borrow.ts 里的逻辑!

📌 让前端调用 API
📍 前端组件(例如 app/page.tsx)

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
41

"use client";
import { useState, useEffect } from "react";

export default function BorrowPage() {
const [borrowRecords, setBorrowRecords] = useState([]);

// 获取借书记录
useEffect(() => {
fetch("/api/borrow")
.then((res) => res.json())
.then((data) => setBorrowRecords(data));
}, []);

// 借书
const borrowBook = async () => {
const response = await fetch("/api/borrow", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ cardId: 1, bookId: 2, adminId: 3 }),
});

if (response.ok) {
alert("借书成功!");
} else {
alert("借书失败!");
}
};

return (
<div>
<h1>借书记录</h1>
<ul>
{borrowRecords.map((record) => (
<li key={record.id}>{record.book.title} 借给 {record.card.name}</li>
))}
</ul>
<button onClick={borrowBook}>借书</button>
</div>
);
}

✅ 前端直接请求 /api/borrow,Next.js API 端点 app/api/borrow.ts 处理请求,并调用 server/routers/borrow.ts 里的逻辑!

权限的问题,到底要坐在前端代码上,还是做在数据库用户上?

1
2
3
4
5
6
7
8
9
10
11
12
13
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { cardId } = req.body;

const borrowRecords = await db.borrowRecord.findMany({
where: { cardId: cardId },
});

if (borrowRecords.length > 0) {
return res.status(400).json({ error: "Card has borrow records" });
}

res.status(200).json({ message: "No borrow records found" });
}

await解析promise
await 和 async 是 JavaScript 处理异步操作 的关键字。
它们一起使用,使得异步代码像同步代码一样直观。

✅ 1. async 关键字
async 用于声明一个函数,让它返回 Promise:

ts
复制
编辑
async function fetchData() {
return “Hello”;
}

console.log(fetchData()); // 返回 Promise
📌 async 函数总是返回一个 Promise:

ts
复制
编辑
async function fetchData() {
return “Hello”;
}

fetchData().then(console.log); // “Hello”
🔍 等价于:

ts
复制
编辑
function fetchData() {
return Promise.resolve(“Hello”);
}
✅ async 让函数内部的 return 变成 Promise.resolve(returnValue)!

✅ 2. await 关键字
await 用于等待一个 Promise 解析,必须在 async 函数内部使用:

1
2
3
4
5
6
7
8
9
10
async function fetchData() {
return "Hello";
}

async function main() {
const result = await fetchData();
console.log(result); // "Hello"
}

main();

📌 如果不用 await,代码是这样的:

1
2
3
4
async function main() {
const result = fetchData(); // 返回的是 Promise
console.log(result); // Promise { 'Hello' }
}

🔍 await 让 Promise 变成最终的值!

findUnique 用于唯一键查询
findUnique 只能用于 主键(@id)或唯一索引(@unique):

1
2
3
4
const user = await db.user.findUnique({
where: { id: 1 }, // ✅ 这里 `id` 是 @id
});
console.log(user); // { id: 1, name: "Alice", email: "alice@example.com" }

📌 如果 id 不是 @id 或 @unique,会报错!

✅ findMany 用于查询多条记录
findMany 适用于 查找多个符合条件的记录:

1
2
3
4
5

const users = await db.user.findMany({
where: { name: "Alice" }, // ✅ 可以查找多个
});
console.log(users); // [{ id: 1, name: "Alice" }, { id: 5, name: "Alice" }]

📌 即使 findMany 只查到一条数据,它的返回值仍然是 Array !
第一种写法
ts
复制
编辑
where: {
…(quire.book && { title: quire.book }),
…(quire.publisher && { publisher: quire.publisher }),
…(quire.startyear && quire.endyear && {
year: { gte: (quire.startyear), lte: (quire.endyear) }
}),
…(quire.author && { author: quire.author }),
…(quire.price && { price: quire.price }),
…(quire.category && { category: quire.category }),
}
📌 特点:

这里使用了 对象扩展运算符 …,它的作用是:
如果 quire.book 存在(非 null / undefined / false),就展开 { title: quire.book }
如果 quire.book 不存在,则不添加这个条件
这种方式 更简洁,因为 不会手动写 undefined ? {} 这样的逻辑。
适用于 Prisma where 查询对象,不会传入 undefined 值。
✅ 最终生成的 where 语句(示例) 如果 quire = { book: “Harry Potter”, year: 2001 }

ts
复制
编辑
where: {
title: “Harry Potter”,
year: 2001
}
📌 不会包含 publisher, author, price, category,因为它们是 undefined。

🔹 第二种写法
ts
复制
编辑
const existingRequire = await db.book.findMany({
where: {
quire.book !== undefined ? { title: quire.book } : {},
quire.publisher !== undefined ? { publisher: quire.publisher } : {},
quire.year !== undefined ? { year: quire.year } : {},
quire.author !== undefined ? { author: quire.author } : {},
quire.price !== undefined ? { price: quire.price } : {},
quire.category !== undefined ? { category: quire.category } : {},
}
});
📌 特点:

这里使用的是 三元运算符(condition ? trueValue : falseValue)
每个查询字段都做了 !== undefined 判断
错误❌:where 里写 {}
Prisma 不支持 {} 作为 where 条件的一部分,会导致 无效的查询对象
例如:
ts
复制
编辑
where: {
title: “Harry Potter”,
{} // ❌ 这是非法的 Prisma where 语法
}
✅ 修正的写法(使用 Object.assign())

ts
复制
编辑
const whereCondition = Object.assign(
{},
quire.book !== undefined && { title: quire.book },
quire.publisher !== undefined && { publisher: quire.publisher },
quire.year !== undefined && { year: quire.year },
quire.author !== undefined && { author: quire.author },
quire.price !== undefined && { price: quire.price },
quire.category !== undefined && { category: quire.category }
);

const existingRequire = await db.book.findMany({ where: whereCondition });

在 server/routers/books.ts 中封装业务逻辑
将数据库查询和操作封装在 server/routers/books.ts 中。比如,我们将 GET 和 POST 逻辑分别封装成两个函数:

ts
复制
编辑
// server/routers/books.ts
import { db } from “~/server/db”;

// 获取所有书籍
export async function getAllBooks() {
return await db.book.findMany();
}

// 创建一本新书
export async function createBook(title: string, author: string, price: number, total: number) {
return await db.book.create({
data: { title, author, price, total, stoke: total },
});
}
2. 在 app/api/books/route.ts 或 pages/api/books.ts 中引入业务逻辑
然后在 API 路由文件中,调用这些封装好的业务逻辑函数:

App Router(app/api/books/route.ts)
ts
复制
编辑
// app/api/books/route.ts
import { NextApiRequest, NextApiResponse } from “next”;
import { getAllBooks, createBook } from “~/server/routers/books”;

export async function GET(req: NextApiRequest, res: NextApiResponse) {
try {
const books = await getAllBooks(); // 调用封装好的业务逻辑
return res.status(200).json(books);
} catch (error) {
return res.status(500).json({ error: “Failed to fetch books” });
}
}

export async function POST(req: NextApiRequest, res: NextApiResponse) {
const { title, author, price, total } = req.body;

try {
const newBook = await createBook(title, author, price, total); // 调用封装好的业务逻辑
return res.status(201).json(newBook);
} catch (error) {
return res.status(500).json({ error: “Failed to create book” });
}
}
Pages Router(pages/api/books.ts)
如果你使用的是 Pages Router,你可以按照类似的方式调用 server/routers/books.ts 中的逻辑:

ts
复制
编辑
// pages/api/books.ts
import { NextApiRequest, NextApiResponse } from “next”;
import { getAllBooks, createBook } from “~/server/routers/books”;

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === “GET”) {
try {
const books = await getAllBooks(); // 调用封装好的业务逻辑
return res.status(200).json(books);
} catch (error) {
return res.status(500).json({ error: “Failed to fetch books” });
}
}

if (req.method === “POST”) {
const { title, author, price, total } = req.body;

try {
  const newBook = await createBook(title, author, price, total);  // 调用封装好的业务逻辑
  return res.status(201).json(newBook);
} catch (error) {
  return res.status(500).json({ error: "Failed to create book" });
}

}

return res.status(405).json({ error: “Method Not Allowed” });
}
解释
封装业务逻辑:我们把所有的数据库操作逻辑封装到 server/routers/books.ts 文件中,这样 API 路由文件就不需要关心具体的业务逻辑了,只需要关心请求的接收和响应。

引入业务逻辑:在 app/api/books/route.ts 或 pages/api/books.ts 中,我们通过引入 server/routers/books.ts 来调用封装的函数,保持 API 路由文件的简洁
使用 Controller 模式(可选)
如果你希望进一步分离逻辑,可以使用 Controller 模式,将 server/routers 中的每个操作进一步拆分为不同的 Controller。例如,创建一个 bookController.ts 文件,将 GET 和 POST 请求的业务逻辑分开管理:

ts
复制
编辑
// server/controllers/bookController.ts
import { getAllBooks, createBook } from “~/server/routers/books”;

// 获取所有书籍
export async function getBooks(req, res) {
try {
const books = await getAllBooks();
return res.status(200).json(books);
} catch (error) {
return res.status(500).json({ error: “Failed to fetch books” });
}
}

// 创建新书
export async function addBook(req, res) {
const { title, author, price, total } = req.body;

try {
const newBook = await createBook(title, author, price, total);
return res.status(201).json(newBook);
} catch (error) {
return res.status(500).json({ error: “Failed to create book” });
}
}
然后在你的 API 路由中调用 Controller:

ts
复制
编辑
// app/api/books/route.ts
import { getBooks, addBook } from “~/server/controllers/bookController”;

export async function GET(req, res) {
return getBooks(req, res);
}

export async function POST(req, res) {
return addBook(req, res);
}
这种方式使得你的 API 路由与 Controller 中的具体实现分离,代码更加模块化,维护性更强

图书管理系统架构图