vue+Nodejs+Koa搭建前后端系统(五)--Nodejs中使用数据库

news2024/11/6 5:22:19

连接数据库

1.开启mysql服务

以管理员身份运行cmd,输入:

net start mysql

2.登录 root用户、创建新用户、赋予新用户权限

如果你用root用户作为node的连接用户,这一步可以略过。

(1)登录root:

mysql -u root -p

(2)创建新用户admin:

 CREATE USER 'admin'@'localhost' IDENTIFIED WITH mysql_native_password BY '611252';

其中,admin是用户名,611252是密码。

(3)赋予admin用户权限:

 GRANT all privileges ON xiaoyang.* TO 'admin'@'localhost';

xiaoyang.*表示 xiaoyang数据库下的所有表。

(4)刷新权限
对用户做了权限变更之后,一定记得重新加载一下权限,将权限信息从内存中写入数据库。

flush privileges;

3.在node项目中安装mysql插件

npm install mysql

mysql插件npm地址:点这里
在这里插入图片描述

4.在node项目的app.js文件中编写连接数据库代码

/**mysql连接 START*/
const mysql = require("mysql");
const connection = mysql.createConnection({
  host: "localhost",//数据库主机
  port: 4200,//数据库端口
  user: "admin",//用户名
  password: "611252",//密码
  database: "xiaoyang",//连接的数据库名
});
connection.connect(function (err) {
  if (err) {
    console.log(`mysql connnect error:${err.stack}`);
    return;
  }
  console.log(`mysql connected as id ${connection.threadId}`);
});
/**mysql连接 END*/

启动node项目,即可连接数据库了。

连接数据库遇到的问题

当你用root用户连接时,可能会遇到连接报错:

mysql connnect error:Error: ER_NOT_SUPPORTED_AUTH_MODE: Client does not support authentication protocol requested by server; consider upgrading MySQL client

在这里插入图片描述这是因为MySQL 8默认采用 caching_sha2_password 加密方式,而node的mysql模块并未完全支持MySQL 8支持该加密方式。
解决方式就是,修改root的密码并采用MySQL native password加密方式:

ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '611252';

在这里插入图片描述

如果要在创建新用户时使用MySQL native password加密方式,有两种方式:
一种方式是创建用户是时指明MySQL native password加密方式(前面用到的):

 CREATE USER 'admin'@'localhost' IDENTIFIED WITH mysql_native_password BY '611252';

另一种就是修改my.ini文件配置:
(1)在[mysqld]中添加默认验证方式

[mysqld]
default_authentication_plugin=mysql_native_password 

(2)重启mysql服务

net stop mysql & net start mysql

(3)登录mysql root用户
(4)创建新用户

 CREATE USER 'admin'@'localhost' IDENTIFIED BY '611252'

(5)赋予用户权限
(6)刷新权限

操作数据库

创建表

一般的WEB项目需求就是对数据库表的增删改查,所以首先需要手动创建一张表。
以用户表为例,创建create_user表,其中有id(用户id)、username(用户名)、password(用户密码)、create_time(创建时间)列。
创建新表有三种方式:

一种是在cmd终端登录mysql,然后在cmd中写sql语句:
1.登录mysql客户端

mysql -u admin -p

2.启用(xioayang)数据库

use xiaoyang

3.编写sql语句

CREATE TABLE
    IF NOT EXISTS create_user(
        id int NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT '用户id',
        username VARCHAR(20) COMMENT '用户名',
        password VARCHAR(32) COMMENT '用户密码',
        create_time TIMESTAMP NOT NULL COMMENT '创建时间'
    ) COMMENT '创建的用户表';

在这里插入图片描述

另一种创建一个sql文件,在文件中写sql语句,然后在终端执行该文件:

1.登录mysql客户端: 同上
2.启用(xioayang)数据库: 同上
3.新建一个sql文件: 我创建了createTable.sql文件,路径为F:\test\vue_node\hello-node\server2\mysql\createTable\createTable.sql
4.在sql文件中编写sql语句: 语句同上
5.在mysql客户端执行sql文件: source F:/test/vue_node/hello-node/server2/mysql/createTable/createTable.sql;

