golang结合neo4j实现权限功能设计

neo4j 是非关系型数据库之图形数据库,这里不再赘述。
传统关系数据库基于rbac实现权限, user ---- role ------permission,加上中间表共5张表。
如果再添上部门的概念:用户属于部门,部门拥有 角色,则又多了一层:
user
------
dept *-------- * role *------*permission,
如果再引入子部门概念。。。

1.权限设计

1.1 关系

user ---*-----> role --- * --> permission
user ------> dept [-->父dept -->父dept --->父dept]  ---可让子部门继承*-> role --- * --> permission
user ------> dept ---不允许子部门继承*-> role --- * --> permission

1.2 图

用户和部门之间的关系:
在这里插入图片描述

部门和子部门之间的关系:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

部门和角色关系:
在这里插入图片描述
角色和权限关系:
在这里插入图片描述
后台配置界面:
在这里插入图片描述

1.查询一个用户拥有的权限集:

match paths=(admin:Admin{name:'zs'})-[:HAS_ROLE]->(:Role)-[:HAS]->(p:Permission)
return p.id as id, p.name as name, p.url as url
union
match (admin:Admin{name:'zs'})
match paths=(admin)-[:BELONG_TO]->(:Dept)-[:CHILD_OF*0..3]->(d:Dept)-[:ALLOW_INHERIT]->(:Role)
-[:HAS]->(p:Permission)
return p.id as id, p.name as name, p.url as url
union
match (admin:Admin{name:'zs'})
match paths=(admin)-[:BELONG_TO]->(d:Dept)-[:ALLOW_NO_INHERIT]->(:Role)
-[:HAS]->(p:Permission)
return p.id as id, p.name as name, p.url as url

在这里插入图片描述
查询用户权限集:链路:

match paths=(admin:Admin{name:'xiaolan'})-[:HAS_ROLE]->(:Role)-[:HAS]->(p:Permission)
return paths
union
match (admin:Admin{name:'xiaolan'})
match paths=(admin)-[:BELONG_TO]->(:Dept)-[:CHILD_OF*0..3]->(d:Dept)-[:ALLOW_INHERIT]->(:Role)
-[:HAS]->(p:Permission)
return paths
union
match (admin:Admin{name:'xiaolan'})
match paths=(admin)-[:BELONG_TO]->(d:Dept)-[:ALLOW_NO_INHERIT]->(:Role)
-[:HAS]->(p:Permission)
return paths

在这里插入图片描述

2.判断一个用户是否可访问特定资源(url, 通过权限体现此概念):

match c=(admin:Admin{name:'xiaoQ'})-[:HAS_ROLE]->(:Role)-[:HAS]->(p:Permission{url:'/api/v2/goods/list'})
return count(c) as accessCount
union
match c=(admin:Admin{name:'xiaoQ'})-[:BELONG_TO]->(:Dept)-[:CHILD_OF*0..3]->(d:Dept)-[:ALLOW_INHERIT]->(:Role)
-[:HAS]->(p:Permission {url:'/api/v2/goods/list'})
where not ((admin)-[:BELONG_TO]->(:Dept)-[:CHILD_OF*0..3]->(d:Dept)-[:DENY]->(:Role))
return count(c) as accessCount
union
match c=(admin:Admin{name:'xiaoQ'})-[:BELONG_TO]->(d:Dept)-[:ALLOW_NO_INHERIT]->(:Role)
-[:HAS]->(p:Permission {url:'/api/v2/goods/list'})
return count(c) as accessCount

在这里插入图片描述

3.查看谁拥有指定资源(url) 的权限:

match (p:Permission{url:'/api/v2/admin/list'})
match (admin:Admin)-[:HAS_ROLE]->(:Role)-[:HAS]->(p)
return admin.id as id, admin.name as name
union
match (p:Permission{url:'/api/v2/admin/list'})
match (admin:Admin)-[:BELONG_TO]->(:Dept)-[:CHILD_OF*0..3]->(d:Dept)-[:ALLOW_INHERIT]->(:Role)-[:HAS]->(p)
where not ((admin)-[:BELONG_TO]->(:Dept)-[:CHILD_OF*0..3]->(d:Dept)-[:DENY]->(:Role))
return admin.id as id, admin.name as name
union
match (p:Permission{url:'/api/v2/admin/list'})
match (admin:Admin)-[:BELONG_TO]->(d:Dept)-[:ALLOW_NO_INHERIT]->(:Role)-[:HAS]->(p)
return admin.id as id, admin.name as name

