背景
最近在研究怎么进行研发提效的事。业务有这么几个特点:
- 插件开发,项目多而小,前后端都没那么难;
- 后端绝大多数逻辑都是 CRUD,数据结构也很简单;
- 前端 UI 用组件库就行,逻辑基本上就是调用 CRUD 的接口或一些 OpenAPI;
那么针对这些特点,优先提高一下后端的开发效率。每次都新建个 Git Repo,搞一套 CI/CD 实在是太重了。于是我盯上了 FaaS,也就是「云函数」。因为本文的重点不是它,所以就不多扩展了,不知道 FaaS 也不会影响后面的内容,只要知道它直接在云服务提供的浏览器 IDE 里面写一个函数,就能生成一个 API 就可以了。当然也少不了「云数据库」,不知道也没关系,还是不影响后文的理解。
总之,我现在要快速搞一个 CRUD 的项目,来跑一下整个流程。下面来看看我是怎么跟 C 老师对话得到我想要的内容的吧。
总结
因为聊天内容太长了,所以还是先把总结写在前面吧,把聊天记录放到后面大家慢慢看。
- 首先,最终生成的代码绝对是可以跑的,不过参数还是需要自己修改,所以还是要有一些编程基础啊;
- 然后,C 老师是真的能帮码农提高效率,我用的还只是 GPT3.5,目前看来效果我已经很满意了;
- 最后,最最重要的是你得会提问。我也是混了好几天 码农翻身 – ChatGPT 基地 的知识星球,看了好多案例,还自己实践了几天才渐渐掌握诀窍的;
小 Tips:告诉大家个小窍门,最好同时开 2 个以上的 tab,一个专门用来查零碎的小问题,一个保持上下文的干净。很好用。
把我问 C 老师的问题提炼出来,大家先过一下目,实际上也就 10 个问题而已。剩下那么多内容都是 C 老师回答的:
- 你是一个非常有经验的程序员,我想向你询问一些编程方面的问题。你可以用专业名词回复我,而不需要解释它们,我自己回去查。你可以优先回答思路和步骤,而不需要马上就返回给我代码。直到我跟你说“请给我代码”,你再把具体代码展示给我。总之,一次回答当中,请尽量全部都是思路或者全部都是代码,而且信息密度要尽量大。如果你明白了,请回复“明白”
- 我想在 mysql 中新建一个测试的用户和测试用的db,要怎么做
- 我已经安装了 MySQL,现在请告诉我 nodejs 的具体代码
- 能不能从新建文件开始,把每一步写的详细一点
- npm 包 mysql 和 mysql2 有什么区别?
- 那请把上面的例子用 mysql2 再给一遍吧
- 请把 morgan 的代码加到上面的 nodejs Demo 代码中,给我展示完整的代码
- 上文中 mysql 的 users 表的结构是什么样的
- 我现在有了如下服务,请在浏览器的 console 中输入代码,为我创建20条数据,直接给我代码即可 【code】
- 请参考下面已有的 3 条数据的格式,为我生成20条模拟数据,静态数据即可,不需要用代码动态生成:【code】
下面就是比较完整的聊天记录了,大家慢慢看~~
聊天过程 TL;DR
注:我将一些不成功的提问过滤掉了,留下的都是比较关键的有用的提问。
1. 先给它角色
来自你的消息:
你是一个非常有经验的程序员,我想向你询问一些编程方面的问题。你可以用专业名词回复我,而不需要解释它们,我自己回去查。你可以优先回答思路和步骤,而不需要马上就返回给我代码。直到我跟你说“请给我代码”,你再把具体代码展示给我。总之,一次回答当中,请尽量全部都是思路或者全部都是代码,而且信息密度要尽量大。如果你明白了,请回复“明白”
来自 ChatGPT 的消息:
明白。
2. 先把 MySQL 准备好
安装什么的我就省略了,其实我开了另一个 tab 来问这些零碎的问题,以免主 tab 中的上下文太混乱。
来自你的消息:
我想在 mysql 中新建一个测试的用户和测试用的db,要怎么做
来自 ChatGPT 的消息:
你可以按照以下步骤在 MySQL 中新建一个测试用户和测试数据库:
以超级用户(如 root 用户)连接到 MySQL 服务器,可以使用以下命令连接:
mysql -u root -p
然后输入超级用户的密码进行身份验证。
创建一个新的数据库,可以使用以下命令:
CREATE DATABASE testdb;
这将创建一个名为 testdb 的数据库。
创建一个新的用户,可以使用以下命令:
CREATE USER 'testuser'@'localhost' IDENTIFIED BY 'mypassword';
这将创建一个名为 testuser 的用户,并使用密码 mypassword 进行身份验证。其中,
'localhost'
表示该用户只能从本地进行连接。将 testuser 用户赋予访问 testdb 数据库的权限,可以使用以下命令:
GRANT ALL PRIVILEGES ON testdb.* TO 'testuser'@'localhost';
这将使 testuser 用户拥有访问 testdb 数据库的所有权限。
退出 MySQL 客户端,可以使用以下命令:
EXIT;
现在,你已经成功创建了一个名为 testuser 的用户,以及一个名为 testdb 的数据库,并且授予了 testuser 用户访问 testdb 数据库的权限。你可以使用以下命令来连接到 MySQL 服务器并使用 testuser 用户访问 testdb 数据库:
mysql -u testuser -p testdb
然后输入 testuser 用户的密码进行身份验证。
3. 接下来让 Nodejs 和 MySQL 连起来
来自你的消息:
我已经安装了 MySQL,现在请告诉我 nodejs 的具体代码
来自 ChatGPT 的消息:
好的,Node.js 连接 MySQL 数据库的基本步骤如下:
- 安装 mysql2 模块
在终端中运行以下命令来安装 mysql2 模块:
npm install mysql2
- 在程序中连接 MySQL 数据库
使用以下代码连接 MySQL 数据库:
const mysql = require('mysql2'); // 创建连接池 const pool = mysql.createPool({ host: 'localhost', // 数据库地址 user: 'root', // 数据库用户 password: 'password', // 数据库密码 database: 'database_name', // 数据库名称 waitForConnections: true, connectionLimit: 10, queueLimit: 0 }); // 使用连接池查询数据 pool.query('SELECT * FROM your_table_name', function (err, results, fields) { if (err) throw err; console.log(results); });
这里,你需要将数据库地址、数据库用户、数据库密码和数据库名称替换为你自己的数据。
在以上代码中,我们先创建了一个连接池,然后通过连接池来查询数据库,MySQL 连接池是一种重用连接的技术,对于高并发的请求能更快的响应,同时具有更好的可扩展性。
来自你的消息:
能不能从新建文件开始,把每一步写的详细一点
来自 ChatGPT 的消息:
当然可以,我们从头开始一步一步地搭建一个带 MySQL 数据库的 Node.js 服务:
- 首先,打开终端,使用命令行工具创建一个新的文件夹,例如使用以下指令:
mkdir my-node-app
- 然后,进入这个文件夹,使用以下命令初始化一个 Node.js 项目:
cd my-node-app npm init
在运行
npm init
命令时会提示你输入一些项目信息,例如项目名称、描述、作者等等。你可以根据自己的需要自行填写。
- 接下来,我们需要在项目中安装 MySQL 驱动程序,使用以下命令在项目中安装
mysql
模块:npm install mysql
- 安装完成后,在根目录创建一个名为
index.js
的文件,并在文件中引入mysql
模块:
const mysql = require('mysql');
- 接着,我们需要连接到 MySQL 数据库。可以先创建一个连接池,便于我们重复使用数据库连接。连接池可以自动管理连接的创建和释放,避免频繁地创建和销毁连接,提高性能。以下是示例代码:
const pool = mysql.createPool({ connectionLimit: 10, host: 'localhost', user: 'root', password: 'password', // 这里需要修改为你自己的密码 database: 'my_database' // 这里需要修改为你自己的数据库名 });
解释一下上面的代码,其中
connectionLimit
用于设置连接池的最大连接数,host
用于设置 MySQL 数据库的主机名或 IP 地址,user
和password
分别对应 MySQL 数据库的用户名和密码,database
对应连接的数据库名。你需要根据自己的具体情况修改这些配置。
- 最后,在回调函数中执行 SQL 查询语句。以下是一个简单的查询示例,该查询语句会查询一个名为
users
的表中的所有行:
pool.getConnection((err, connection) => { if (err) throw err; // 查询失败抛出异常 const sql = 'SELECT * FROM users'; connection.query(sql, (error, results, fields) => { connection.release(); // 释放连接 if (error) throw error; // 查询失败抛出异常 console.log(results); // 输出查询结果 }); });
解释一下上面的代码,
getConnection
方法实现从连接池中获取一个连接,执行查询之前需要获取一个连接。query
方法执行 SQL 查询语句,查询完成后需要释放连接(使用release()
方法)以便连接池可以重复使用这个连接。results
参数对应查询结果,fields
参数对应所有字段的元数据信息。到这里为止,我们已经完成了一个带 MySQL 数据库的 Node.js 服务的搭建过程。如果你想要更深入地了解 Node.js 和 MySQL 数据库的相关内容,可以参考官方文档或者各种在线教程。
4. 小插曲 – 把 C 老师拉回 mysql2
注:这块出了点小状况。C 老师一会用 mysql2
一会用 mysql
,有点乱。想了想还是把这段留下来,也算是给大家一个参考,看我是怎么把它拉回来的。其实我问的问题不多,但是它回答的内容比较多,各位可以快速扫一下就行了。
来自你的消息:
npm 包 mysql 和 mysql2 有什么区别?
来自 ChatGPT 的消息:
mysql
和mysql2
都是 Node.js 中连接 MySQL 数据库的第三方库,它们的主要区别在于性能和功能特性。
mysql
是连接 MySQL 最常见的 Node.js 库之一,因为它是最早的 Node.js MySQL 驱动程序之一。它可以连接 MySQL 数据库并执行查询,但是它在处理多个查询时性能比较低,并且它不支持异步/等待接口。相比之下,
mysql2
这个包致力于提供更高的性能和全面的特性。与mysql
不同的是,mysql2
是一个使用纯 JavaScript 编写的库,并支持很多额外的功能,例如:支持 promises、streaming resultsets、复制流和支持视图,同时避免了在执行查询语句时被攻击者利用。因此,如果您需要高性能和全面的特性,那么建议使用
mysql2
来连接 MySQL 数据库。但是如果你的应用程序需要与一个老的,只支持mysql
的版本兼容,或者你不需要mysql2
的某些特性,那么还可以继续使用mysql
。来自你的消息:
那请把上面的例子用 mysql2 再给一遍吧
来自 ChatGPT 的消息:
好的,以下是使用
mysql2
来查询 MySQL 数据库并返回结果的示例代码:
const mysql = require('mysql2'); const pool = mysql.createPool({ host: 'localhost', user: 'root', password: 'password', database: 'database_name', waitForConnections: true, connectionLimit: 10, queueLimit: 0 }); function queryDatabase(sql, params, callback) { pool.query(sql, params, function (error, results, fields) { if (error) { return callback(error, null); } return callback(null, results); }); } // 使用示例 const sql = 'SELECT * FROM table_name WHERE id = ?'; const params = [1]; queryDatabase(sql, params, function (error, results) { if (error) { console.log(error); return; } console.log(results); });
上面的代码示例中,我们使用
mysql2
来创建连接池,并通过连接池来查询数据库。注意,mysql2
支持使用参数占位符(?
)来防止 SQL 注入攻击。当查询执行完成后,我们调用回调函数来释放连接并返回查询结果。
5. 第一版比较完整的代码
注:这块省略了一段加 morgan
日志的对话,不耽误。
来自你的消息:
请把 morgan 的代码加到上面的 nodejs Demo 代码中,给我展示完整的代码
来自 ChatGPT 的消息:
好的,请参考下面的完整代码,我已经加入了 morgan 中间件并进行了相应的注释:
// 引入必备模块 const express = require('express'); const bodyParser = require('body-parser'); const mysql = require('mysql'); const morgan = require('morgan'); // 引入 morgan 中间件 // 创建 express 应用 const app = express(); // 使用 body-parser 中间件来解析请求体中的 JSON 数据 app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); // 使用 morgan 中间件来记录每一次请求的信息 app.use(morgan('combined')); // 创建一个 MySQL 数据库连接池 const pool = mysql.createPool({ connectionLimit: 10, // 最多同时处理 10 个连接请求 host: 'localhost', // 数据库服务器的地址 user: 'root', // 登录数据库的用户名 password: 'password', // 登录数据库的密码 database: 'test', // 要连接的数据库的名字 }); // GET 请求的处理程序 app.get('/users', (req, res) => { // 因为通过 URL 查询字符串也可以传递客户端数据,所以这里也解析一下查询字符串中的参数 const { name } = req.query; // 查询数据 let sql = 'SELECT * FROM users'; if (name) { sql += ` WHERE name LIKE '%${name}%'`; } pool.query(sql, (error, results) => { if (error) { res.status(500).send(error); } else { res.send(results); } }); }); // POST 请求的处理程序 app.post('/users', (req, res) => { // 获取客户端提交的数据 const { name, email } = req.body; // 把数据插入到数据库中 pool.query('INSERT INTO users SET ?', { name, email }, (error, results) => { if (error) { res.status(500).send(error); } else { res.send(results); } }); }); // PUT 请求的处理程序 app.put('/users/:id', (req, res) => { // 获取客户端提交的数据和 URL 中的参数 const { id } = req.params; const { name, email } = req.body; // 更新指定 ID 的数据 pool.query('UPDATE users SET ? WHERE id = ?', [{ name, email }, id], (error, results) => { if (error) { res.status(500).send(error); } else { res.send(results); } }); }); // DELETE 请求的处理程序 app.delete('/users/:id', (req, res) => { // 获取 URL 中的参数 const { id } = req.params; // 删除指定 ID 的数据 pool.query('DELETE FROM users WHERE id = ?', id, (error, results) => { if (error) { res.status(500).send(error); } else { res.send(results); } }); }); // 启动服务器 app.listen(3000, () => { console.log('Server is running at http://localhost:3000'); });
以上就是完整代码,如果您需要对接自己的 MySQL 数据库,需要修改
host
、user
、password
和database
这四个参数,分别代表数据库服务器的地址、登录数据库的用户名、密码和要连接的数据库的名字。
6. 竟然还没建表
注:先有了代码,后建的表,好像跟平时工作相反哈。不过仔细想想,这才是正常的思维啊,现有业务的描述,然后才能想出来怎么建表嘛。只不过我们在描述业务的过程中,已经把代码提前写出来了而已。
来自你的消息:
上文中 mysql 的 users 表的结构是什么样的
来自 ChatGPT 的消息:
很抱歉我没有提供相关信息,下面是 users 表的结构。
CREATE TABLE users ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) NOT NULL, email VARCHAR(100) NOT NULL UNIQUE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
这个 SQL 语句会在 MySQL 数据库中创建一个名为 users 的表,它包含三个列:id、name 和 email。其中,id 是一个自增的整数,作为主键,name 和 email 都是必填项,email 还需要保证唯一性。该表使用 InnoDB 引擎,字符集为 utf8mb4,使用 utf8mb4_unicode_ci 算法进行比较和排序。
7. 调用接口试试,顺便多生成几条数据
注:这块 C 老师好像把上下文忘了,只能我手动给它补上了。另外,生成的代码因为 async/await 的语法原因,还不能直接在 console 里运行,还是需要小改一下的。只要去掉 async,把 await 改成 promise 的写法就行了。这里就留个动手题大家自己试一下吧。
来自你的消息:
我现在有了如下服务,请在浏览器的 console 中输入代码,为我创建20条数据,直接给我代码即可
// 引入必备模块 const express = require('express'); const bodyParser = require('body-parser'); const mysql = require('mysql'); const morgan = require('morgan'); // 引入 morgan 中间件 // 创建 express 应用 const app = express(); // 使用 body-parser 中间件来解析请求体中的 JSON 数据 app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); // 使用 morgan 中间件来记录每一次请求的信息 app.use(morgan('combined')); // 创建一个 MySQL 数据库连接池 const pool = mysql.createPool({ connectionLimit: 10, // 最多同时处理 10 个连接请求 host: 'localhost', // 数据库服务器的地址 user: 'root', // 登录数据库的用户名 password: 'password', // 登录数据库的密码 database: 'test', // 要连接的数据库的名字 }); // GET 请求的处理程序 app.get('/users', (req, res) => { // 因为通过 URL 查询字符串也可以传递客户端数据,所以这里也解析一下查询字符串中的参数 const { name } = req.query; // 查询数据 let sql = 'SELECT * FROM users'; if (name) { sql += ` WHERE name LIKE '%${name}%'`; } pool.query(sql, (error, results) => { if (error) { res.status(500).send(error); } else { res.send(results); } }); }); // POST 请求的处理程序 app.post('/users', (req, res) => { // 获取客户端提交的数据 const { name, email } = req.body; // 把数据插入到数据库中 pool.query('INSERT INTO users SET ?', { name, email }, (error, results) => { if (error) { res.status(500).send(error); } else { res.send(results); } }); }); // PUT 请求的处理程序 app.put('/users/:id', (req, res) => { // 获取客户端提交的数据和 URL 中的参数 const { id } = req.params; const { name, email } = req.body; // 更新指定 ID 的数据 pool.query('UPDATE users SET ? WHERE id = ?', [{ name, email }, id], (error, results) => { if (error) { res.status(500).send(error); } else { res.send(results); } }); }); // DELETE 请求的处理程序 app.delete('/users/:id', (req, res) => { // 获取 URL 中的参数 const { id } = req.params; // 删除指定 ID 的数据 pool.query('DELETE FROM users WHERE id = ?', id, (error, results) => { if (error) { res.status(500).send(error); } else { res.send(results); } }); }); // 启动服务器 app.listen(3000, () => { console.log('Server is running at http://localhost:3000'); });
来自 ChatGPT 的消息:
以下是用 fetch 函数向服务器批量创建20条数据的代码:
// 定义函数,用于发送 POST 请求并创建数据 async function createUsers() { const endpoint = 'http://localhost:3000/users'; const headers = { 'Content-Type': 'application/json' }; const data = [ { name: 'Alice', email: 'alice@example.com' }, { name: 'Bob', email: 'bob@example.com' }, { name: 'Charlie', email: 'charlie@example.com' }, // ...还有17条数据 ]; try { const response = await fetch(endpoint, { method: 'POST', headers, body: JSON.stringify(data), }); const result = await response.json(); console.log('创建成功:', result); } catch (error) { console.error('创建失败:', error); } } // 调用函数,创建数据 createUsers();
注意:以上代码需要在浏览器的 console 中执行,而不是在服务器端编写和运行。
来自你的消息:
请参考下面已有的 3 条数据的格式,为我生成20条模拟数据,静态数据即可,不需要用代码动态生成:
const data = [
{ name: ‘Alice’, email: ‘alice@example.com‘ },
{ name: ‘Bob’, email: ‘bob@example.com‘ },
{ name: ‘Charlie’, email: ‘charlie@example.com‘ },
// …还有17条数据
];来自 ChatGPT 的消息:
根据上述数据格式,以下是生成20条静态数据的一种方法:
const data = [ { name: 'Alice', email: 'alice@example.com' }, { name: 'Bob', email: 'bob@example.com' }, { name: 'Charlie', email: 'charlie@example.com' }, { name: 'David', email: 'david@example.com' }, { name: 'Emma', email: 'emma@example.com' }, { name: 'Frank', email: 'frank@example.com' }, { name: 'Grace', email: 'grace@example.com' }, { name: 'Hannah', email: 'hannah@example.com' }, { name: 'Ian', email: 'ian@example.com' }, { name: 'Jane', email: 'jane@example.com' }, { name: 'Kate', email: 'kate@example.com' }, { name: 'Liam', email: 'liam@example.com' }, { name: 'Mandy', email: 'mandy@example.com' }, { name: 'Nina', email: 'nina@example.com' }, { name: 'Oliver', email: 'oliver@example.com' }, { name: 'Peter', email: 'peter@example.com' }, { name: 'Rose', email: 'rose@example.com' }, { name: 'Samantha', email: 'samantha@example.com' }, { name: 'Tom', email: 'tom@example.com' }, { name: 'Victoria', email: 'victoria@example.com' } ];
另外,以下是另一种生成20条静态数据的方法:
const data = Array.from({ length: 20 }, (_, i) => ({ name: `User ${i + 1}`, email: `user${i + 1}@example.com` }));
请让我知道需要返回给你哪一种方法的具体代码。
彩蛋
恭喜你能够耐心的看到最后,作为奖励,我把我复盘之后总结出来的咒语告诉你吧,效果特别的好:
我现在想新建个 express + mysql2 的服务,要求:
- 目录结构尽量科学,文件拆分合理
- 用 commonjs 的方式写
- 模拟一个 mysql 的 users 表,有 id,name,email 属性
- express 服务实现对 users 表的增删改查 API
请先列出来目录结构,然后挨个 js 文件展示代码,只需要返回代码,不需要解释任何事情。