在这里插入图片描述
还有一种方式就是利用mysql可视化工具创建表,这里不做详细介绍,可自行百度。

将mysql操作对象加入ctx对象中

const mysql = require("mysql");
const connection = mysql.createConnection({
  host: "localhost",
  port: 4200,
  user: "root",
  password: "611252",
  database: "xiaoyang",
});
connection.connect(function (err) {
  if (err) {
    console.log(`mysql connnect error:${err.stack}`);
    return;
  }
  console.log(`mysql connected as id ${connection.threadId}`);
});
app.context.db = connection;

app.context 是 ctx对象 的原型。您可以通过编辑 app.context 为 ctx 添加其他属性。这对于将 ctx
添加到整个应用程序中使用的属性或方法非常有用,这可能会更加有效(不需要中间件)和/或 更简单(更少的
require()),而更多地依赖于ctx,这可以被认为是一种反模式。

然后我们就可以在router中使用db对象了:

const router = require("koa-router")();
router.post("/add", (ctx, next) => {
	const sql = `INSERT INTO create_user (username,password,create_time) value('xy','123456',CURRENT_TIMESTAMP())`;
	ctx.db.query(sql, (err, data) => {
      if (err) {
        console.error(`mysql ERROR:${err}`);
        return;
      }
      console.log(`mysql success!`);
    });
})

编写新增用户接口

在/routes/users.js中编写add路由,接口接收参数usernamepassword

const router = require("koa-router")();

router.post("/add", (ctx, next) => {
  return new Promise((res, rej) => {
    const params = ctx.request.body;
    const sql = `INSERT INTO create_user (username,password,create_time) value('${params.username}','${params.password}',CURRENT_TIMESTAMP())`;
    ctx.db.query(sql, (err, data) => {
      if (err) {
        console.error(`mysql ERROR:${err}`);
        ctx.body = "fail";
        rej();
        return;
      }
      ctx.body = "success";
      res();
    });
  });
});

注意,这里要用Promise,将其变为异步,否则ctx.body返回不了响应中,因为ctx.db.query是异步的。

在这里插入图片描述

前端vue请求新增用户

首先,需要查看前端请求的端口是否与node服务器的一致(vite.config.ts),然后在编写请求页面,我在APP.vue中:

<script setup lang="ts">
import axios from "axios";
import { ref } from "vue";
//post请求
function http(url: string, params = {}) {
  return new Promise((resolve, reject) => {
    axios
      .request({
        url: `/nodeApi/${url}`,
        timeout: 8000,
        headers: { "X-Custom-Header": "foobar" },
        method: "post",
        data: params,
      })
      .then((res: any) => {
        console.log(`${url}响应:`, res);
        resolve(res);
      })
      .catch((err) => {
        console.error(`${url}错误信息:`, err);
        reject(err);
      });
  });
}
function addUser() {
  const params = {
    username: username.value,
    password: password.value,
  };
  //这里有user前缀,是因为后端node处理过路由地址为route文件路径(前面文章提到过)
  http("users/add", params);
}
const username = ref("");
const password = ref("");
</script>

<template>
  <button @click="helloNode">hello-node</button>
  <button @click="goodbyeNode">goodbye-node</button>
  <lable>用户名:<input v-model="username" type="text" /></lable>
  <lable>密码:<input v-model="password" type="password" /></lable>
  <button @click="addUser">添加用户</button><br />
</template>

完善页面功能 – 增、删、改、查功能

新增用户功能已编写完成,下面我们把删、改、查功能写出来。直接贴代码

后端node代码(users.js页面):

const router = require("koa-router")();