在这里插入图片描述
附上完整关系图:
在这里插入图片描述

下面介绍golang代码整合处理:

先上成型图:
在这里插入图片描述
在这里插入图片描述

1.启动项目时读取配置,初始化neo4j driver:

package commonimport ("context""github.com/neo4j/neo4j-go-driver/v5/neo4j""log"
)var DBName string
var Neo4jCtx = context.Background()
var Driver neo4j.DriverWithContextfunc initNeo4jConfig(c neo4jConfig) {var err error// Driver is thread safe: can be shared by multiple threadsDriver, err = neo4j.NewDriverWithContext(c.DbUri, neo4j.BasicAuth(c.DbUser, c.DbPwd, ""))if err != nil {log.Println("new neo4j driver with context failed:", err.Error())return}err = Driver.VerifyConnectivity(Neo4jCtx)if err != nil {log.Printf("init neo4j failed:%s\n", c)return}log.Println("neo4j connection established...")DBName = c.DBName
}

2.neo4j列表分页查询数据

func PageDept(pageNo, pageSize int, name string, queryParentOnly string, parent uint64) (*common.Page, error) {var ctx = common.Neo4jCtxsession := common.Driver.NewSession(ctx, neo4j.SessionConfig{DatabaseName: common.DBName})defer session.Close(ctx)tx, err := session.BeginTransaction(ctx)if err != nil {return nil, err}defer tx.Rollback(ctx)whereSql, params := composeDeptSearchQuerySql(name, queryParentOnly, parent)res, err := tx.Run(ctx, whereSql+` return count(d.id) as c`, params)if err != nil {return nil, err}record, err := res.Single(ctx)if err != nil {return nil, err}var c = int64(0)if r, flg := record.Get("c"); flg && r != nil {c = r.(int64)}// 没有数据if c == int64(0) {return common.NewPage([]model.Dept{}, pageNo, pageSize, 0), nil}params["s"] = (pageNo - 1) * pageSizeparams["size"] = pageSizeres, err = tx.Run(ctx, whereSql + ` return `+row+` order by d.id SKIP $s limit $size`, params)if err != nil {return nil, err}var ds []model.Deptfor res.Next(ctx) {m := res.Record().AsMap()var d model.Depterr = mapstructure.Decode(m, &d)if err != nil {return nil, err}d.CreatedTimeStr = d.CreatedTime.Format(time.DateTime)ds = append(ds, d)}return common.NewPage(ds, pageNo, pageSize, int(c)), nil
}func composeDeptSearchQuerySql(name string, only string, parent uint64) (string, map[string]any) {var params = map[string]any{}sb := strings.Builder{}sb.WriteString("match (d:Dept) ")// 没有条件查询if name == "" && only == "" && parent == 0 {return sb.String(), params}// 只查询父分类if only == "on" {sb.WriteString(" where d.parent = 0")return sb.String(), params}// 查询指定的父分类if parent > 0 {sb.WriteString("-[:CHILD_OF]->(:Dept{id: $parent})")//sb.WriteString(" where d.parent = $parent")params["parent"] = parent}// 有部门名称的模糊查询if len(name) > 0 {sb.WriteString(" where d.name CONTAINS $name")params["name"] = name}return sb.String(), params
}

权限permission dao for neo4j操作:

package neoimport ("commerce/common""commerce/model""fmt""github.com/mitchellh/mapstructure""github.com/neo4j/neo4j-go-driver/v5/neo4j""strings""sync"
)var permissionLock sync.Mutexfunc PagePermission(pageNo, pageSize int, name string) (*common.Page, error) {var ctx = common.Neo4jCtxsession := common.Driver.NewSession(ctx, neo4j.SessionConfig{DatabaseName: common.DBName})defer session.Close(ctx)tx, err := session.BeginTransaction(ctx)if err != nil {return nil, err}defer tx.Rollback(ctx)whereSql, params := composePermissionSearchQuerySql(name)res, err := tx.Run(ctx, whereSql+` return count(p.id) as c`, params)if err != nil {return nil, err}record, err := res.Single(ctx)if err != nil {return nil, err}var c = int64(0)if r, flg := record.Get("c"); flg && r != nil {c = r.(int64)}// 没有数据if c == int64(0) {return common.NewPage([]model.Permission{}, pageNo, pageSize, 0), nil}params["s"] = (pageNo - 1) * pageSizeparams["size"] = pageSizeres, err = tx.Run(ctx, whereSql+` return p.id as id, p.name as name, p.priority as priority, p.status as status, p.public_res_flg as public_res_flg order by p.id SKIP $s limit $size`, params)if err != nil {return nil, err}var rs []model.Permissionfor res.Next(ctx) {m := res.Record().AsMap()var r model.Permissionerr = mapstructure.Decode(m, &r)if err != nil {return nil, err}rs = append(rs, r)}return common.NewPage(rs, pageNo, pageSize, int(c)), nil
}func GetPermissionById(id uint64) (*model.Permission, error) {sqlTpl := `match (p:Permission {id: $id}) return p.id as id, p.name as name, p.priority as priority, p.status as status, p.public_res_flg as public_res_flg`res, err := neo4j.ExecuteQuery(common.Neo4jCtx, common.Driver, sqlTpl, map[string]any{"id": id,}, neo4j.EagerResultTransformer,neo4j.ExecuteQueryWithDatabase(common.DBName),neo4j.ExecuteQueryWithReadersRouting(),)if err != nil {return nil, err}records := res.Recordsif records == nil || len(records) == 0 {return nil, err}m := records[0].AsMap()var r model.Permissionerr = mapstructure.Decode(m, &r)if err != nil {return nil, err}return &r, nil
}func AddPermission(c model.Permission) (uint64, error) {permissionLock.Lock()defer permissionLock.Unlock()res, err := neo4j.ExecuteQuery(common.Neo4jCtx, common.Driver, `match (p:Permission {name: $name}) return p.id as id limit 1`, map[string]any{"name": c.Name},neo4j.EagerResultTransformer, neo4j.ExecuteQueryWithDatabase(common.DBName),neo4j.ExecuteQueryWithReadersRouting())if err != nil {return 0, err}if res.Records != nil && len(res.Records) > 0 {return 0, fmt.Errorf("%s 已存在,不允许创建", c.Name)}id := common.IdGenerator.Generate()sqlTpl := `create (p:Permission {id: $id, name: $name, priority: $priority, status:$status, public_res_flg: $publicResFlg, created_time: datetime({timezone: 'Asia/Shanghai'}), updated_time: datetime({timezone: 'Asia/Shanghai'})})`_, err = neo4j.ExecuteQuery(common.Neo4jCtx, common.Driver, sqlTpl, map[string]any{"id":           id,"name":         c.Name,"priority":     c.Priority,"status":       c.Status,"publicResFlg": c.PublicResFlg,}, neo4j.EagerResultTransformer, neo4j.ExecuteQueryWithDatabase(common.DBName))if err != nil {return 0, err}return id, nil
}func UpdatePermission(c model.Permission) (bool, error) {permissionLock.Lock()defer permissionLock.Unlock()res, err := neo4j.ExecuteQuery(common.Neo4jCtx, common.Driver, `match (p:Permission {name: $name}) return p.id as id limit 1`, map[string]any{"name": c.Name},neo4j.EagerResultTransformer, neo4j.ExecuteQueryWithDatabase(common.DBName),neo4j.ExecuteQueryWithReadersRouting())if err != nil {return false, err}records := res.Recordsif records != nil && len(records) > 0 {r, _ := records[0].Get("id")dbId := uint64(r.(int64))if dbId != c.Id {return false, fmt.Errorf("%s 已存在,不允许更新部门名称为此值", c.Name)}}sqlTpl := `match (p:Permission {id: $id}) set p.name=$name, p.priority=$priority,p.public_res_flg=$publicResFlg, p.updated_time=datetime({timezone: 'Asia/Shanghai'})`res, err = neo4j.ExecuteQuery(common.Neo4jCtx, common.Driver, sqlTpl, map[string]any{"id":           c.Id,"name":         c.Name,"priority":     c.Priority,"publicResFlg": c.PublicResFlg,}, neo4j.EagerResultTransformer, neo4j.ExecuteQueryWithDatabase(common.DBName))if err != nil {return false, err}return res.Summary.Counters().ContainsUpdates(), nil
}func composePermissionSearchQuerySql(name string) (string, map[string]any) {var params = map[string]any{}sb := strings.Builder{}sb.WriteString("match (p:Permission) ")// 没有条件查询if name == "" {return sb.String(), params}// 有权限名称的模糊查询if len(name) > 0 {sb.WriteString(" where p.name CONTAINS $name")params["name"] = name}return sb.String(), params
}func UpdatePermissionStatus(id uint64, status int8) error {sqlTpl := `match (p:Permission {id: $id}) set p.status = $status, p.updated_time=datetime({timezone: 'Asia/Shanghai'})`_, err := neo4j.ExecuteQuery(common.Neo4jCtx, common.Driver, sqlTpl, map[string]any{"id":     id,"status": status,}, neo4j.EagerResultTransformer, neo4j.ExecuteQueryWithDatabase(common.DBName))if err != nil {return err}return nil
}func ListAllPermission() ([]model.Permission, error) {res, err := neo4j.ExecuteQuery(common.Neo4jCtx, common.Driver,`match (p:Permission) where p.status = $status return p.id as id, p.name as name order by p.priority`,map[string]any{"status": 1},neo4j.EagerResultTransformer, neo4j.ExecuteQueryWithDatabase(common.DBName),neo4j.ExecuteQueryWithReadersRouting())if err != nil {return nil, err}records := res.Recordsvar ps = make([]model.Permission, len(records))for i, r := range records {var p model.Permissionerr = mapstructure.Decode(r.AsMap(), &p)if err != nil {return nil, err}ps[i] = p}return ps, nil
}func ListPermissionByRoleId(roleId uint64) ([]model.Permission, error) {res, err := neo4j.ExecuteQuery(common.Neo4jCtx, common.Driver,`match (p:Permission {status: $status})<-[:HAS]-(r:Role {id: $roleId}) return distinct p.id as id, p.name as name`,map[string]any{"status": 1, "roleId": roleId},neo4j.EagerResultTransformer, neo4j.ExecuteQueryWithDatabase(common.DBName),neo4j.ExecuteQueryWithReadersRouting())if err != nil {return nil, err}records := res.Recordsvar ps = make([]model.Permission, len(records))for i, r := range records {var p model.Permissionerr = mapstructure.Decode(r.AsMap(), &p)if err != nil {return nil, err}ps[i] = p}return ps, nil
}

