.
3ss.cn

怎么使用Nodejs连接Mysql,实现差不多的增删改查操作

接下来示例代码的主要技术点包括

基础框架

Koa

Koa-router

koa-nunjucks-2

Mysql连接包

mysqljs

0、前置需求

安装mysql数据库并启动

安装Nodejs(这个应该都木有问题)

1、node连接数据库

创建一个空的文件夹

执行 yarn add koa koa-router mysql

在根目录下创建一个js(test.js)文件,用来测试连接数据库操作

我们先在test.js中写一段代码,输出hello,保证启动程序不报错

const Koa = require("koa") // 导入koa
const Router = require("koa-router") //导入koa-router
const mysql = require("mysql")  // 导入mysql,连接mysql 需要用到
const app = new Koa(); // 实例化koa
const router = new Router(); // 实例化路由
// 创建一个路径为/hello的get请求
router.get("/hello", async ctx => {
// 返回 字符串 hello
    ctx.body = "hello"

})

// koa注册路由相关
app
.use(router.routes())
.use(router.allowedMethods())
// 监听端口
.listen(3333,()=>{
    console.log("server running port:" + 3333);
})

在项目根目录下执行 node test.js 或者 nodemon test.js 启动项目

使用 nodemon启动项目需要全局安装 yarn global add nodemon 或者npm i -g nodemon

使用nodemon启动项目,nodemon将监视启动目录中的文件,如果有任何文件更改,nodemon将自动重新启动node应用程序,强烈建议使用 nodemon 启动node项目

项目启动完成后,我们在浏览器输入 http://localhost:3333/hello,就可以看到页面中输出 文字 hello 了

这个界面出现后,就证明我们的项目启动没有问题

接下来我们就用node连接mysql数据库了

我们先准备一波数据

      CREATE DATABASE db1;
      USE db1;
      CREATE TABLE user (
    	id INT PRIMARY KEY auto_increment,
      	NAME VARCHAR(20) NOT NULL,
     	age INT NOT NULL
      ); 
      INSERT INTO user VALUES 
      (null, "张三", 23),
      (null, "李四", 24),
      (null, "王五", 25),
      (null, "赵六", 26);

2、 连接mysql数据库,实现表格显示功能

接下来我们在test.js中写连接mysql的代码

  const Koa = require("koa") // 导入koa
  const Router = require("koa-router") //导入koa-router
  const mysql = require("mysql")  // 导入mysql,连接mysql 需要用到
  const app = new Koa(); // 实例化koa
  const router = new Router(); -- 实例化路由

  // mysqljs 连接 mysql数据库
  let connection = mysql.createConnection({
      host: '127.0.0.1', // mysql所在的主机,本地的话就是 127.0.0.1 或者 localhost, 如果数据库在服务器上,就写服务器的ip
      user: 'root', // mysql的用户名
      password: '密码', // mysql的密码
      database: 'db1' // 你要连接那个数据库
  })

  // 连接 mysql
  connection.connect(err=>{
      // err代表失败
      if(err) {
          console.log("数据库初始化失败");
      }else {
          console.log("数据库初始化成功");
      }
  })

  // 创建一个路径为/hello的get请求
  router.get("/hello", async ctx => {
  // 返回 字符串 hello
      ctx.body = "hello"

  })

  // koa注册路由相关
  app
  .use(router.routes())
  .use(router.allowedMethods())
  // 监听端口
  .listen(3333,()=>{
      console.log("server running port:" + 3333);
  })

当终端输出数据库初始化成功文字就代表,数据库连接成功了

刚才我们已经在db1数据库中准备了四条数据,接下来我们就可以把数据查询出来,展示在控制台了

我们在 connection.connect方法下加入这段查询代码

connection.query方法的第一个参数是一个字符串类型的sql语句,第二个参数是可选的,后边会说,最后是一个包含了错误信息和正确响应结果数据的方法

  const selectSql = "SELECT * FROM user"
  connection.query(selectSql, (err,res) => {
      if(err) console.log(err);
      console.log(res);
  })

返回的数据是这样的

这个时候数据库中的数据就已经被查询出来了,那么我们就可以把这些数据通过JSON的格式返回给前端了