//新增用户
router.post("/add", (ctx, next) => {
  return new Promise((res, rej) => {
    const params = ctx.request.body;
    const sql = `INSERT INTO create_user (username,password,create_time) value('${params.username}','${params.password}',CURRENT_TIMESTAMP())`;
    ctx.db.query(sql, (err, data) => {
      if (err) {
        console.error(`mysql ERROR:${err}`);
        ctx.body = "fail";
        rej();
        return;
      }
      ctx.body = "success";
      res();
    });
  });
});
//查看所有用户
router.post("/look", (ctx, next) => {
  return new Promise((res, rej) => {
    const sql = `SELECT * FROM create_user`;
    ctx.db.query(sql, (err, data) => {
      if (err) {
        console.error(`mysql ERROR:${err}`);
        ctx.body = "fail";
        rej();
        return;
      }
      ctx.body = data;
      res();
    });
  });
});
//删除用户
router.post("/del", (ctx, next) => {
  return new Promise((res, rej) => {
    const params = ctx.request.body;
    const sql = `DELETE FROM create_user WHERE id=${params.id}`;
    ctx.db.query(sql, (err, data) => {
      if (err) {
        console.error(`mysql ERROR:${err}`);
        ctx.body = "fail";
        rej();
        return;
      }
      ctx.body = "success";
      res();
    });
  });
});
//修改用户密码
router.post("/update", (ctx, next) => {
  return new Promise((res, rej) => {
    const params = ctx.request.body;
    const sql = `UPDATE create_user SET password='${params.password}' WHERE id=${params.id}`;
    ctx.db.query(sql, (err, data) => {
      if (err) {
        console.error(`mysql ERROR:${err}`);
        ctx.body = "fail";
        rej();
        return;
      }
      ctx.body = "success";
      res();
    });
  });
});

前端VUE代码(App.vue页面):

<script setup lang="ts">
import axios from "axios";
import { ref } from "vue";
//post请求
function http(url: string, params = {}) {
  return new Promise((resolve, reject) => {
    axios
      .request({
        url: `/nodeApi/${url}`,
        timeout: 8000,
        headers: { "X-Custom-Header": "foobar" },
        method: "post",
        data: params,
      })
      .then((res: any) => {
        console.log(`${url}响应:`, res);
        resolve(res);
      })
      .catch((err) => {
        console.error(`${url}错误信息:`, err);
        reject(err);
      });
  });
}
//新增用户
function addUser() {
  const params = {
    username: username.value,
    password: password.value,
  };
  http("users/add", params).then((res) => lookUser());
}
//查看所有用户
function lookUser() {
  const params = {};
  http("users/look", params).then((data: any) => (list.value = data.data));
}
//删除用户
function delUser(id: number) {
  const params = { id: id };
  http("users/del", params).then((data: any) => lookUser());
}
//修改用户密码
function updateUser(id: number) {
  const password = prompt("修改密码", "请输入新密码");
  const params = { id: id, password: password };
  http("users/update", params).then((data: any) => lookUser());
}
const username = ref("");
const password = ref("");
const list = ref<any[]>([]);
lookUser();
</script>

<template>
  <lable>用户名:<input v-model="username" type="text" /></lable>
  <lable>密码:<input v-model="password" type="password" /></lable>
  <button @click="addUser">添加用户</button><br />
  <table>
    <thead>
      <tr>
        <td>用户名</td>
        <td>密码</td>
        <td>创建时间</td>
        <td>操作</td>
      </tr>
    </thead>
    <tbody>
      <tr v-for="i in list" :key="i.id">
        <td>{{ i.username }}</td>
        <td>{{ i.password }}</td>
        <td>{{ i.create_time }}</td>
        <td>
          <button @click="updateUser(i.id)">修改密码</button>
          <button @click="delUser(i.id)">删除</button>
        </td>
      </tr>
    </tbody>
  </table>
</template>

以上代码只是用来演示,并未添加任何限制。

一些代码优化

先只关注node代码的优化。

1.连接数据库,集合!

可以将数据库的一些相关代码封装到插件中,首先就是数据库连接,在 /plugins/ 目录下新建mysql.js文件:

const mysql = require("mysql");
const defaulOpts = {
  host: "localhost",
  port: 4200,
  user: "admin",
  password: "611252",
  database: "xiaoyang",
};
function connection(app, myOpts = {}) {
  const opts = {};
  Object.assign(opts, defaulOpts, myOpts);
  const conn = mysql.createConnection(opts);
  conn.connect(function (err) {
    if (err) {
      console.log(`mysql connnect error:${err.stack}`);
      return;
    }
    console.log(`mysql connected as id ${conn.threadId}`);
  });
  app.context.db = conn;
}

module.exports = {
  connection,
};

在app.js中引入即可:

const Koa = require("koa");
const app = new Koa();
const { connection } = require("./plugins/mysql.js");
//连接数据库
connection(app);

2.优雅的操作数据库

由于ctx.db.query是异步,导致上面增删改查接口中,每个都要用Promise包裹,有些麻烦,可不可以让代码更优雅一些。

解决办法是:可以将ctx.db.query封装起来:
将代码封装在 /plugins/mysql.js 插件中:

const mysql = require("mysql");

function connection(app, myOpts = {}) {
  /**此处代码省略*/
}
//封装ctx.db.query为异步
function query(ctx, sql) {
  return new Promise((res, rej) => {
    ctx.db.query(sql, (err, data) => {
      if (err) {
        rej({ err });
        return;
      }
      res({ data });
    });
  });
}
module.exports = {
  connection,
  query
};
const router = require("koa-router")();
const {query} = require("../plugins/mysql.js");

//查看所有用户
router.post("/look", async (ctx, next) => {
  const sql = `SELECT * FROM create_user`;
  const r = await query(ctx, sql);
  if (r.err) {
    ctx.body = "fail";
    return;
  }
  ctx.body = r.data;
});

还有一种办法就是借助别人的力量co-mysql

npm i co-mysql

/plugins/mysql.js 文件代码:

const mysql = require("mysql");
const co = require("co-mysql");

const defaulOpts = {
  host: "localhost",
  port: 4200,
  user: "admin",
  password: "611252",
  database: "xiaoyang",
};
function connection(app, myOpts = {}) {
  const opts = {};
  Object.assign(opts, defaulOpts, myOpts);
  const conn = mysql.createConnection(opts);
  conn.connect(function (err) {
    if (err) {
      console.log(`mysql connnect error:${err.stack}`);
      return;
    }
    console.log(`mysql connected as id ${conn.threadId}`);
  });
  app.context.db = co(conn);
}

module.exports = {
  connection,
};

然后在 /routes/users.js 文件中:

const router = require("koa-router")();

router.post("/look", async (ctx, next) => {
  const sql = `SELECT * FROM create_user`;
  try {
    ctx.body = await ctx.db.query(sql);
  } catch (e) {
    ctx.body = "fail";
  }
  /**
  或者也可以这样使用
  ctx.db.query(sql).then(res=>ctx.body=res).catch(e=>ctx.body="fail")
  */
});
router.post("/del", async (ctx, next) => {
  const params = ctx.request.body;
  const sql = `DELETE FROM create_user WHERE id=${params.id}`;
  try {
    await ctx.db.query(sql);
    ctx.body = "success";
  } catch (e) {
    ctx.body = "fail";
  }
});

3.路由你能不能简单点

想把路由配置页的书写格式变成像填写配置项那样(参考vue-router)。比如 /routes/user.js 可以写成这样:

module.exports = [
  {
    url: "/add",
    methods: "post",
    actions: async (ctx, next) => {
      const params = ctx.request.body;
      const sql = `INSERT INTO create_user (username,password,create_time) value('${params.username}','${params.password}',CURRENT_TIMESTAMP())`;
      try {
        await ctx.db.query(sql);
        ctx.body = "success";
      } catch (e) {
        ctx.body = "fail";
      }
    },
  },
  {
    url: "/look",
    methods: "post",
    actions: async (ctx, next) => {
      const sql = `SELECT * FROM create_user`;
      try {
        ctx.body = await ctx.db.query(sql);
      } catch (e) {
        ctx.body = "fail";
      }
    },
  },
  {
    url: "/del",
    methods: "post",
    actions: async (ctx, next) => {
      const params = ctx.request.body;
      const sql = `DELETE FROM create_user WHERE id=${params.id}`;
      try {
        await ctx.db.query(sql);
        ctx.body = "success";
      } catch (e) {
        ctx.body = "fail";
      }
    },
  },
  {
    url: "/update",
    methods: "post",
    actions: async (ctx, next) => {
      const params = ctx.request.body;
      const sql = `UPDATE create_user SET password='${params.password}' WHERE id=${params.id}`;
      try {
        await ctx.db.query(sql);
        ctx.body = "success";
      } catch (e) {
        ctx.body = "fail";
      }
    },
  },
];

要想实现这样的写法,只需要修改 /plugins/loadRoutes.js 一点点代码:

const fs = require("fs");
const path = require("path");
const defaultOptions = {
  extname: [".js"],
  root: "routes/",
  prefixIgnore: ["main.js"],
};
const routesDir = path.resolve(defaultOptions.root);
function loadRoutes(app, dirPath) {
  fs.readdir(dirPath, { withFileTypes: true }, function (err, files) {
    if (err) {
      console.warn(err, "读取文件夹错误!");
    } else {
      files.forEach(function (dirent) {
        const currentPath = path.join(dirPath, dirent.name);
        if (dirent.isDirectory()) {
          loadRoutes(app, currentPath);
        } else if (dirent.isFile()) {
          const relativePath = path.relative(__dirname, currentPath);
          const extname = path.extname(relativePath);
          if (defaultOptions.extname.includes(extname)) {
          
          	/** delete */
            // const router = require(relativePath);
            /** delete */
            
            /**new */
            const routes = require(relativePath);
            let router = null;
            if (Array.isArray(routes)) {
              //新写法
              router = require("koa-router")();
              routes.forEach((item) => {
                router[item.methods](item.url, item.actions);
              });
            } else {
              //原写法
              router = require(relativePath);
            }
            /**new */

            const extnameReg = new RegExp(defaultOptions.extname.join("|"));
            const prefixIgnore = defaultOptions.prefixIgnore.some((s) => {
              const ignoeSrc = path.resolve(defaultOptions.root, s);
              return currentPath.indexOf(ignoeSrc) === 0;
            });
            if (!prefixIgnore) {
              const routerNamespace = path
                .relative(routesDir, currentPath)
                /**new (将反斜杠处理成斜杠) */
                .replace(/\\/gim, "/")
                /**new */
                .replace(extnameReg, "");
              router.prefix("/" + routerNamespace);
            }
            app.use(router.routes(), router.allowedMethods());
          }
        }
      });
    }
  });
}

module.exports = function (app, opt = {}) {
  Object.assign(defaultOptions, opt);
  loadRoutes(app, routesDir);
};

上面代码中/**new */表示在原代码上新增的代码,/** delete */ 表示删除的原代码。上述修改使路由的页面兼容以前写法。

如果你没有看过《vue+Nodejs+Koa搭建前后端系统(三)–koa-generator项目优化修改》,你需要检查app.js中是否加载了全部路由:

const load = require("./plugins/loadRoutes.js");
//加载全部路由
load(app);

4.路由和mysql你们不能在一起

现在,路由页面还是不够清爽,因为接口逻辑api也写在了路由配置页面中。我需要将其分离。
首先在项目根目录下新建一个module目录,用来存放各个模块的api。然后路由需要哪个api引入就行。

让我们分离一下 /routes/user.js 中的增删改查接口:
新建 /module/user.js ,将逻辑api放入该文件:

