nextjs初探之连接mysql及插入数据

888 阅读5分钟

背景

在虚拟机里安装mysql,本地连接mysql获取数据。
用到的软件版本:centeos7.6, docker, mysql5.7, nextjs14, mysql2(npm)
先看下效果
数据库: image.png node端: image.png 页面:

image.png

安装软件

centeos7.6

虚拟机用的 virtualBox,大家找一下centeos7.6的镜像,安装一下。
安装后设置一下网络和端口映射

image.png

image.png

安装docker

yum 包更新到最新

sudo yum update

安装需要的软件包

sudo yum install -y yum-utils device-mapper-persistent-data lvm2

设置yum源为阿里云

sudo yum-config-manager --add-repo <http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo>

安装docker

sudo yum install docker-ce
# 启动
sudo systemctl start docker

安装后查看docker版本

docker -v

通过docker安装mysql

拉取mysql镜像

docker pull mysql:5.7

创建容器

docker run -di --name=msql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=admin mysql:5.7

docker run -id --name=m_ysql -p 3306:3306 \
-v /root/mysql/logs:/logs \
-v /root/mysql/data:/var/lib/mysql \
-v /root/mysql/conf:/etc/mysql/conf.d \
-e MYSQL_ROOT_PASSWORD=123456 mysql:5.7

docker cp m_ysql:/etc/mysql/conf.d .
-e 代表添加环境变量  MYSQL_ROOT_PASSWORD  是root用户的登陆密码

docker查看启动的容器

docker ps

image.png 如果下次启动的时候是3306 -> 3306可以通过下面的命令修改,先暂停容器

docker run -e MYSQL_ROOT_PASSWORD=123456 -p 0.0.0.0:3306:3306 image_name

接下来先试试远程连接是否能成功

远程链接mysql

mysql -h 127.0.0.1 -P 3306 -u root -p

如果mysql未找到先查一下如何安装mysql

image.png 出现这个表示连接成功

nextjs连接mysql

先看一下目录结构

image.png
db/index.ts:

import mysql from 'mysql2';

// 创建数据库连接池
const pool = mysql.createPool({
  host: '127.0.0.1',
  port: 3306,
  user: 'root',
  password: '123456',
  database: 'knowledge',
  waitForConnections: true,
  connectionLimit: 10,
  queueLimit: 0,
});

// 导出连接池
export default pool.promise();

query-utils.ts

/* eslint-disable @typescript-eslint/no-explicit-any */
import type { ResultSetHeader } from 'mysql2/promise';
import pool from './connection';

export async function SelectQuery<T>(
  queryString: string,
  params?: any[]
): Promise<Partial<T[]>> {
  let connection;
  try {
    connection = await pool.getConnection();
    const [results] = await connection.execute(queryString, params);
    return results as T[];
  } catch (error) {
    console.error(error);
    throw error;
  } finally {
    if (connection) {
      connection.release();
    }
  }
}

export async function ModifyQuery(
  queryString: string,
  params?: any[]
): Promise<ResultSetHeader> {
  let connection;
  try {
    connection = await pool.getConnection();
    const [result] = await connection.execute(queryString, params);
    return result as ResultSetHeader;
  } catch (error) {
    console.error(error);
    throw error;
  } finally {
    if (connection) {
      connection.release();
    }
  }
}

db/index.ts

import * as employees from './employees/index';

const db = {
  employees,
};

export default db;

db/employees/index.ts

/* eslint-disable @typescript-eslint/no-unsafe-return */
import type { RowDataPacket } from 'mysql2/promise';
import { SelectQuery } from '../query-utils';

export interface IEmployeesRow extends RowDataPacket {
  id: number;
  name: string;
  salary: number;
}

export function getAll() {
  return SelectQuery<IEmployeesRow>('SELECT * FROM employees;');
}

export function getOne(id: number) {
  const queryString = 'SELECT * FROM employees WHERE id = ?;';
  return SelectQuery<IEmployeesRow>(queryString, [id]);
}

页面上获取数据

app/employees/page.tsx

import Link from 'next/link';
import { getAll, type IEmployeesRow } from '~/db/employees/index';

export default async function Page() {
  const req = await getAll();
  console.log('req:::', req);
  return (
    <>
      {req?.map((item: IEmployeesRow | undefined) => {
        return (
          <Link key={item?.id} href={`/employees/${item?.id}`}>
            {item?.name}
          </Link>
        );
      })}
    </>
  );
}

employees/[id]/page.tsx

import { getOne } from '~/db/employees/index';

export default async function Page({ params }: { params: { id: string } }) {
  const req = await getOne(Number(params.id));
  console.log('req:::', req);
  return (
    <>
      <p>{req?.[0]?.name}</p>
      <p>{req?.[0]?.salary}</p>
    </>
  );
}

这样可以从数据库读取到数据了,接下来看看drizzle-orm如何连接mysql及获取数据

更新一下测试mac下是否连接成功的例子

我的A1芯片,很久没看这块了,最近继续看看