通过添加这段代码把数据以JSON的格式返回给浏览器

  // 因为 mysqljs不支持 Promise方式CRUD数据
  // 所以我们做一个简单的封装
  function resDb(sql) {
      return new Promise((resolve,reject) => {
          connection.query(sql, (err,res) => {
              if(err) {
                  reject(err)
              }else {
                  resolve(res)
              }
          })
      })
  }

  //请求 /userAll 的时候返回数据
  router.get("/userAll", async ctx => {
      ctx.body =  await resDb("SELECT * FROM user")
  })

这个数据才是我们所需要的,呃呃呃,数据是返回了,我们可是做前端的,怎么能没有页面呐,先加入一个展示数据的表格页面,这里使用的是 nunjucks 模板引擎,先来安装一下yarn add koa-nunjucks-2

test.js中添加这段代码

  const koaNunjucks = require('koa-nunjucks-2');
  const path = require('path');

   // 注入 nunjucks 模板引擎
   app.use(koaNunjucks({
      ext: 'html', // html文件的后缀名
      path: path.join(__dirname, 'views'), // 视图文件放在哪个文件夹下
      nunjucksConfig: {
        trimBlocks: true // 自动去除 block/tag 后面的换行符
      }
    }));
    //在 /userAll这个路由中我们不直接返回数据了,我们返回table.html页面
  router.get("/userAll", async ctx => {
  const userAll = await resDb("SELECT * FROM user")
  await ctx.render("table",{userAll})
  })

通过nunjucks模板引擎,我们把所有的html文件统一放在了根目录的views文件夹下,那么我们需要在根目录下创建一个views文件夹,在文件夹中创建 table.html的文件,文件代码如下

    <!DOCTYPE html>
      <html>
      <head>
          <meta charset="UTF-8">
          <meta http-equiv="X-UA-Compatible" content="IE=edge">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title>Document</title>
          <style>
              .table{
                  width: 500px;
              }
              td{
                  text-align: center;
              }
          </style>
      </head>
      <body>
          <table border="1"  cellspacing="0">
              <thead>
                  <tr>
                      <th>id</th>
                      <th>姓名</th>
                      <th>年龄</th>
                  </tr>
              </thead>
              <tbody>
                  {% for user in userAll %}
                  <tr >
                      <td>{{user.id}}</td>
                      <td>{{user.NAME}}</td>
                      <td>{{user.age}}</td>
                  </tr>
                  {% endfor %}
              </tbody>
          </table>
      </body>
      </html>

重启服务器后 访问 http://localhost:3333/userAll

这个页面出来后,显示部分就大功告成了

查询功能做完了,接下来我们就可以实现新增功能

3、 添加数据到mysql数据库中

我们先把table.html页面的添加部分写完

  <form action="/addUser">
      <label for="name">
          用户名:
          <input type="text" name="name" placeholder="请输入用户名">
      </label>
      <label for="age">
          年龄:
          <input type="number" name="age" min="0" placeholder="请输入年龄">
      </label>
      <input type="submit" value="添加">
  </form>

这个时候页面是长这样的

当我们输入完用户名和年龄点击添加按钮后,浏览器会通过 get请求 把数据发送到 /addUser 这个路由中,接下来,我们在test.js中接收一下前端传的参数,并且把参数保存到数据库中。然后刷新页面

//请求 /addUser 接受前端传过来的数据,并且把数据持久化到数据库中
  router.get("/addUser", async ctx => {
      const { name, age } = ctx.query
      // 判断 name 和 age是否有值,都有值时,数据存入数据库,刷新表格页面
      // 否则直接返回到表格页面
      if(name && age) {
      await resDb("INSERT INTO user values(null,?,?)",[name, age])
      }
       //重定向路由,到 userAll
      ctx.redirect("/userAll")
  })

为了提高 resDb 的健壮性,我们对这个方法进行了升级

  function resDb(sql, params) {
      return new Promise((resolve,reject) => {
          let sqlParamsList = [sql]
          if(params) {
              sqlParamsList.push(params)
          }
          connection.query(...sqlParamsList, (err,res) => {
              if(err) {
                  reject(err)
              }else {
                  resolve(res)
              }
          })
      })
  }

升级之后的这个方法适合 CRUD的 promise 化了,当然 修改和删除功能下边我们会说

到这个时候,我们的新增功能就完成了,那么我们来看一波截图,并且理一下逻辑

4、 通过id更新数据