//新增用户
async function addUser(ctx, next) {
  const params = ctx.request.body;
  const sql = `INSERT INTO create_user (username,password,create_time) value('${params.username}','${params.password}',CURRENT_TIMESTAMP())`;
  try {
    await ctx.db.query(sql);
    ctx.body = "success";
  } catch (e) {
    ctx.body = "fail";
  }
}
//查看所有用户
async function lookUser(ctx, next) {
  const sql = `SELECT * FROM create_user`;
  try {
    ctx.body = await ctx.db.query(sql);
  } catch (e) {
    ctx.body = "fail";
  }
}
//更新用户密码
async function updateUserPassword(ctx, next) {
  const params = ctx.request.body;
  const sql = `UPDATE create_user SET password='${params.password}' WHERE id=${params.id}`;
  try {
    await ctx.db.query(sql);
    ctx.body = "success";
  } catch (e) {
    ctx.body = "fail";
  }
}
//删除用户
async function delUser(ctx, next) {
  const params = ctx.request.body;
  const sql = `DELETE FROM create_user WHERE id=${params.id}`;
  try {
    await ctx.db.query(sql);
    ctx.body = "success";
  } catch (e) {
    ctx.body = "fail";
  }
}
module.exports = {
  addUser,
  lookUser,
  updateUserPassword,
  delUser,
};

/routes/user.js中引入api:

const {
  addUser,
  lookUser,
  updateUserPassword,
  delUser,
} = require("../module/user");
module.exports = [
  {
    url: "/add",
    methods: "post",
    actions: addUser,
  },
  {
    url: "/look",
    methods: "post",
    actions: lookUser,
  },
  {
    url: "/del",
    methods: "post",
    actions: delUser,
  },
  {
    url: "/update",
    methods: "post",
    actions: updateUserPassword,
  },
];

在这里插入图片描述建议module目录中的文件结构和routes目录中的一致,这样查找方便。

保持数据库连接

mysql在8个小时内没有任何操作,就会自动中断连接
因此,可以每三个小时ping一次数据库,保持数据库连接状态。

修改 /plugin/mysql.js 中的代码:

const mysql = require("mysql");
const co = require("co-mysql");

var pingInterval = null;
const defaulOpts = {
  host: "localhost",
  port: 4200,
  user: "admin",
  password: "611252",
  database: "xiaoyang",
};
function connection(app, myOpts = {}) {
  const opts = {};
  Object.assign(opts, defaulOpts, myOpts);
  const conn = mysql.createConnection(opts);
  conn.connect(function (err) {
    if (err) {
      console.log(`mysql connnect error:${err.stack}`);
      return;
    }
    console.log(`mysql connected as id ${conn.threadId}`);
  });
  //数据库失去连接则重启连接
  conn.on("error", function (err) {
    if (err.code === "PROTOCOL_CONNECTION_LOST") {
      connection(app, myOpts);
    } else {
      throw err;
    }
  });
  // 每隔3小时ping一次数据库,保持数据库连接状态
  clearInterval(pingInterval);
  pingInterval = setInterval(() => {
    conn.ping((err) => {
      if (err) {
        console.log("ping error: " + JSON.stringify(err));
      }
    });
  }, 3600000 * 3);

  app.context.db = co(conn);
}

module.exports = {
  connection,
};

参考资料:
知乎:node+koa+mysql开发
简书:koa 连接数据库
简书:操作mysql数据库 中间件 mysql、co-msql
解决node连接数据库频繁关闭问题
CSDN:nodejs连接mysql突然中断问题解决方案
CSDN:nodejs连接mysql报错Error: ER_NOT_SUPPORTED_AUTH_MODE: Client does not support authentication protocol re
CSDN:mysql创建新用户并授权

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/508710.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

多功能文档应用程序Codex Docs

什么是 Codex Docs &#xff1f; CodeX Docs 是一个简单的免费应用程序&#xff0c;适用于您的内部、公共或个人文档。它基于Editor.js&#xff0c;允许使用漂亮干净的 UI 处理内容。 官方提供了演示站点&#xff1a;https://docs-demo.codex.so/about-this-demo 安装 在群晖…

CIAA 网络安全模型 — 数据传输安全

