存储数据

服务端应用需要一种方法跟数据仓库连接,然后就可以处理这个数据仓库里的数据了,比如用户可以通过应用的客户端去发布一个内容,这个内容会通过网络交给服务端应用,服务端收到请求会把这个请求主题里面的数据提取出来,然后把它放在应用的数据仓库里存储起来,这样以后需要用到这个数据的时候就可以从数据仓库里调取出来。


数据连接

通常会使用一种叫做 Drivers 的东西,字面意思是数据驱动,驱动就知道它怎么跟服务端应用沟通,也知道怎么去连接某一种类型的数据仓库服务,有点像中间人,负责把服务端应用要做的事情告诉给数据仓库服务。找一个适用于后台语言并能够连接到使用的数据仓库服务的驱动。在 node 里面,这种驱动就是一个包,比如 mysql、mysql2。


安装驱动连接数据仓库

使用 mysql2 这个包提供的功能去连接使用 mysql 类型的数据仓库服务

1
npm install mysql2

如果使用了 typescript,还需要安装一下这个包的类型定义,这样编辑器就知道 mysql2 这个包里都有什么东西了

1
npm install types/mysql2 --save-dev

使用 mysql2 连接

在应用里可以新建一个连接,然后可以去重复使用这个连接,在这个连接里面需要设置连接的那个数据仓库服务的主机、端口号、用户、还有密码之类的信息,这些信息可以保存在项目的环境变量里面,比如

设置环境变量

1
2
3
4
5
6
#数据仓库配置
MYSQL_HOST=localhost
MYSQL_POST=3306
MYSQL_USER=root
MYSQL_PASSWORD=cxn931119
MYSQL_DATABASE=xb2_node

在 config.js 中导出

1
2
3
4
5
6
7
8
9
10
/**
* 数据仓库配置
*/
export const {
MYSQL_HOST,
MYSQL_POST,
MYSQL_USER,
MYSQL_PASSWORD,
MYSQL_DATABASE
} = process.env;

创建一个数据服务连接,新建文件 database/mysql.ts,创建连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import mysql from 'mysql2';
import{
MYSQL_HOST,
MYSQL_POST,
MYSQL_USER,
MYSQL_PASSWORD,
MYSQL_DATABASE
} from '../../app/app.config';

/**
* 创建数据服务连接
*/
export const connection = mysql.createConnection({
host:MYSQL_HOST,
port:parseInt(MYSQL_POST,10),
user:MYSQL_USER,
password:MYSQL_PASSWORD,
database:MYSQL_DATABASE
})

测试一下,在 main.ts 中输入后在终端中使用 node 运行一下,控制台打印成功连接服务。

1
2
3
4
5
6
7
8
9
10
11
12
import {connection} from './app/database/mysql'

/**
* 测试试用数据服务连接
*/
connection.connect(error=>{
if(error){
console.log('连接数据服务失败',error.message);
return
}
console.log('成功连接服务')
})

调取内容

post.service.ts:

1
2
3
4
5
6
7
8
9
10
11
12
13
import {connection} from '../app/database/mysql'

/**
* 获取内容列表
*/
export const getPosts = async () => {
const statement = `
SELECT * FROM post
`;
const [data] = await connection.promise().query(statement);

return data;
};

post.controller.ts:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { Request, Response, NextFunction } from 'express'; //引入接口、处理器、参数需要的类型
import { getPosts } from './post.service';

/**
* 内容列表
*/
export const index = async (
request: Request,
response: Response,
next: NextFunction,
) => {
const posts = await getPosts();
response.send(posts);
};

利用数据之间的关系

post.service.ts:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import {connection} from '../app/database/mysql'
/**
* 获取内容列表
*/
export const getPosts = async () => {
const statement = `
SELECT
post.id,
post.title,
post.content,
JSON_OBJECT( //使用JSON_OBJECT创建了一个存放作者信息的对象
'id', user.id,
'name', user.name
) as user
FROM post
LEFT JOIN user
ON user.id = post.userId
`;
const [data] = await connection.promise().query(statement);

return data;
};

处理使用数据服务时遇到的异常情况

在控制器中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { Request, Response, NextFunction } from 'express'; //引入接口、处理器、参数需要的类型
import { getPosts } from './post.service';

/**
* 内容列表
*/
export const index = async (
request: Request,
response: Response,
next: NextFunction,
) => {
try {
const posts = await getPosts();
response.send(posts);
} catch (error) {
next(error) //将error交给默认的异常处理器
}
};

在中间件中:

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
/**
* 默认异常处理器
*/
export const defaultErrorHandler = (
error: any,
request: Request,
response: Response,
next: NextFunction,
) => {
if(error.message){
console.log(error.message) //如果有error.message,在控制台上打印
}
let statusCode: number, message: string;

/**
* 处理异常
*/
switch (error.message) {
default:
statusCode = 500;
message = '服务暂时出了点问题~';
break;
}
response.status(statusCode).send({ message });
};