本地先安装好docker,前端的依赖和上面的一样

拉取mysql

docker run --platform linux/amd64 -d --name=msql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=admin mysql:5.7

启动一个sql

docker run -id --name=ec_mysql -p 3306:3306 \

-v ~/mysql/logs:/logs \

-v ~/mysql/data:/var/lib/mysql \

-v ~/mysql/conf:/etc/mysql/conf.d \

-e MYSQL_ROOT_PASSWORD=123456 mysql:5.7

测试连接

image.png

index.ts:

import { drizzle } from 'drizzle-orm/mysql2';
import mysql from 'mysql2/promise';

if (
  !process.env.MYSQL_HOST ||
  !process.env.MYSQL_POST ||
  !process.env.MYSQL_USER ||
  !process.env.MYSQL_PASSWORD ||
  !process.env.MYSQL_DATABASE
) {
  throw new Error('no mysql config');
}

// 创建数据库连接池
const poolConnection = mysql.createPool({
  host: process.env.MYSQL_HOST,
  port: Number(process.env.MYSQL_POST),
  user: process.env.MYSQL_USER,
  password: process.env.MYSQL_PASSWORD,
  database: process.env.MYSQL_DATABASE,
  waitForConnections: true,
  connectionLimit: 10,
  queueLimit: 0,
});

export const db = drizzle(poolConnection);

.env.example

# DateBase
MYSQL_HOST=localhost
MYSQL_POST=3306
MYSQL_USER=root
MYSQL_PASSWORD=xxx
MYSQL_DATABASE=xxx

db-test.ts

import type { NextApiRequest, NextApiResponse } from 'next';
import { sql } from 'drizzle-orm';
import { db } from '~/db'; // 引入你配置的 Drizzle ORM 数据库连接模块

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  try {
    // 尝试执行一条简单的 SQL 查询,例如获取当前时间
    const result = await db.execute(sql`SELECT NOW() AS currentTime`)// 假设SQLWrapper是一个类,需要实例化

    // 返回成功的响应
    res.status(200).json({ message: 'Database connected successfully!', result });
  } catch (error) {
    // 捕获错误并返回失败的响应
    console.error('Database connection failed:', error);
    res.status(500).json({ message: 'Database connection failed.', error: String(error) });
  }
}

可以看到

image.png

初始化表

首先定义一个schema,然后通过脚本来执行

先看下脚本

"migrations:generate": "drizzle-kit generate:mysql --config=drizzle.config.ts",
"db:push": "drizzle-kit push:mysql --config=drizzle.config.ts",

第一个生成过程,第二个推送到数据库

drizzle.config.ts

用于配置链接数据,返回一个链接后的数据库对象

import type { Config } from 'drizzle-kit';

if (
  !process.env.MYSQL_HOST ||
  !process.env.MYSQL_POST ||
  !process.env.MYSQL_USER ||
  !process.env.MYSQL_PASSWORD ||
  !process.env.MYSQL_DATABASE
) {
  throw new Error('no mysql config');
}

export default {
  schema: './db/schema/index.ts',
  out: './db/migrations',
  driver: 'mysql2',
  dbCredentials: {
    host: process.env.MYSQL_HOST,
    port: Number(process.env.MYSQL_POST),
    user: process.env.MYSQL_USER,
    password: process.env.MYSQL_PASSWORD,
    database: process.env.MYSQL_DATABASE,
  },
} satisfies Config;

然后db/schema/index.ts里导出的是schema对象,可以理解成sql的对象

import { sql } from 'drizzle-orm';
import {
  int, mysqlTable, timestamp, index, uniqueIndex,
} from 'drizzle-orm/mysql-core';

const cart = mysqlTable(
  'cart',
  {
    id: int('id').autoincrement().primaryKey().notNull(),
    userId: int('userId').notNull(),
    productId: int('productId'),
    quantity: int('quantity'),
    checked: int('checked'),
    createTime: timestamp('createTime').default(sql`now()`).notNull(),
    updateTime: timestamp('updateTime').default(sql`now()`).notNull(),
  },
  // 调整索引命名以保持一致
  (cart) => ({
    uniqueUserIdIndex: uniqueIndex('mmall_cart__user_id__unique').on(
      cart.userId
    ),
    userIdIndex: index('mmall_cart__user_id__idx').on(cart.userId),
  })
);

export default cart;
export {cart}

在对应的数据库中就会创建一个cart的表

插入数据

初始化表后一般都会有一些数据,主要通过db.insert(mmallCategory).values({xxx})来插入数据

await db.insert(schema).values({
    userId: 21,            // 用户ID,假设是1
    productId: 26,       // 商品ID,假设是123
    quantity: 1,          // 商品数量,假设是2
    checked: 1,           // 是否选中,假设是选中(1代表选中,0代表未选中)
    createTime: new Date(),
    updateTime: new Date(),
});

schema为上面我们定义的schema,然后写入对应的值就行。

例子:github.com/jianghr-rr/…