目录 文章目录 目录网络传输 CIAA 安全模型机密性&#xff08;Confidentiality&#xff09;对称加密非对称加密混合加密 完整性&#xff08;Integrity&#xff09;L2 数据链路层的 CRC 强校验L3 网络层的 Checksum 弱校验L4 传输层的 Checksum 弱校验安全层的 Checksum 强校验 …

解决:component COMDLG32.OCX or one of…和 MSCOMCTL.OCX or one of...的解决方法

遇到的问题&#xff1a; 在做CTF题目 使用16进制转图片工具 出现了两个报错&#xff01; 解决方法&#xff1a; 第一步&#xff1a;下载COMDLG32.OCX 程序&#xff08;可以去官网&#xff09;也可也使用我的百度网盘 http://链接&#xff1a;https://pan.baidu.com/s/1-1KNg…

本地部署 闻达:一个LLM调用平台

本地部署 闻达&#xff1a;一个LLM调用平台 1. 什么是 闻达2. Github 地址3. 安装 Miniconda34. 创建虚拟环境5. 安装 闻达6. 下载各个 model7. 配置各个 model8. 使用 RWKV-4-Raven-14B-v11x 启动9. 使用 chatglm-6b-int4 启动10. 使用 stable-vicuna-13B 启动11. 使用 moss-m…

SpringFramework

&#x1f3e1;个人主页 &#xff1a; 守夜人st &#x1f680;系列专栏&#xff1a;Spring …持续更新中敬请关注… &#x1f649;博主简介&#xff1a;软件工程专业&#xff0c;在校学生&#xff0c;写博客是为了总结回顾一些所学知识点 目录 Springspring概述1 Spring定义2 Sp…

我的创作纪念日(2)设置飞机进行调优

文章目录 前言 2.1 电池设置 2.2 电机设置 2.3 PID控制器初始设置 前言 以下参数应根据你的飞机的规格正确设置。每一个都会影响调优过程的质量。 2.1 电池设置 确保你的 VTOL 电机的推力曲线尽可能的线性是非常重要的。一个线性的推力曲线意味着电机产生的实际推力的变化…

GuassDB数据库的GRANT REVOKE

目录 一、GaussDB的权限概述 二、GaussDB权限设计建议 三、GaussDB的GRANT命令 1.功能说明 2.注意事项 3.常用语法 四、GaussDB的REVOKE命令用法 1.功能说明 2.注意事项 3.常用语法 五、GaussDB示例 1.GRANT 语句示例 2.REVOKE 语句示例 一、GaussDB的权限概述 在…

电气设备绝缘在线监测系统的原理

摘要&#xff1a;在线监测是控制好电气设备绝缘的重要方式&#xff0c;为电力系统稳定奠定重要基础。在线监测电气设备时&#xff0c;要利用检测技术促进电力系统运行效率提升&#xff0c;让电气设备在具体工作过程中发挥更大作用。本次研究中主要分析了电气设备绝缘在线监测系…

单开网页应用利器 - BroadcastChannel

前言 前段时间在做一个基于 psd 模板生成图片的应用&#xff0c;其中重要的功能就是打开编辑器页面来设计出图。但是有个问题&#xff0c;每当我点击一个模板&#xff0c;就会新开一个浏览器页签。现代浏览器是以空间换时间的运行思路来提高效率&#xff0c;这就导致了内存开销…

单片机c51中断 — 中断键控流水灯

项目文件 文件 关于项目的内容知识点可以见专栏单片机原理及应用 的第五章&#xff0c;中断 在第4章的实例2中&#xff0c;按键检测是采用查询法进行的&#xff0c;其流程图如图所示 问题是这样的&#xff1a;由于查询法 -按键查询、标志位修改及彩灯循环几个环节是串联关系…

微信小程序从入门到精通

目录 前言一&#xff0c;初学小程序1.1 小程序概述1.2 基础配置1.2.1 注册开发账号1.2.2 获取AppID1.2.3 微信开发者工具1.2.4 修改代理模式 1.3 第一个小程序1.4 开发文档1.5 机型1.6 项目基本结构1.6.1 页面内部文件1.6.2 app.json1.6.3 project.config.json1.6.4 sitemap.js…