更新数据的前端部分,我们就不写模态框了,直接写个类似新增的表单,实现更新的操作吧,其实新增和更新功能非常类似,有差别的地方只是sql的写法

我们先把table.html页面改造一下

      <form action="/updateUser">
          <label for="id">
              id:
              <input type="number" name="id" placeholder="请输入要更新的ID">
          </label>
          <label for="name">
              用户名:
              <input type="text" name="name" placeholder="请输入用户名">
          </label>
          <label for="age">
              年龄:
              <input type="number" name="age" min="0" placeholder="请输入年龄">
          </label>
          <input type="submit" value="修改">
      </form>

下面我们看下后台的代码

  //请求 /updateUser 接受前端传过来的数据,并且把数据持久化到数据库中
  router.get("/updateUser", async ctx => {
      const { id, name, age } = ctx.query
      // 判断 id, name 和 age是否有值,都有值时,更新数据库中的数据,刷新表格页面
      // 否则直接返回到表格页面
      if(id, name && age) {
      await resDb("UPDATE user SET name=?, age=? WHERE id=?",[name, age, id])
      }
      //重定向路由,到 userAll
      ctx.redirect("/userAll")
  })

代码逻辑和新增部分的逻辑是一样的,

刚才在写新增和更新的sql代码,大家会看到sql语句中有?占位符,第二个参数数组是?占位符对应的内容。那么这个时候大家肯定会有这样一个疑问,为啥我们不直接把前端传过来的参数拼进去。非得这么麻烦。

其实这样通过占位符的方式写sql是为了防止 sql注入,有关sql注入的文章大家可以参考这篇 sql注入原理及防范

5、通过id删除单条数据

老规矩我们先把table.html页面改造一下

  <table class="table" border="1"  cellspacing="0">
      <thead>
          <tr>
              <th>id</th>
              <th>姓名</th>
              <th>年龄</th>
              <th>操作</th>
          </tr>
      </thead>
      <tbody>
          {% for user in userAll %}
          <tr >
              <td>{{user.id}}</td>
              <td>{{user.NAME}}</td>
              <td>{{user.age}}</td>
              <td>
                  <a href={{'/delete/'+user.id}}>删除</a>
              </td>
          </tr>
          {% endfor %}
      </tbody>
  </table>

看下页面效果

老规矩,下面我们来看看后台的代码

  //请求/delete/:id  接受前端传过来的数据,并且把对应的id的数据删掉
  router.get("/delete/:id", async ctx => {
      const { id } = ctx.params
      // 判断 id否有值,有值时,根据id删除数据库中的数据,刷新表格页面
      // 否则直接返回到表格页面
      if(id) {
      await resDb("DELETE FROM user WHERE id=?",[id])
      }
      //重定向路由,到 userAll
      ctx.redirect("/userAll")
  })

到目前为止对表格的增删改查(CRUD),就都已经写完了。

6、 完整代码

目录结构

package.json

    {
       "koa": "^2.13.1",
       "koa-nunjucks-2": "^3.0.2",
       "koa-router": "^10.0.0",
       "mysql": "^2.18.1"
     }

