谷粒商城实战笔记-55-商品服务-API-三级分类-修改-拖拽数据收集
文章目录
- 一,拖拽后结点的parentCid的更新
- 二,拖拽后结点的父节点下所有结点的sort排序属性的变化
- 更新排序的逻辑
- 代码分析
- 三,拖拽后结点及其子节点catLevel的变化
- 判断是否需要更新 `catLevel`
- 获取拖动后的新节点
- 更新 `catLevel`
- 完整代码
这一节的主要内容是收集拖拽后的要更新的节点的数据,逻辑比较复杂。
- 1,拖拽后结点的parentCid的更新;
- 2,拖拽后结点的父节点下所有结点的sort排序属性的变化;
- 3,拖拽后结点及其子节点catLevel的变化;
所有这些数据都用收集到,然后发送给后台更新。
拖拽结束后,触发拖拽结束事件,所以要在el-tree上绑定这个事件。
事件函数nodeDrop定义如下。
然后定义一个全局数组,用来收集需要更新的节点数据。
一,拖拽后结点的parentCid的更新
var draggingNodeNewPId = 0;// 1,更新draggingNode的parentCid,根据dropPosition的不同值,分为两种情况if (dropPosition === "before" || dropPosition === "after") {draggingNodeNewPId = dropNode.data.parentCid;} else {draggingNodeNewPId = dropNode.data.cid;}
这段代码是在处理 el-tree
组件中拖拽结束后的逻辑,特别是更新被拖动节点的 parentCid
字段,以反映新的父节点关系。parentCid
假设是数据库中用来标识父节点的一个字段,通常在树形结构的数据模型中使用。
代码中的逻辑分为两种情况:
-
当拖动节点放置在目标节点之前 (
prev
) 或之后 (next
):if (dropPosition === "prev" || dropPosition === "next") {draggingNode.parentCid = dropNode.data.parentCid; }
在这种情况下,拖动的节点将变为与目标节点同级,但它们共同的父节点会成为新的父节点。因此,
draggingNode
的parentCid
被设置为dropNode.data.parentCid
,即目标节点的父节点ID。这种写法还兼容了没有父节点的情况,没有父节点时,parentCid为0。 -
当拖动节点放置在目标节点内部 (
inner
):else if (dropPosition === "inner") {draggingNode.parentCid = dropNode.data.cid; }
如果拖动的节点被放置在目标节点内部,那么它将成为目标节点的子节点。因此,
draggingNode
的parentCid
被设置为dropNode.data.cid
,即目标节点自身的ID。
这段代码确保了在拖拽结束后,树形结构在逻辑上保持一致,parentCid
的更新反映了新的父子关系。这在维护树形数据结构的完整性方面非常重要,特别是在需要同步这些变化到后端数据库的场景下。
二,拖拽后结点的父节点下所有结点的sort排序属性的变化
// 2,更新draggingNode及其子节点的sort// 2.1如果draggingNode的parentCid没有更新,只需要重排draggingNode的兄弟结点的sort;// 2.2如果draggingNode的parentCid有更新,不仅需要重排draggingNode的原来的兄弟结点的sort,还需要重排draggingNode新的兄弟结点的sortvar siblingNodesOld = [];var siblingNodesNew = [];// draggingNode.parent为空,所以要根据parentCid找到其parent。// 写一个根据cid从menus中查询结点的函数let draggingNodeOldParentNode = this.getNodeByCid(draggingNode.data.parentCid, this.getLevel1Nodes(dropNode));console.log("draggingNodeOldParentNode:", draggingNodeOldParentNode);siblingNodesOld = draggingNodeOldParentNode.childNodes;;console.log("siblingNodesOld:", siblingNodesOld);if (draggingNode.data.parentCid !== draggingNodeNewPId) {if (dropPosition === "before" || dropPosition === "after") {siblingNodesNew = dropNode.parent.childNodes;} else {siblingNodesNew = dropNode.childNodes;}}for (var i = 0; i < siblingNodesOld.length; i++) {this.nodesInfoAfterDrop.push({catId: siblingNodesOld[i].data.catId, sort: i});}console.log("update sortu0....", siblingNodesNew, siblingNodesOld, dropNode, dropPosition);for (var i = 0; i < siblingNodesNew.length; i++) {this.nodesInfoAfterDrop.push({catId: siblingNodesNew[i].data.catId, sort: i});}console.log("update sort....", siblingNodesNew, siblingNodesOld, dropNode, dropPosition);
这段代码涉及到了在 el-tree
拖拽操作后更新节点排序(sort
属性)的逻辑,以便反映节点在树结构中的新位置。这里主要关注两个方面:更新拖动节点 draggingNode
及其子节点的排序,以及根据 draggingNode
的父节点是否改变来决定哪些节点的排序需要被更新。
更新排序的逻辑
-
确定旧的和新的兄弟节点集合:
siblingNodesOld
是拖动前draggingNode
的兄弟节点集合,即它原本的同级节点。siblingNodesNew
是拖动后draggingNode
的兄弟节点集合,这取决于拖动的目标位置(放置在目标节点之前、之后还是内部)。
-
判断是否需要更新新的兄弟节点集合:
- 如果
draggingNode
的父节点ID(parentCid
)没有改变,意味着拖动只改变了顺序而没有改变层级,此时只需要更新旧的兄弟节点集合的排序。 - 如果
draggingNode
的父节点ID改变了,意味着节点的层级发生了变化,此时需要更新旧的和新的兄弟节点集合的排序。
- 如果
-
更新兄弟节点的排序:
- 遍历
siblingNodesOld
和siblingNodesNew
集合,将每个节点的sort
属性设置为其在集合中的索引。这是因为索引反映了节点在数组中的位置,可以作为排序的依据。
- 遍历
代码分析
-
在
siblingNodesNew
的赋值中,对于放置在目标节点之前或之后的情况,代码似乎直接将dropNode.data.parentCid
赋值给了siblingNodesNew
,但实际上dropNode.data.parentCid
不应直接作为节点集合,这看起来像是一个错误或代码片段的不完整展示。正确的做法应该是获取dropNode
的父节点的子节点集合。 -
对于放置在目标节点内部的情况,代码正确地从
dropNode
的父节点获取了子节点集合。
三,拖拽后结点及其子节点catLevel的变化
// 3,更新draggingNode及其子节点的catLevelvar catLevelNeedUpdate = true;if (draggingNode.data.catLevel === dropNode.data.catLevel && (dropPosition === "before" || dropPosition === "after")) {catLevelNeedUpdate = false;}var draggingNodeAfterDrop = {};if (catLevelNeedUpdate) {var draggingParentNodeAfterDrop = {};if (dropPosition === "before" || dropPosition === "after") {draggingParentNodeAfterDrop = dropNode.parent;} else {draggingParentNodeAfterDrop = dropNode;}draggingParentNodeAfterDrop.childNodes.forEach((child) => {if (child.cid === draggingNode.data.cid) {draggingNodeAfterDrop = child;}})// 递归变量draggingNodeAfterDrop及其childNodes,将其data属性的cateLevel置为level属性值this.updateCatLevel(draggingNodeAfterDrop);}
updateCatLevel的定义如下:
// 递归更新draggingNode及其子节点的catLevel
updateCatLevel(node) {node.catLevel = node.level;if (node.childNodes && node.childNodes.length > 0) {node.childNodes.forEach((child) => {this.updateCatLevel(child);});}
},
这段代码的主要作用是,在 el-tree
组件的拖拽操作完成后,更新拖动节点 draggingNode
及其所有子节点的 catLevel
属性,以反映新的层级关系。catLevel
通常用于表示节点在树结构中的层级深度,这对于保持树结构的一致性和完整性是非常重要的。
判断是否需要更新 catLevel
首先,代码检查是否需要更新 catLevel
:
var catLevelNeedUpdate = true;
if (draggingNode.data.catLevel === dropNode.data.catLevel && (dropPosition === "prev" || dropPosition === "next")) {catLevelNeedUpdate = false;
}
如果拖动节点和目标节点的层级相同,并且拖动位置是目标节点的前后,那么 catLevel
不需要更新,因为拖动操作不会改变节点的层级深度。
获取拖动后的新节点
接下来,代码尝试获取拖动操作完成后的拖动节点 draggingNodeAfterDrop
,这通常是通过查找父节点的子节点列表来完成的:
var draggingNodeAfterDrop = {};
if (catLevelNeedUpdate) {var draggingParentNodeAfterDrop = {};if (dropPosition === "prev" || dropPosition === "next") {draggingParentNodeAfterDrop = dropNode.parent;} else {draggingParentNodeAfterDrop = dropNode;}draggingParentNodeAfterDrop.childNodes.forEach((child) => {if (child.cid === draggingNode.data.cid) {draggingNodeAfterDrop = child;}})
}
这里,draggingParentNodeAfterDrop
根据拖动位置确定,然后遍历其子节点找到具有相同 cid
的节点,即拖动后的拖动节点。
更新 catLevel
最后,如果需要更新 catLevel
,调用 updateCatLevel
方法来递归更新拖动节点及其所有子节点的 catLevel
:
this.updateCatLevel(draggingNodeAfterDrop, dropNode.data.catLevel + deep);
updateCatLevel
方法如下:
// 递归更新draggingNode及其子节点的catLevelupdateCatLevel(node) {if (!node) {return;}this.nodesInfoAfterDrop.push({catId: node.data.catId, catLevel: node.level});if (node.childNodes && node.childNodes.length > 0) {node.childNodes.forEach((child) => {this.updateCatLevel(child);});}},
在这个方法中,node.catLevel
被设置为 node.level
,后者通常反映了节点的实际层级深度。如果节点有子节点,递归地调用 updateCatLevel
方法来更新所有子节点的 catLevel
。
完整代码
<template><div><el-treenode-key="catId":data="menus":props="defaultProps":expand-on-click-node="false"show-checkbox:default-expanded-keys="expandedKeys":allow-drop="allowDrag"@node-drop="nodeDrop"draggable><span class="custom-tree-node" slot-scope="{ node, data }"><span>{{ node.label }}</span><span><el-buttonv-if="node.level <= 2"size="mini"@click="() => append(data)">Append</el-button><el-button size="mini" @click="() => edit(data)"> Edit </el-button><el-buttonv-if="node.childNodes.length == 0"type="text"size="mini"@click="() => remove(node, data)">Delete</el-button></span></span></el-tree><el-dialog:title="dialogTitle":visible.sync="dialogFormVisible":close-on-click-modal="false"><el-form :model="category"><el-form-item label="分类名称"><el-input v-model="category.name" autocomplete="off"></el-input></el-form-item><el-form-item label="图标"><el-input v-model="category.icon" autocomplete="off"></el-input></el-form-item><el-form-item label="计量单位"><el-inputv-model="category.productUnit"autocomplete="off"></el-input></el-form-item></el-form><div slot="footer" class="dialog-footer"><el-button @click="dialogFormVisible = false">取 消</el-button><el-button type="primary" @click="submitCategory">确 定</el-button></div></el-dialog></div>
</template><script>
export default {components: {},props: {},data() {return {nodesInfoAfterDrop: [],dialogTitle: "", // 编辑窗口标题,新增分类,修改分类dialogType: "", // 编辑窗口类型,create表示append,edit表示editdialogFormVisible: false,menus: [],category: {name: "",parentCid: 0,catLevel: 0,sort: 0,showStatus: 1,icon: "",productUnit: "",catId: null,},expandedKeys: [],defaultProps: {children: "children",label: "name",},};},methods: {nodeDrop(draggingNode, dropNode, dropPosition) {console.log("draggingNode:", draggingNode, dropNode, dropPosition);var draggingNodeNewPId = 0;// 1,更新draggingNode的parentCid,根据dropPosition的不同值,分为两种情况if (dropPosition === "before" || dropPosition === "after") {draggingNodeNewPId = dropNode.data.parentCid;} else {draggingNodeNewPId = dropNode.data.cid;}// 2,更新draggingNode及其子节点的sort// 2.1如果draggingNode的parentCid没有更新,只需要重排draggingNode的兄弟结点的sort;// 2.2如果draggingNode的parentCid有更新,不仅需要重排draggingNode的原来的兄弟结点的sort,还需要重排draggingNode新的兄弟结点的sortvar siblingNodesOld = [];var siblingNodesNew = [];// draggingNode.parent为空,所以要根据parentCid找到其parent。// 写一个根据cid从menus中查询结点的函数let draggingNodeOldParentNode = this.getNodeByCid(draggingNode.data.parentCid, this.getLevel1Nodes(dropNode));console.log("draggingNodeOldParentNode:", draggingNodeOldParentNode);siblingNodesOld = draggingNodeOldParentNode.childNodes;;console.log("siblingNodesOld:", siblingNodesOld);if (draggingNode.data.parentCid !== draggingNodeNewPId) {if (dropPosition === "before" || dropPosition === "after") {siblingNodesNew = dropNode.parent.childNodes;} else {siblingNodesNew = dropNode.childNodes;}}for (var i = 0; i < siblingNodesOld.length; i++) {this.nodesInfoAfterDrop.push({catId: siblingNodesOld[i].data.catId, sort: i});}console.log("update sortu0....", siblingNodesNew, siblingNodesOld, dropNode, dropPosition);for (var i = 0; i < siblingNodesNew.length; i++) {this.nodesInfoAfterDrop.push({catId: siblingNodesNew[i].data.catId, sort: i});}console.log("update sort....", siblingNodesNew, siblingNodesOld, dropNode, dropPosition);// 3,更新draggingNode及其子节点的catLevelvar catLevelNeedUpdate = true;if (draggingNode.data.catLevel === dropNode.data.catLevel && (dropPosition === "before" || dropPosition === "after")) {catLevelNeedUpdate = false;}var draggingNodeAfterDrop = null;if (catLevelNeedUpdate) {var draggingParentNodeAfterDrop = {};if (dropPosition === "before" || dropPosition === "after") {draggingParentNodeAfterDrop = dropNode.parent;} else {draggingParentNodeAfterDrop = dropNode;}draggingParentNodeAfterDrop.childNodes.forEach((child) => {if (child.data.catId === draggingNode.data.catId) {draggingNodeAfterDrop = child;}})// 递归变量draggingNodeAfterDrop及其childNodes,将其data属性的cateLevel置为level属性值this.updateCatLevel(draggingNodeAfterDrop);}this.nodesInfoAfterDrop.push({catId: draggingNode.data.catId, parentCid: draggingNodeNewPId});console.log(this.nodesInfoAfterDrop);// 4,调用后端接口,将数组nodesInfoAfterDrop发送给后端this.$http({url: this.$http.adornUrl("/product/category/update/sort"),method: "post",data: this.$http.adornData(this.nodesInfoAfterDrop, false),}).then(({ data }) => {if (data && data.code === 0) {this.$message({message: "操作成功",type: "success",duration: 1500,onClose: () => {console.log("删除成功,关闭消息提示");this.getMenus(); // 重新获取数据this.expandedKeys = [draggingNodeNewPId]; // 重置展开节点},});} else {this.$message.error(data.msg);}});},getLevel1Nodes(node) {var tmpNode = node;while(tmpNode.parent) {tmpNode = tmpNode.parent;}return tmpNode.childNodes;},// 写一个根据cid从menus中查询结点的函数getNodeByCid(cid, nodes) {if (cid === 0) {return null;}// 递归查询for (var i = 0; i < nodes.length; i++) {if (nodes[i].data.catId === cid) {return nodes[i];}if (nodes[i].childNodes && nodes[i].childNodes.length > 0) {var node = this.getNodeByCid(cid, nodes[i].childNodes);if (node) {return node;}}}return null;},// 递归更新draggingNode及其子节点的catLevelupdateCatLevel(node) {if (!node) {return;}this.nodesInfoAfterDrop.push({catId: node.data.catId, catLevel: node.level});if (node.childNodes && node.childNodes.length > 0) {node.childNodes.forEach((child) => {this.updateCatLevel(child);});}},allowDrag(draggingNode, dropNode, dropPosition) {var deep = this.countDraggingNodeDeep(draggingNode);// 根据dropPosition结合dropNode.catLevel来判断draggingNode新位置的位置是否合法if (dropPosition === "prev" || dropPosition === "next") {return dropNode.data.catLevel + deep - 1 <= 3;} else if (dropPosition === "inner") {return dropNode.data.catLevel + deep <= 3;}},// 递归计算draggingNode子树的深度countDraggingNodeDeep(draggingNode) {var deep = 0;if (draggingNode.childNodes && draggingNode.childNodes.length > 0) {debugger;draggingNode.childNodes.forEach((child) => {deep = Math.max(deep, this.countDraggingNodeDeep(child));});}return deep + 1;},append(data) {console.log(data);this.dialogType = "create";this.dialogTitle = "新增分类";this.dialogFormVisible = true;this.category = {name: "",parentCid: data.catId,catLevel: data.level + 1,sort: 0,showStatus: 1,};},edit(data) {console.log(data);this.dialogType = "edit";this.dialogTitle = "修改分类";this.dialogFormVisible = true;// 根据catId查询最新数据this.$http({url: this.$http.adornUrl(`/product/category/info/${data.catId}`),method: "get",data: this.$http.adornData({ catId: data.catId }, false),}).then(({ data }) => {if (data && data.code === 0) {this.category = { ...data.data };} else {this.$message.error(data.msg);}});},submitCategory() {if (this.dialogType === "create") {this.addCategory();} else if (this.dialogType === "edit") {this.updateCategory();}},updateCategory() {var { catId, name, icon, productUnit } = this.category;console.log(this.category);this.$http({url: this.$http.adornUrl("/product/category/update"),method: "post",data: this.$http.adornData({ catId, name, icon, productUnit }, false),}).then(({ data }) => {if (data && data.code === 0) {this.$message({message: "修改成功",type: "success",duration: 1500,onClose: () => {console.log("修改成功,关闭消息提示");this.dialogFormVisible = false;this.getMenus(); // 重新获取数据this.expandedKeys = [this.category.parentCid == 0? this.category.catId: this.category.parentCid,]; // 重置展开节点console.log(this.expandedKeys);},});} else {this.$message.error(data.msg);}});},addCategory() {this.$http({url: this.$http.adornUrl("/product/category/save"),method: "post",data: this.$http.adornData(this.category, false),}).then(({ data }) => {if (data && data.code === 0) {this.$message({message: "添加成功",type: "success",duration: 1500,onClose: () => {console.log("添加成功,关闭消息提示");this.dialogFormVisible = false;this.getMenus(); // 重新获取数据this.expandedKeys = [this.category.parentCid]; // 重置展开节点},});} else {this.$message.error(data.msg);}});},remove(node, data) {console.log(node, data);var ids = [node.data.catId];this.$confirm(`确定对[id=${ids.join(",")}]进行[${ids.length == 1 ? "删除" : "批量删除"}]操作?`,"提示",{confirmButtonText: "确定",cancelButtonText: "取消",type: "warning",}).then(() => {this.$http({url: this.$http.adornUrl("/product/category/delete"),method: "post",data: this.$http.adornData(ids, false),}).then(({ data }) => {if (data && data.code === 0) {this.$message({message: "操作成功",type: "success",duration: 1500,onClose: () => {console.log("删除成功,关闭消息提示");this.getMenus(); // 重新获取数据this.expandedKeys = [node.parent.data.catId]; // 重置展开节点},});} else {this.$message.error(data.msg);}});}).catch(() => {});},// 获取分类数据getMenus() {this.dataListLoading = true;this.$http({url: this.$http.adornUrl("/product/category/list/tree"),method: "get",}).then(({ data }) => {console.log(data);this.dataListLoading = false;this.menus = data.data;});},},created() {this.getMenus(); // 获取分类数据},
};
</script>
<style scoped>
</style>
相关文章:

谷粒商城实战笔记-55-商品服务-API-三级分类-修改-拖拽数据收集
文章目录 一,拖拽后结点的parentCid的更新二,拖拽后结点的父节点下所有结点的sort排序属性的变化更新排序的逻辑代码分析 三,拖拽后结点及其子节点catLevel的变化判断是否需要更新 catLevel获取拖动后的新节点 更新 catLevel完整代码 这一节的…...

AI绘画入门实践|Midjourney:使用 --seed 制作情侣头像与漫画
在 Midjourney 中,seed 是指一个种子,用于生成图像时的起点或基础。 使用格式:--seed 获取的seed值 获取 seed 值 使用 seed 生成图像 a cute boys avatar, background with blue sky and white cloud, Ghibli Studio style, Hayao Miyazaki…...
笔记:Enum中FlagsAttribute特性的用法
一、目的:分享Enum中FlagsAttribute特性的用法 在C#中,Enum(枚举)类型可以使用[Flags]属性来表示一个枚举可以存储多个值。这是通过按位运算符(如|(或)和&(与)&#…...
QWidget如何切换ui
在Qt中,QWidget及其子类用于构建图形用户界面。如果你想要在不同的UI之间切换,可以使用QStackedWidget,它可以管理一组QWidget,并且每次只显示其中一个。 以下是一个简单的例子,展示如何使用QStackedWidget切换UI&…...

web网站组成
web网站由四部分组成:浏览器 前端服务器 后端服务器 数据库服务器 流程: 1.浏览器输入网站后,向前端服务器发送请求,前端服务器响应,静态的数据给浏览器。 2.前端代码中script中有url,这个是向后台发送请求的网…...

带您详细了解安全漏洞的产生和防护
什么是漏洞? 漏洞是 IT、网络、云、Web 或移动应用程序系统中的弱点或缺陷,可能使其容易受到成功的外部攻击。攻击者经常试图寻找网络安全中的各种类型的漏洞来组合和利用系统。 一些最常见的漏洞: 1.SQL注入 注入诸如 SQL 查询之类的小代…...

【接口测试】params传参与body传参区别
文章目录 一.params传参二.body传参三.两者区别说明 一.params传参 params传参一般用于get请求 params传参时,参数会附于URL后面以问号形式展示。 示例: http://ip地址:端口号/login?usernamexm&pwd111二.body传参 body传参一般用于post请求 body传参时需…...

【docker】部署证书过期监控系统mouday/domain-admin
证书过期了再去部署证书容易被骂,就找了一个开源的证书过期系统来部署一下 过程 官方文档:https://domain-admin.readthedocs.io/zh-cn/latest/manual/install.html#docker 直接下载镜像是超时的,切换一下文档推荐的镜像源 新建docker配置…...
高级java每日一道面试题-2024年7月17日
面试官: java中都有哪些引用类型? 我回答: 强引用(Strong Reference) 描述:这是最常见和最直观的引用类型,我们通常在代码中创建的对象引用就是强引用。例如,Object obj new Object();。只要强引用存在,…...
css中如何清除浮动
在CSS中,可以使用clear:both属性来清除浮动。以下是几种常见的清除浮动的方法: 使用clearfix类:在CSS中定义一个clearfix类,并将其应用于需要清除浮动的父元素上。 .clearfix::after {content: "";display: table;cle…...

【网络】tcp_socket
tcp_socket 一、tcp_server与udp_server一样的部分二、listen接口(监听)三、accept接收套接字1、为什么还要多一个套接字(明明已经有了个socket套接字文件了,为什么要多一个accept套接字文件?)2、底层拿到新…...

Live555源码阅读笔记:哈希表的实现
😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 🤣本文内容🤣&a…...

vue3创建vite项目
一、创建vue3 vite项目: 命令行创建:npm create vitelatest vue3-tdly-demo -- --template vue (1)先进入项目文件夹,cd vue3-tdly-demo (2)之后执行, npm install (3)最后运行,npm run dev 将main.js文件内容改成…...

Maven概述
目录 1.Maven简介 2.Maven开发环境搭建 2.1下载Maven服务器 2.2安装,配置Maven 1.配置本地仓库地址 2.配置阿里云镜像地址 2.3在idea中配置maven 2.4在idea中创建maven项目 3.pom.xml配置 1.项目基本信息 2.依赖信息 3.构建信息 4.Maven命令 5.打包Jav…...
Easyu中datagrid点击时获取所在行的数据
问题 双击单元格时,获取该行的记录内容 $(#list).datagrid({method: post,url: user/list,queryParams:{sex : "f",age : "18~25"},fitColumns: true,pageList: [ 5, 10, 15, 20 ],singleSelect: false,pagination: true,fit: true,rownumber…...

java项目中添加SDK项目作为依赖使用(无需上传Maven)
需求: 当需要多次调用某个函数或算法时,不想每次调用接口都自己编写,可以将该项目打包,以添加依赖的方式实现调用 适用于: 无需上线的项目,仅公司或团队内部使用的项目 操作步骤: 以下面这…...

区块链和数据要素融合的价值及应用
一、数据要素面临的关键障碍 在构建数据要素基石的过程中,首要任务是明确并解决产权架构的难题,特别是使用权的确立与流转机制的顺畅,此乃数字经济蓬勃发展的命脉所在。一个高效的数据流转体系对于激发数据潜能、加速经济发展及优化数据资源…...
以太坊的可扩展性危机:探索执行层的瓶颈
导读:以太坊执行层承担着交易处理、智能合约执行以及保持一致和安全状态的维护等工作。Fuel Labs 撰文解析了以太坊执行层的工作原理,及其在可扩展性方面的发展瓶颈和影响。 Fuel Labs: 执行是指在区块链上执行交易和执行状态更改所需的计算。此计算通常…...
静态解析activiti文本,不入库操作流程
说明: activiti本身状态存库,导致效率太低,把中间状态封装成一个载荷类,返回给上游,下次请求时给带着载荷类即可。 1.pom依赖 <dependency><groupId>net.sf.json-lib</groupId><artifactId>js…...
100个python的基本语法知识【上】
0. 变量和赋值: x 5 name “John” 1. 数据类型: 整数(int) 浮点数(float) 字符串(str) 布尔值(bool) 2. 注释: # 这是单行注释 ""…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...
Rust 异步编程
Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文全面剖析RNN核心原理,深入讲解梯度消失/爆炸问题,并通过LSTM/GRU结构实现解决方案,提供时间序列预测和文本生成…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...

华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...