角色操作neo4j dao:

package neoimport ("commerce/common""commerce/model""fmt""github.com/mitchellh/mapstructure""github.com/neo4j/neo4j-go-driver/v5/neo4j""strings""sync"
)var roleLock sync.Mutexfunc PageRole(pageNo, pageSize int, name string) (*common.Page, error) {var ctx = common.Neo4jCtxsession := common.Driver.NewSession(ctx, neo4j.SessionConfig{DatabaseName: common.DBName})defer session.Close(ctx)tx, err := session.BeginTransaction(ctx)if err != nil {return nil, err}defer tx.Rollback(ctx)whereSql, params := composeRoleSearchQuerySql(name)res, err := tx.Run(ctx, whereSql+` return count(r.id) as c`, params)if err != nil {return nil, err}record, err := res.Single(ctx)if err != nil {return nil, err}var c = int64(0)if r, flg := record.Get("c"); flg && r != nil {c = r.(int64)}// 没有数据if c == int64(0) {return common.NewPage([]model.Role{}, pageNo, pageSize, 0), nil}params["s"] = (pageNo - 1) * pageSizeparams["size"] = pageSizeres, err = tx.Run(ctx, whereSql+` return r.id as id, r.name as name, r.priority as priority, r.status as status order by r.id SKIP $s limit $size`, params)if err != nil {return nil, err}var rs []model.Rolefor res.Next(ctx) {m := res.Record().AsMap()var r model.Roleerr = mapstructure.Decode(m, &r)if err != nil {return nil, err}rs = append(rs, r)}return common.NewPage(rs, pageNo, pageSize, int(c)), nil
}func GetRoleById(id uint64) (*model.Role, error) {sqlTpl := `match (r:Role {id: $id}) return r.id as id, r.name as name, r.priority as priority, r.status as status`res, err := neo4j.ExecuteQuery(common.Neo4jCtx, common.Driver, sqlTpl, map[string]any{"id": id,}, neo4j.EagerResultTransformer,neo4j.ExecuteQueryWithDatabase(common.DBName),neo4j.ExecuteQueryWithReadersRouting(),)if err != nil {return nil, err}records := res.Recordsif records == nil || len(records) == 0 {return nil, err}m := records[0].AsMap()var r model.Roleerr = mapstructure.Decode(m, &r)if err != nil {return nil, err}return &r, nil
}func AddRole(c model.Role) (uint64, error) {roleLock.Lock()defer roleLock.Unlock()res, err := neo4j.ExecuteQuery(common.Neo4jCtx, common.Driver, `match (r:Role {name: $name}) return r.id as id limit 1`, map[string]any{"name": c.Name},neo4j.EagerResultTransformer, neo4j.ExecuteQueryWithDatabase(common.DBName),neo4j.ExecuteQueryWithReadersRouting())if err != nil {return 0, err}if res.Records != nil && len(res.Records) > 0 {return 0, fmt.Errorf("%s 已存在,不允许创建", c.Name)}id := common.IdGenerator.Generate()sqlTpl := `create (r:Role {id: $id, name: $name,priority: $priority, status:$status, created_time: datetime({timezone: 'Asia/Shanghai'}), updated_time: datetime({timezone: 'Asia/Shanghai'})})`_, err = neo4j.ExecuteQuery(common.Neo4jCtx, common.Driver, sqlTpl, map[string]any{"id":       id,"name":     c.Name,"priority": c.Priority,"status":   c.Status,}, neo4j.EagerResultTransformer, neo4j.ExecuteQueryWithDatabase(common.DBName))if err != nil {return 0, err}return id, nil
}func UpdateRole(c model.Role) (bool, error) {roleLock.Lock()defer roleLock.Unlock()res, err := neo4j.ExecuteQuery(common.Neo4jCtx, common.Driver, `match (r:Role {name: $name}) return r.id as id limit 1`, map[string]any{"name": c.Name},neo4j.EagerResultTransformer, neo4j.ExecuteQueryWithDatabase(common.DBName),neo4j.ExecuteQueryWithReadersRouting())if err != nil {return false, err}records := res.Recordsif records != nil && len(records) > 0 {r, _ := records[0].Get("id")dbId := uint64(r.(int64))if dbId != c.Id {return false, fmt.Errorf("%s 已存在,不允许更新部门名称为此值", c.Name)}}sqlTpl := `match (r:Role {id: $id}) set r.name=$name, r.priority=$priority, r.updated_time=datetime({timezone: 'Asia/Shanghai'})`res, err = neo4j.ExecuteQuery(common.Neo4jCtx, common.Driver, sqlTpl, map[string]any{"id":       c.Id,"name":     c.Name,"priority": c.Priority,}, neo4j.EagerResultTransformer, neo4j.ExecuteQueryWithDatabase(common.DBName))if err != nil {return false, err}return res.Summary.Counters().ContainsUpdates(), nil
}func composeRoleSearchQuerySql(name string) (string, map[string]any) {var params = map[string]any{}sb := strings.Builder{}sb.WriteString("match (r:Role) ")// 没有条件查询if name == "" {return sb.String(), params}// 有角色名称的模糊查询if len(name) > 0 {sb.WriteString(" where r.name CONTAINS $name")params["name"] = name}return sb.String(), params
}func UpdateRoleStatus(id uint64, status int8) error {sqlTpl := `match (r:Role {id: $id}) set r.status = $status, r.updated_time=datetime({timezone: 'Asia/Shanghai'})`_, err := neo4j.ExecuteQuery(common.Neo4jCtx, common.Driver, sqlTpl, map[string]any{"id":     id,"status": status,}, neo4j.EagerResultTransformer, neo4j.ExecuteQueryWithDatabase(common.DBName))if err != nil {return err}return nil
}func AttachRolePermissionList(roleId uint64, permissionIdList []uint64) error {var sqlTpl stringif len(permissionIdList) == 0 {sqlTpl = `match (:Role {id: $roleId})-[rel:HAS]->(:Permission) delete rel`} else {sqlTpl = `match (r:Role {id: $roleId})CALL {match (r:Role {id: $roleId})-[rel:HAS]->(:Permission) delete rel }with runwind $permissionIdList as pIdmatch (p:Permission {id: pId})merge (r)-[:HAS]->(p)`}_, err := neo4j.ExecuteQuery(common.Neo4jCtx, common.Driver, sqlTpl, map[string]any{"roleId":           roleId,"permissionIdList": permissionIdList,}, neo4j.EagerResultTransformer, neo4j.ExecuteQueryWithDatabase(common.DBName))if err != nil {return err}return nil
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL之备份与恢复(七)

备份与恢复 文件系统快照 规划LVM备份 LVM快照备份也是有开销的。服务器写到原始卷的越多&#xff0c;引发的额外开销也越多。当服务器随机修改许多不同块时&#xff0c;磁头需要需要自写时复制空间来来回回寻址&#xff0c;并且将数据的老版本写到写时复制空间。从快照中读…

网络基础:IS-IS协议

IS-IS&#xff08;Intermediate System to Intermediate System&#xff09;是一种链路状态路由协议&#xff0c;最初由 ISO&#xff08;International Organization for Standardization&#xff09;为 CLNS&#xff08;Connectionless Network Service&#xff09;网络设计。…

Windows电脑下载、安装VS Code的方法

本文介绍Visual Studio Code&#xff08;VS Code&#xff09;软件在Windows操作系统电脑中的下载、安装、运行方法。 Visual Studio Code&#xff08;简称VS Code&#xff09;是一款由微软开发的免费、开源的源代码编辑器&#xff0c;支持跨平台使用&#xff0c;可在Windows、m…

apk反编译修改教程系列-----修改apk 解除软件限制功能 实例操作步骤解析_3【二十二】

在前面的几期博文中有过解析去除apk中功能权限的反编译步骤。另外在以往博文中也列举了修改apk中选项功能权限的操作方法。今天以另外一款apk作为演示修改反编译去除软件功能限制的步骤。兴趣的友友可以参考其中的修改过程。 课程的目的是了解apk中各个文件的具体作用以及简单…

【经验篇】Spring Data JPA开启批量更新时乐观锁失效问题

乐观锁机制 什么是乐观锁&#xff1f; 乐观锁的基本思想是&#xff0c;认为在大多数情况下&#xff0c;数据访问不会导致冲突。因此&#xff0c;乐观锁允许多个事务同时读取和修改相同的数据&#xff0c;而不进行显式的锁定。在提交事务之前&#xff0c;会检查是否有其他事务…

浏览器插件利器-allWebPluginV2.0.0.14-stable版发布

allWebPlugin简介 allWebPlugin中间件是一款为用户提供安全、可靠、便捷的浏览器插件服务的中间件产品&#xff0c;致力于将浏览器插件重新应用到所有浏览器。它将现有ActiveX插件直接嵌入浏览器&#xff0c;实现插件加载、界面显示、接口调用、事件回调等。支持谷歌、火狐等浏…

【音视频 | RTSP】RTSP协议详解 及 抓包例子解析(详细而不赘述)

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

catia数控加工仿真铣平面粗加工

1&#xff0c;零件建模&#xff0c;毛坯建模 2 在毛坯上建立坐标系 3 添加资料刀具 4&#xff0c;双击对相关加工信息做设置 5 Roughing 加工设置 高亮红色区域是必选的&#xff0c;其他可以默认 6 完成加工仿真 7 加工余量

Android zygote访谈录

戳蓝字“牛晓伟”关注我哦&#xff01; 用心坚持输出易读、有趣、有深度、高质量、体系化的技术文章&#xff0c;技术文章也可以有温度。 本文摘要 本文以访谈的方式来带大家了解zygote进程&#xff0c;了解zygote进程是啥&#xff1f;它的作用是啥&#xff1f;它是如何一步…

从零开始开发跑腿配送系统:技术选型与架构设计

开发一个跑腿配送系统涉及多个技术栈和模块&#xff0c;从前端到后端&#xff0c;再到数据库和实时通信&#xff0c;每一个环节都至关重要。本文将详细介绍从零开始开发跑腿配送系统的技术选型与架构设计&#xff0c;并提供部分代码示例以帮助理解。 一、技术选型 前端技术&am…

国产化新标杆:TiDB 助力广发银行新一代总账系统投产上线

随着全球金融市场的快速发展和数字化转型的深入推进&#xff0c;金融科技已成为推动银行业创新的核心力量。特别是在当前复杂多变的经济环境下&#xff0c;银行业务的高效运作和风险管理能力显得尤为重要。总账系统作为银行会计信息系统的核心&#xff0c;承载着记录、处理和汇…

Linux网络管理

一、linux网络管理 1.获取计算机的网络信息 基本语法&#xff1a; #ifconfig #ip address &#xff08;ip a&#xff09; 解析&#xff1a; ens33&#xff1a;默认网卡 lo&#xff1a;环回网卡&#xff0c;127.0.0.1作为固定ip代表本机 virbr0&#xff1a;虚拟网络接口&…

Python入门 2024/7/3

目录 for循环的基础语法 遍历字符串 练习&#xff1a;数一数有几个a range语句 三个语法 语法1 语法2 语法3 练习&#xff1a;有几个偶数 变量作用域 for循环的嵌套使用 打印九九乘法表 发工资案例 continue和break语句 函数的基础定义语法 函数声明 函数调用 …

探索Linux:开源世界的无限可能

Linux是一款开源操作系统&#xff0c;它的起源可以追溯到上世纪90年代初。这个故事始于一个名叫Linus Torvalds的芬兰大学生&#xff0c;他在1983年开始编写一个用于个人电脑的操作系统内核。在他的努力下&#xff0c;Linux逐渐发展成为一个稳定而强大的操作系统。 然而&#…

Apache Seata配置管理原理解析

本文来自 Apache Seata官方文档&#xff0c;欢迎访问官网&#xff0c;查看更多深度文章。 本文来自 Apache Seata官方文档&#xff0c;欢迎访问官网&#xff0c;查看更多深度文章。 Apache Seata配置管理原理解析 说到Seata中的配置管理&#xff0c;大家可能会想到Seata中适配…

盘点8款国内顶尖局域网监控软件(2024年国产局域网监控软件排名)

局域网监控软件对于企业网络管理至关重要&#xff0c;它们可以帮助IT部门维护网络安全&#xff0c;优化网络性能&#xff0c;同时监控和控制内部员工的网络使用行为。以下是八款备受推崇的局域网监控软件&#xff0c;每一款都有其独特的优势和适用场景。 1.安企神软件 试用版领…

【机器学习实战】Datawhale夏令营:Baseline精读笔记2

# AI夏令营 # Datawhale # 夏令营 在原有的Baseline上除了交叉验证&#xff0c;还有一种关键的优化方式&#xff0c;即特征工程。 如何优化特征&#xff0c;关系着我们提高模型预测的精准度。特征工程往往是对问题的领域有深入了解的人员能够做好的部分&#xff0c;因为我们要…

护网在即,知攻善防助力每一位安服仔~

前言 是不是已经有师傅进场了呢~ 是不是有安服&#x1f412;在值守呢~ 您是不是被网上眼花缭乱的常用应急响应工具而烦恼呢&#xff1f; 何以解忧&#xff1f;唯有知攻善防&#xff01; 创作起源&#xff1a; 驻场、护网等&#xff0c;有的客户现场只允许用客户机器&…

Linux-gdb

目录 1.-g 生成含有debug信息的可执行文件 2.gdb开始以及gdb中的常用执行指令 3.断点的本质用法 4.快速跳出函数体 5.其他 1.-g 生成含有debug信息的可执行文件 2.gdb开始以及gdb中的常用执行指令 3.断点的本质用法 断点的本质是帮助我们缩小出问题的范围 比如&#xff0c;…

Linux系统安装软件包的方法rpm和yum详解

起因&#xff1a; 本篇文章是记录学习Centos7的历程 关于rpm 常见命令 1&#xff09;查看已经安装的软件包 rpm -q 软件包名 2&#xff09;查看文件的相关信息 rpm -qi 软件包名 3&#xff09;查看软件包的依赖关系 就是说要想安装这个软件包&#xff0c;就必须把一些前…