test.js

        const Koa = require("koa")
        const Router = require("koa-router")
        const mysql = require("mysql")
        const koaNunjucks = require('koa-nunjucks-2');
        const path = require('path');

        const app = new Koa();
        const router = new Router();

        // mysqljs 连接 mysql数据库
        let connection = mysql.createConnection({
            host: '127.0.0.1', // mysql所在的主机,本地的话就是 127.0.0.1 或者 localhost, 如果数据库在服务器上,就写服务器的ip
            user: 'root', // mysql的用户名 默认root
            password: 'mysql密码', // mysql的密码
            database: 'db1' // 你要连接那个数据库
        })

        // 连接 mysql
        connection.connect(err=>{
            // err代表失败
            if(err) {
                console.log("数据库初始化失败");
            }else {
                console.log("数据库初始化成功");
            }
        })

        // 因为 mysqljs不支持 Promise方式CRUD数据
        // 所以我们做一个简单的封装
        function resDb(sql, params) {
            return new Promise((resolve,reject) => {
                let sqlParamsList = [sql]
                if(params) {
                    sqlParamsList.push(params)
                }
                connection.query(...sqlParamsList, (err,res) => {
                    if(err) {
                        reject(err)
                    }else {
                        resolve(res)
                    }
                })
            })
        }

         // 注入 nunjucks 模板引擎
         app.use(koaNunjucks({
            ext: 'html', // html文件的后缀名
            path: path.join(__dirname, 'views'), // 视图文件放在哪个文件夹下
            nunjucksConfig: {
              trimBlocks: true // 自动去除 block/tag 后面的换行符
            }
          }));

        //请求 /userAll 的时候返回数据
        router.get("/userAll", async ctx => {
            const userAll = await resDb("SELECT * FROM user")
            await ctx.render("table",{userAll})
        })

        //请求 /addUser 接受前端传过来的数据,并且把数据持久化到数据库中
        router.get("/addUser", async ctx => {
            const { name, age } = ctx.query
            // 判断 name 和 age是否有值,都有值时,数据存入数据库,刷新表格页面
            // 否则直接返回到表格页面
            if(name && age) {
            await resDb("INSERT INTO user values(null,?,?)",[name, age])
            }
            //重定向路由,到 userAll
            ctx.redirect("/userAll")
        })

        //请求 /updateUser 接受前端传过来的数据,并且把数据持久化到数据库中
        router.get("/updateUser", async ctx => {
            const { id, name, age } = ctx.query
            // 判断 id, name 和 age是否有值,都有值时,更新数据库中的数据,刷新表格页面
            // 否则直接返回到表格页面
            if(id, name && age) {
            await resDb("UPDATE user SET name=?, age=? WHERE id=?",[name, age, id])
            }
            //重定向路由,到 userAll
            ctx.redirect("/userAll")
        })

        //请求/delete/:id  接受前端传过来的数据,并且把对应的id的数据删掉
        router.get("/delete/:id", async ctx => {
            const { id } = ctx.params
            // 判断 id否有值,有值时,根据id删除数据库中的数据,刷新表格页面
            // 否则直接返回到表格页面
            if(id) {
            await resDb("DELETE FROM user WHERE id=?",[id])
            }
            //重定向路由,到 userAll
            ctx.redirect("/userAll")
        })

        //测试代码
        router.get("/hello", ctx => {
            ctx.body = "hello"
        })


        app
        .use(router.routes())
        .use(router.allowedMethods())
        .listen(3333,()=>{
            console.log("server running port:" + 3333);
        })

views/table.html

  <!DOCTYPE html>
      <html>

      <head>
          <meta charset="UTF-8">
          <meta http-equiv="X-UA-Compatible" content="IE=edge">
          <meta name="viewport" content="width=device-width, initial-scale=1.0">
          <title>Document</title>
          <style>
              .table {
                  width: 500px;
              }

              td {
                  text-align: center;
              }
          </style>
      </head>

          <body>
              <form action="/addUser" autocomplete="off">
                  <label for="name">
                      用户名:
                      <input type="text" name="name" placeholder="请输入用户名">
                  </label>
                  <label for="age">
                      年龄:
                      <input type="number" name="age" min="0" placeholder="请输入年龄">
                  </label>
                  <input type="submit" value="添加">
              </form>
              <form action="/updateUser" autocomplete="off">
                  <label for="id">
                      id:
                      <input type="number" name="id" placeholder="请输入要更新的ID">
                  </label>
                  <label for="name">
                      用户名:
                      <input type="text" name="name" placeholder="请输入用户名">
                  </label>
                  <label for="age">
                      年龄:
                      <input type="number" name="age" min="0" placeholder="请输入年龄">
                  </label>
                  <input type="submit" value="修改">
              </form>
              <table border="1" cellspacing="0">
                  <thead>
                      <tr>
                          <th>id</th>
                          <th>姓名</th>
                          <th>年龄</th>
                          <th>操作</th>
                      </tr>
                  </thead>
                  <tbody>
                      {% for user in userAll %}
                      <tr>
                          <td>{{user.id}}</td>
                          <td>{{user.NAME}}</td>
                          <td>{{user.age}}</td>
                          <td>
                              <a href={{'/delete/'+user.id}}>删除</a>
                          </td>
                      </tr>
                      {% endfor %}
                  </tbody>
              </table>
          </body>
      </html>

7、写在最后

当你看到这里的时候,首先你是个很有毅力的人,

赞(0)
未经允许不得转载:互联学术 » 怎么使用Nodejs连接Mysql,实现差不多的增删改查操作

评论 抢沙发