开关电源基础07:离线式开关电源变压器设计(1)

说在开头&#xff1a;关于第六届索尔维会议&#xff08;2&#xff09; 爱因斯坦一天都挺开心的&#xff0c;反正难题出给了玻尔&#xff0c;他还在自己的房间里拉起了小提琴&#xff0c;有人说爱因斯坦小提琴拉的跟锯木头一样&#xff0c;那也不至于那么夸张&#xff0c;但是水…

RK3568平台开发系列讲解(Linux内存篇)Linux内存管理框架

🚀返回专栏总目录 文章目录 一、内核态内存分配二、用户态内存分配三、内存篇章更新哪些内容沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇我们一起将整个内存管理的体系串起来。 对于内存的分配需求,可能来自内核态,也可能来自用户态。 一、内核态内存分配…

Spring Boot集成ShardingSphere实现读写分离 | Spring Cloud 43

一、读写分离 1.1 背景 面对日益增加的系统访问量&#xff0c;数据库的吞吐量面临着巨大瓶颈。 对于同一时刻有大量并发读操作和较少写操作类型的应用系统来说&#xff0c;将数据库拆分为主库和从库&#xff0c;主库负责处理事务性的增删改操作&#xff0c;从库负责处理查询操…

NetApp 利用适用于混合云的实时解决方案解决芯片设计方面的数据管理挑战

电子设计自动化 (EDA) 成本持续增加&#xff0c;而周期时间缩短。这些都为 EDA 设计带来了前所未有的挑战&#xff0c;对现代高性能工作流的需求变得从未如此巨大。 联想凌拓芯片设计行业存储解决方案及最佳实践 联想凌拓芯片行业数据存储与管理解决方案&#xff0c;针对EDA…

驱动设计的思想:面向对象/分层/分离(以LED操作为例)

1. 面向对象 字符设备驱动程序抽象出一个file_operations结构体&#xff1b; 对于LED&#xff0c;写的程序针对硬件部分抽象出led_operations结构体。 2. 分层 上下分层&#xff0c;之前写的LED驱动程序就分为2层&#xff1a; ① 上层实现硬件无关的操作&#xff0c;比如注册…

一文搞懂——MySQL索引事务JDBC

目录 一、索引 1.1 索引是什么&#xff1f; 1.2 怎样创建索引&#xff1f; 1.3 索引使用的数据结构是什么&#xff1f; 1.4 索引相关的概念 1.5 索引失效的原因 二、事务 2.1 事务是什么&#xff1f; 2.2 为什么要使用事务&#xff1f; 2.3 事务的使用 2.4 事务的特性…

黑马头条(学习笔记)

​ 目录 一. 项目概述 二、项目初始化 移动端 REM 适配&#xff1a; 关于 PostCSS 配置文件&#xff1a; Autoprefixer 插件的配置 &#xff1a; postcss-pxtorem 插件的配置&#xff1a; 关于字体图标: 配置路由&#xff1a; 封装请求模块: 三&#xff1a;登录注册&…

ChatGPT有话说:虚拟现实 VS 增强现实

以下内容均为ChatGPT根据用户引导和提示作出的阐述和说明。 一、引言 虚拟现实和增强现实是当前最受瞩目的创新技术。虚拟现实是指利用计算机生成的虚拟环境&#xff0c;用户可以通过佩戴VR头戴式显示器等设备完全沉浸在其中&#xff0c;感受到身临其境的感觉。而增强现实则是…

三分钟上手安全渗透系统Kali Linux

kali linux系统集成了常用的安全渗透工具&#xff0c;省去了安装工具的时间&#xff0c;做安全相关的工作是非常推荐使用的。 安装Kalii Linux 安装系统 一般使用虚拟机进行安装&#xff0c;Kali Linux基于Debian内核&#xff0c;虚拟机的操作系统选择Debian 7.x 64 选择系统…