当前位置: 首页 > news >正文

.NET8关于ORM的一次思考

文章目录

  • 前言
  • 一、思路
  • 二、实现ODBC=>SqlHelper.cs
  • 三、数据对象实体化
  • 四、SQL生成SqlBuilder.cs
  • 五、参数注入 SqlParameters.cs
  • 六、反射 SqlOrm.cs
  • 七、自定义数据查询
  • 八、总结

前言

琢磨着在.NET8找一个ORM,对比了最新的框架和性能。

框架批量操作性能SQL控制粒度学习成本扩展性
Dapper★★★★☆完全自主依赖扩展库
SqlSugar★★★★☆半自动内置优化
EF Core★★☆☆☆自动生成高度可扩展
ODBC★★☆☆☆完全自主依赖驱动

Dapper在1000条以内和10万以上的数据都是最快的,且粒度小。
毕竟Dapper够轻量:仅26个核心类,无复杂映射配置。

但当我看到它的驱动依旧是System.Data.SqlClient时,我思索,为什么我不自己写一个呢。
毕竟我的逻辑大多在存储过程里。框架也是人家重构出来的嘛,人家的不一定是适合自己的。
尝试着在.net8里重构了一下并记录下来

一、思路

1、泛型调用实体,缩减定义代码
2、语句参数化,保障性能和安全(防注入)
3、以dataset为主、model的二次操作为辅,实现数据的快速Josn化,方便接口调用、数据IO
4、事务可选化设置,因为主业务在存储过程,我可以另外单独写事务。
5、异步提升效率。
6、使用Lamada精简代码
7、复杂语句在存储过程分离,降低ODBC的维护成本。
8、using实现数据的快速回收。

二、实现ODBC=>SqlHelper.cs

Nuget 安装Microsoft.Data.SqlClient包。
主要方法
1、ExecuteNonQuery 返回执行条数,作为编辑用。
2、ExecuteScalar返回执行Object ,作为查询用。
这区分开了就很好实现了,增、改、删我用1、查我用2。思路清晰。

 using (SqlConnection connection = new SqlConnection(connectionString)){await connection.OpenAsync();using (SqlCommand cmd = new SqlCommand(sql, connection)){return await cmd.ExecuteNonQueryAsync();//ExecuteScalar()}
}

主要连接就这个了,使用using 实现资源释放。

加上我们提到的重构一下:

using Microsoft.Data.SqlClient;
using System.Data;
using System.Data.Common;
using System.Diagnostics;
using System.Transactions;namespace DataProcess
{/// <summary>/// ODBC 辅助类/// </summary>public class SqlHelper{public static string ConnectionString = "";private static int timeout = 30;private static string _empty = "null";/// <summary>/// 返回查询结果/// </summary>/// <param name="SqlStr"></param>/// <returns></returns>public static async Task<object> MyTran(List<CmdData> list, string type, bool IsTran){try{using (SqlConnection connection = new SqlConnection(ConnectionString)){await connection.OpenAsync();if (type == "Edit")// 执行SQL 返回影响条数return await Edit(connection, CommandType.Text, list, IsTran);if (type == "QueryDs")// 执行SQL 返回查询结果DataSetreturn await QueryDs(connection, CommandType.Text, list);if (type == "QueryInt")// 执行SQL 返回查询结果 第一行第一列的int return await QueryInt(connection, CommandType.Text, list);elsereturn _empty;}}catch (SqlException ex){Console.WriteLine($"数据库错误:{ex.Message}");return _empty;}}/// <summary>/// 非查询  =>条数  --存储过程 Istran=0/// </summary>/// <returns></returns>public static async Task<object> Edit(SqlConnection connection, CommandType cmdType, List<CmdData> list, bool IsTran){SqlTransaction trans = null;if (IsTran) //是否开启事务trans = connection.BeginTransaction();try{int result = 0;for (int i = 0; i < list.Count; i++)//批量删除{using (SqlCommand cmd = new SqlCommand(list[i].sql, connection)){if (IsTran) cmd.Transaction = trans;cmd.CommandType = cmdType;if (list[i].parameter != null) cmd.Parameters.AddRange(list[i].parameter);cmd.CommandTimeout = timeout; // 超时定义int rst = await cmd.ExecuteNonQueryAsync();if (rst == 0){  //没执行成功if (IsTran) await trans.RollbackAsync();else break;}else result += rst;}if (IsTran) await (trans).CommitAsync();}return result;}catch (Exception e){if (IsTran) await trans.RollbackAsync();return _empty;}}/// <summary>/// 查询  =>数据 Int/// </summary>public static async Task<object> QueryInt(SqlConnection connection, CommandType cmdType, List<CmdData> list){using (SqlCommand cmd = new SqlCommand(list[0].sql, connection)){cmd.CommandType = cmdType;if (list[0].parameter != null) cmd.Parameters.AddRange(list[0].parameter);cmd.CommandTimeout = timeout; // 超时定义try{var rst = await cmd.ExecuteScalarAsync() ;return rst;}catch (Exception e){return _empty;}}}/// <summary>/// 查询  =>数据 DataSet /// </summary>public static async Task<object> QueryDs(SqlConnection connection, CommandType cmdType, List<CmdData> list){using (SqlCommand cmd = new SqlCommand(list[0].sql, connection)){cmd.CommandType = cmdType;if (list[0].parameter != null) cmd.Parameters.AddRange(list[0].parameter);cmd.CommandTimeout = timeout; // 超时定义try{using (DbDataReader reader = await cmd.ExecuteReaderAsync()){DataSet rst = ConvertDataReaderToDataSet(reader);return rst;}}catch (Exception e){return _empty;}}}public static DataSet ConvertDataReaderToDataSet(DbDataReader reader){DataSet dataSet = new DataSet();// 处理第一个结果集DataTable schemaTable = reader.GetSchemaTable();DataTable dataTable = new DataTable();// 自动构建列结构(根据DataReader的元数据)dataTable.Load(reader);  // 此方法自动映射列并填充数据[^2]dataSet.Tables.Add(dataTable);// 处理后续结果集(如果存在)while (!reader.IsClosed && reader.NextResult()){DataTable nextTable = new DataTable();nextTable.Load(reader);dataSet.Tables.Add(nextTable);}return dataSet;}}//存储过程对象public class StoredProc{public string Name { get; set; }public List<ProcParam> param { get; set; }}public class ProcParam {public ProcParam(string Name, object value){this.Name = Name;this.value = value;}public string Name { get; set; }public object value { get; set; }}

webapi 直接给 sqlhelp.connectionString 赋值,就能实现数据连接了。

三、数据对象实体化

要实现泛型,那肯定要先拿到数据实体的model
数据实体手敲那肯定不和谐,现在实现一键转换的工具还是很多的。我使用EF Core Power Tools,

在这里插入图片描述
在这里插入图片描述
连接数据库,并选中所有表
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

这样就能自动生成跟数据库字段对应的表对象实体了。

四、SQL生成SqlBuilder.cs

SQL是生成分两部分,主体、参数。增删查改还是有迹可循的。

using Microsoft.Data.SqlClient;
using Model;
using System;
using System.Collections.Generic;
using System.Data;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;namespace DataProcess
{/// <summary>/// T-SQL DIY/// </summary>public class SqlBuilder{#region  编辑Edit/// <summary>/// 实体 泛型 Insert 语句/// </summary>public static string InsertSQL<T>(T entity){Type type = typeof(T);string  columns = "";string values = "";foreach (PropertyInfo prop in type.GetProperties()){if (prop.Name == "Id") continue; // 排除自增主键columns+=$"{prop.Name},";values+=$"@{prop.Name},";}return $"INSERT INTO {type.Name} ({columns.TrimEnd(',')}) VALUES ({values.TrimEnd(',')});";}public static string InsertSQL_id<T>(T entity){return InsertSQL(entity) + "Select @@IDENTITY AS LastID;";}public static string UpdateSQL<T>(T entity){Type type = typeof(T);string temp = "";foreach (PropertyInfo prop in type.GetProperties()){if (prop.Name == "Id") { continue; } // 排除自增主键temp += string.Format("{0}=@{0},", prop.Name);}return $"UPDATE  {type.Name} SET ({temp.TrimEnd(',')} WHERE  @id=id";}public static string DeleteSQL<T>(T entity) {string objectName = entity.GetType().Name;string sql = string.Format("delete from  {0}  where id=@id;", objectName);return sql;}#endregion#region 查询 querypublic static string SelectSQL<T>(string id) where T: new(){string ModelName = getName<T>();string sql = string.Format("Select * from  {0}  where id={1};", ModelName, id);return sql;}public static string  ByPageSQL<T>(string strWhere, string orderby, int startIndex, int endIndex) where T : new(){string ModelName = getName<T>();StringBuilder strSql = new StringBuilder();strSql.Append("Select * FROM ( ");strSql.Append(" Select ROW_NUMBER() OVER (");if (!string.IsNullOrEmpty(orderby.Trim())){strSql.Append("order by T." + orderby);}else{strSql.Append("order by T.id desc");}strSql.Append(")AS Row, T.*  from " + ModelName + " T ");if (!string.IsNullOrEmpty(strWhere.Trim())){strSql.Append(" WHERE " + strWhere);}strSql.Append(" ) TT");strSql.AppendFormat(" WHERE TT.Row between {0} and {1}", startIndex, endIndex);return strSql.ToString();}public static string  ListSQL<T>(string strWhere) where T : new(){string ModelName = getName<T>();if (string.IsNullOrEmpty(strWhere)) strWhere = "1=1";string sql = string.Format("Select * from  {0}  where {1};", ModelName, strWhere);return sql;}public static string CountSQL<T>(string strWhere) where T : new(){string ModelName = getName<T>();if (string.IsNullOrEmpty(strWhere)) strWhere = "1=1";string sql = string.Format("Select count(1) from  {0}  where {1};", ModelName, strWhere);return sql;}public static string ProcSQL(StoredProc T){string columns = "";if(string.IsNullOrEmpty(T.ActionType))columns += $"@ActionType={T.ActionType},";foreach (ProcParam item in T.param){columns += $"@{item.Name}={item.value},";}return $"EXEC {T.Name} {columns.TrimEnd(',')};";}#endregion/// <summary>/// 实例以取表名/// </summary>public static string getName<T>() where T : new(){T t = new T();string name = t.GetType().Name;return name;}}
}

五、参数注入 SqlParameters.cs

using Microsoft.Data.SqlClient;
using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using System.Threading.Tasks;namespace DataProcess
{/// <summary>/// 实体注入/// </summary>public class SqlParameters{/// <summary>/// for add/// </summary>public static SqlParameter[] NoID(object entity){return entity.GetType().GetProperties().Where(p => p.Name != "Id").Select(p => new SqlParameter($"@{p.Name}", p.GetValue(entity) ?? DBNull.Value)).ToArray();}/// <summary>/// for delete/// </summary>public static SqlParameter[] OnlyID(object entity){return entity.GetType().GetProperties().Where(p => p.Name == "Id").Select(p => new SqlParameter($"@{p.Name}", p.GetValue(entity) ?? DBNull.Value)).ToArray();}/// <summary>/// for update/// </summary>public static SqlParameter[] HaveId(object entity){SqlParameter[] rst = NoID(entity);SqlParameter[] rst2 = OnlyID(entity);rst.Append(rst2[0]);return rst;}}
}

根据加、删、改,分别循环实体的value注入进去。当然我的每个表都是自增id作为主键的。

六、反射 SqlOrm.cs

增、删、改的Edit部分完成了,现在实现 查询部分。
通过循环实体属性,将DataSet转换为model,并完成赋值

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace DataProcess
{/// <summary>///  DataRow to Model/// </summary>public class SqlOrm{/// <summary>/// 反射/// </summary>public static T ToEntity<T>(DataRow row) where T : new(){//初始化T t = new T();//得到类型Type type = t.GetType();//属性集合PropertyInfo[] ps = type.GetProperties();//赋值、格式转换ps.ToList().ForEach(p =>{var _data = row[p.Name];//值if (_data != null && _data != DBNull.Value)//非空{if (p.PropertyType == typeof(System.Nullable<System.DateTime>))//空时间p.SetValue(t, DateTime.Parse(_data.ToString() ?? "1970-01-01"), null);else if (p.PropertyType == typeof(System.Nullable<System.Decimal>))//空Decimalp.SetValue(t, Decimal.Parse(_data.ToString() ?? "0"), null);else if (p.PropertyType == typeof(System.Nullable<System.Int32>))//Int32p.SetValue(t, Int32.Parse(_data.ToString() ?? "0"), null);elsep.SetValue(t, Convert.ChangeType(_data, p.PropertyType), null);}elsep.SetValue(t, Convert.ChangeType(_data, p.PropertyType), null);});return t;}}
}

七、自定义数据查询

using Microsoft.Data.SqlClient;
using Model;
using System;
using System.Data;
using System.Data.Common;
using System.Text;
using System.Threading.Tasks;namespace DataProcess
{public class Access{#region 基础basic/// <summary>/// 单增/// </summary>public static async Task<bool> Add<T>(T entity){string SqlStr = SqlBuilder.InsertSQL<T>(entity);//语句SqlParameter[] parameter = SqlParameters.NoID(entity);//参数List<CmdData> list = new List<CmdData>();list.Add(new CmdData(SqlStr, parameter));int rst = (int)await SqlHelper.MyTran(list, "Edit", true);return rst > 0;}/// <summary>/// 单改/// </summary>public static async Task<bool> Update<T>(T entity){string SqlStr = SqlBuilder.UpdateSQL<T>(entity);SqlParameter[] parameters = SqlParameters.HaveId(entity);List<CmdData> list = new List<CmdData>();list.Add(new CmdData(SqlStr, parameters));int rst = (int)await SqlHelper.MyTran(list, "Edit", true);return rst > 0;}/// <summary>/// 单删/// </summary>public static async Task<bool> Delete<T>(T entity){string SqlStr = SqlBuilder.DeleteSQL<T>(entity);SqlParameter[] parameters = SqlParameters.OnlyID(entity);List<CmdData> list = new List<CmdData>();list.Add(new CmdData(SqlStr, parameters));int rst = (int)await SqlHelper.MyTran(list, "Edit", true);return rst > 0;}/// <summary>/// 单查=>Entity/// </summary>public static async Task<T> GetModel<T>(int id) where T : new(){string SqlStr = SqlBuilder.SelectSQL<T>(id.ToString());List<CmdData> list = new List<CmdData>();list.Add(new CmdData(SqlStr, null));DataSet ds = (DataSet)await SqlHelper.MyTran(list, "QueryDs", true);if (ds.Tables[0].Rows.Count > 0)return SqlOrm.ToEntity<T>(ds.Tables[0].Rows[0]);else return new T();}#endregion#region  扩展 Extend/// <summary>/// 批量增/// </summary>public static async Task<bool> Adds<T>(List<T> listT){List<CmdData> list = new List<CmdData>();foreach (var entity in listT){string SqlStr = SqlBuilder.InsertSQL<T>(entity);//语句SqlParameter[] parameter = SqlParameters.NoID(entity);//参数list.Add(new CmdData(SqlStr, parameter));}int rst = (int)await SqlHelper.MyTran(list, "Edit", true);return rst > 0;}/// <summary>/// 批改/// </summary>public static async Task<bool> Updates<T>(List<T> listT){List<CmdData> list = new List<CmdData>();foreach (var entity in listT){string SqlStr = SqlBuilder.UpdateSQL<T>(entity);SqlParameter[] parameter = SqlParameters.HaveId(entity);list.Add(new CmdData(SqlStr, parameter));}int rst = (int)await SqlHelper.MyTran(list, "Edit", true);return rst > 0;}/// <summary>/// 批删/// </summary>public static async Task<bool> Deletes<T>(List<T> listT){List<CmdData> list = new List<CmdData>();foreach (var entity in listT){string SqlStr = SqlBuilder.DeleteSQL<T>(entity);SqlParameter[] parameters = SqlParameters.OnlyID(entity);list.Add(new CmdData(SqlStr, parameters));}int rst = (int)await SqlHelper.MyTran(list, "Edit", true);return rst > 0;}/// <summary>/// 单增 返回ID/// </summary>public static async Task<int> Add_ID<T>(T entity){string SqlStr = SqlBuilder.InsertSQL_id<T>(entity);//语句SqlParameter[] parameters = SqlParameters.NoID(entity);//参数List<CmdData> list = new List<CmdData>();list.Add(new CmdData(SqlStr, parameters));return (int)await SqlHelper.MyTran(list, "QueryInt", true);}/// <summary>/// 条件查询/// </summary>/// <returns></returns>public static async Task<DataSet> GetList<T>(string strWhere) where T : new(){string SqlStr = SqlBuilder.ListSQL<T>(strWhere);List<CmdData> list = new List<CmdData>();list.Add(new CmdData(SqlStr, null));return (DataSet)await SqlHelper.MyTran(list, "QueryDs", true);}/// <summary>/// 条件查询=》多Entity/// </summary>public static async Task<List<T>> GetModelList<T>(string strWhere) where T : new(){DataSet ds = await GetList<T>(strWhere);List<T> rst = new List<T>();if (ds.Tables[0].Rows.Count > 0){ds.Tables[0].Rows.Cast<DataRow>().ToList().ForEach(p =>{rst.Add(SqlOrm.ToEntity<T>(p));});}return rst;}/// <summary>/// 条件查询=》条数/// </summary>public static async Task<int> RecordCount<T>(string strWhere) where T : new(){string SqlStr = SqlBuilder.ListSQL<T>(strWhere);List<CmdData> list = new List<CmdData>();list.Add(new CmdData(SqlStr, null));return (int)await SqlHelper.MyTran(list, "QueryInt", true);}/// <summary>/// 分页/// </summary>public static async Task<DataSet> GetListByPage<T>(string strWhere, string orderby, int startIndex, int endIndex) where T : new(){string SqlStr = SqlBuilder.ByPageSQL<T>(strWhere, orderby, startIndex, endIndex);List<CmdData> list = new List<CmdData>();list.Add(new CmdData(SqlStr, null));return (DataSet)await SqlHelper.MyTran(list, "QueryDs", true);}/// <summary>/// 存储过程/// </summary>public static async Task<DataSet> ExecProc(StoredProcs proc){// return (DataSet)await SqlHelper.MyTran(SqlStr, null, "Query", 1);string SqlStr = SqlBuilder.ProcSQL(proc);//语句List<CmdData> list = new List<CmdData>();list.Add(new CmdData(SqlStr, null));return (DataSet)await SqlHelper.MyTran(list, "Edit", false);//不启动事务}#endregion}}

八、总结

5个类完成了自己在 .net8 中的ORM. 不是太复杂。
我的想法是前端传回json到API ,解析成modelList 完成批量的增删改,联表这种数据量大的就丢到存储过程里去把。

//调用存储过程示例
public static async Task<DataSet> MyProc()
{StoredProc proc = new StoredProc();proc.Name = "SP_Test";proc.param.Add(new ProcParam("createtime", "2025-0-13"));proc.param.Add(new ProcParam("name", "张三"));proc.param.Add(new ProcParam("class", "2年纪"));return await Access.ExecProc(proc);
}
//批量修改示例public static async Task<bool> Updates<Users>(string JsonStr){List<Users> List = JsonConvert.DeserializeObject<List<Users>>(JsonStr);return await Access.Updates<Users>(List);}
//分页查询示例public static async Task<string> GetListByPage<User>(){DataSet ds= await Access.GetListByPage<User> ("name like '%张%'"," createtme desc",  101,  200);string JsonStr=JsonConvert.SerializeObject(ds.tables[0]);return JsonStr;}

相关文章:

.NET8关于ORM的一次思考

文章目录 前言一、思路二、实现ODBC>SqlHelper.cs三、数据对象实体化四、SQL生成SqlBuilder.cs五、参数注入 SqlParameters.cs六、反射 SqlOrm.cs七、自定义数据查询八、总结 前言 琢磨着在.NET8找一个ORM&#xff0c;对比了最新的框架和性能。 框架批量操作性能SQL控制粒…...

LlamaIndex 第八篇 MilvusVectorStore

本指南演示了如何使用 LlamaIndex 和 Milvus 构建一个检索增强生成&#xff08;RAG&#xff09;系统。 RAG 系统将检索系统与生成模型相结合&#xff0c;根据给定的提示生成新的文本。该系统首先使用 Milvus 等向量相似性搜索引擎从语料库中检索相关文档&#xff0c;然后使用生…...

记录为什么LIst数组“增删慢“,LinkedList链表“查改快“?

数组&#xff08;Array&#xff09; 增删慢&#xff1a;对于数组来说&#xff0c;增加或删除元素的操作可能会比较慢&#xff0c;特别是当你需要在数组的开头或中间进行这些操作时。这是因为这些操作通常需要移动数组中的其他元素以保持连续性。例如&#xff0c;如果你想要在数…...

【论文阅读】Dip-based Deep Embedded Clustering with k-Estimation

摘要 近年来&#xff0c;聚类与深度学习的结合受到了广泛关注。无监督神经网络&#xff0c;如自编码器&#xff0c;能够自主学习数据集中的关键结构。这一思想可以与聚类目标结合&#xff0c;实现对相关特征的自动学习。然而&#xff0c;这类方法通常基于 k-means 框架&#x…...

ARFoundation 图片识别,切换图片克隆不同的追踪模型

场景搭建&#xff1a; 你可以把我的代码发给AI&#xff0c;去理解 using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.XR; using UnityEngine.XR.ARFoundation; using UnityEngine.XR.ARSubsystems; using TMPro; using Unit…...

鸿蒙next播放B站视频横屏后的问题

&#xff08;此文讨论范围为b站视频链接&#xff0c;且不包括b站直播链接&#xff1b;android/iOS的webview播放b站视频完全没有这么多问题&#xff09; 1、竖屏播放没问题 从一个竖屏页p1点击进入视频页p2&#xff0c;p2页仍为竖屏&#xff1b; p2页有一Web组件&#xff0c;…...

华为0507机试

题目二 建设基站 有一棵二叉树&#xff0c;每个节点上都住了一户居民。现在要给这棵树上的居民建设基站&#xff0c;每个基站只能覆盖她所在与相邻的节点&#xff0c;请问信号覆盖这棵树最少需要建设多少个基站 #include <bits/stdc.h> using namespace std;const int …...

apache2的默认html修改

使用127.0.0.1的时候&#xff0c;默认打开的是index.html&#xff0c;可以通过配置文件修改成我们想要的html vi /etc/apache2/mods-enabled/dir.conf <IfModule mod_dir.c>DirectoryIndex WS.html index.html index.cgi index.pl index.php index.xhtml index.htm <…...

EXCEL下拉菜单与交替上色设置

Excel/WPS 表格操作教程&#xff08;双功能整合&#xff09; 目录 功能一&#xff1a;交替行上色 Excel 操作WPS 操作 功能二&#xff1a;下拉菜单设置 Excel 操作WPS 操作 组合效果示例注意事项 功能一&#xff1a;交替行上色 Excel 操作 选中数据区域 拖动鼠标选择需要设置…...

list基础用法

list基础用法 1.list的访问就不能用下标[]了,用迭代器2.emplace_back()几乎是与push_back()用法一致&#xff0c;但也有差别3.insert(),erase()的用法4.reverse()5.排序6.合并7.unique()&#xff08;去重&#xff09;8.splice剪切再粘贴 1.list的访问就不能用下标[]了,用迭代器…...

鸿蒙PC版体验_画面超级流畅_具备terminal_无法安装windows、linux软件--纯血鸿蒙HarmonyOS5.0工作笔记017

鸿蒙NEXT和开源鸿蒙OpenHarmony现在已经开发实现统一,使用鸿蒙ArkTS开发的应用,可以直接 在开源鸿蒙上. 鸿蒙的terminal是使用的linux的语法,但是有很多命令,目前还不能使用,常用的ifconfig等是可以用的. 鸿蒙终于出来PC版了,虽然,不像Windows以及mac等,开放的命令那么多,但…...

Spring 集成 SM4(国密对称加密)

Spring 集成 SM4&#xff08;国密对称加密&#xff09;算法 主要用于保护敏感数据&#xff0c;如身份证、手机号、密码等。 下面是完整集成步骤&#xff08;含工具类 使用示例&#xff09;&#xff0c;采用 Java 实现&#xff08;可用于 Spring Boot&#xff09;。 一、依赖引…...

deepseek梳理java高级开发工程师微服务面试题

Java微服务高级面试题与答案 一、微服务架构设计 1. 服务拆分原则 Q1&#xff1a;微服务拆分时有哪些核心原则&#xff1f;如何解决拆分后的分布式事务问题&#xff1f; 答案&#xff1a; 服务拆分五大原则&#xff1a; 1. 单一职责原则&#xff08;SRP&#xff09;- 每个…...

人事管理系统8

员工管理&#xff08;分页查询、查看详情页、修改&#xff09;&#xff1a; 1. 分页查询 Staff.java 中加入部门名和岗位名两个属性以及对应的 get 和 set 方法。这两个属性没有数据库字段对应&#xff0c; 仅供前端显示用&#xff1a; private String departname; //部门名属…...

Stapi知识框架

一、Stapi 基础认知 1. 框架定位 自动化API开发框架&#xff1a;专注于快速生成RESTful API 约定优于配置&#xff1a;通过标准化约定减少样板代码 企业级应用支持&#xff1a;适合构建中大型API服务 代码生成导向&#xff1a;显著提升开发效率 2. 核心特性 自动CRUD端点…...

第三章 初始化配置(一)

我们首先介绍配置Logback的方法&#xff0c;并提供了许多示例配置脚本。在后面的章节中&#xff0c;我们将介绍Logback所依赖的配置框架Joran。 初始化配置 在应用程序代码中插入日志请求需要大量的规划和努力。观察表明&#xff0c;大约4%的代码用于记录。因此&#xff0c;即…...

WebGIS 开发中的数据安全与隐私保护:急需掌握的要点

在 WebGIS 开发中&#xff0c;数据安全与隐私保护是绝对不能忽视的问题&#xff01;随着地理信息系统的广泛应用&#xff0c;越来越多的敏感数据被存储和传输&#xff0c;比如个人位置信息、企业地理资产等。一旦这些数据泄露&#xff0c;后果不堪设想。然而&#xff0c;很多开…...

C语言 ——— 函数栈帧的创建和销毁

目录 寄存器 mian 函数是被谁调用的 通过汇编了解函数栈帧的创建和销毁 转汇编后&#xff08;Add函数之前的部分&#xff09; 转汇编后&#xff08;进入Add函数之前的部分&#xff09; 转汇编后&#xff08;正式进入Add函数的部分&#xff09; ​编辑 总结 局部变量…...

2025年真实面试问题汇总(二)

jdbc的事务是怎么开启的 在JDBC中&#xff0c;事务的管理是通过Connection对象控制的。以下是开启和管理事务的详细步骤&#xff1a; 1. 关闭自动提交模式 默认情况下&#xff0c;JDBC连接处于自动提交模式&#xff08;auto-commit true&#xff09;&#xff0c;即每条SQL语…...

【用「概率思维」重新理解生活】

用「概率思维」重新理解生活&#xff1a;为什么你总想找的「确定答案」并不存在&#xff1f; 第1层&#xff1a;生活真相——所有结果都是「综合得分」 现象&#xff1a;我们总想找到“孩子生病是因为着凉”或“伴侣生气是因为那句话”的单一答案现实&#xff1a;每个结果背后…...

Redis——线程模型·

为什么Redis是单线程却仍能有10w/秒的吞吐量&#xff1f; 内存操作&#xff1a;Redis大部分操作都在内存中完成&#xff0c;并且采用了高效的数据结构&#xff0c;因此Redis的性能瓶颈可能是机器的内存或者带宽&#xff0c;而非CPU&#xff0c;既然CPU不是瓶颈&#xff0c;自然…...

APS排程系统(Advanced Planning and Scheduling,高级计划与排程系统)

APS排程系统&#xff08;Advanced Planning and Scheduling&#xff0c;高级计划与排程系统&#xff09;是一种基于供应链管理和约束理论的智能生产管理工具&#xff0c;旨在通过动态优化资源分配和生产流程&#xff0c;解决制造业中的复杂计划问题。以下是其核心要点解析&…...

首个窗口级无人机配送VLN系统!中科院LogisticsVLN:基于MLLM实现精准投递

导读 随着智能物流需求日益增长&#xff0c;特别是“最后一公里”配送场景的精细化&#xff0c;传统地面机器人逐渐暴露出适应性差、精度不足等瓶颈。为此&#xff0c;本文提出了LogisticsVLN系统——一个基于多模态大语言模型的无人机视觉语言导航框架&#xff0c;专为窗户级别…...

仓颉Magic亮相GOSIM AI Paris 2025:掀起开源AI框架新热潮

巴黎&#xff0c;2025年5月6日——由全球开源创新组织GOSIM联合CSDN、1ms.ai共同主办的 GOSIM AI Paris 2025 大会今日在法国巴黎盛大开幕。GOSIM 作为开源人工智能领域最具影响力的年度峰会之一&#xff0c;本届大会以“开放、协作、突破”为核心&#xff0c;汇聚了来自华为、…...

《Effective Python》第2章 字符串和切片操作——深入理解Python 中的字符数据类型(bytes 与 str)的差异

引言 本篇博客基于学习《Effective Python》第三版 Chapter 2: Strings and Slicing 中的 Item 10: Know the Differences Between bytes and str 的总结与延伸。在 Python 编程中&#xff0c;字符串处理是几乎每个开发者都会频繁接触的基础操作。然而&#xff0c;Python 中的…...

windows 强行终止进程,根据端口号

步骤1&#xff1a;以管理员身份启动终端‌ 右键点击开始菜单 → 选择 ‌终端&#xff08;管理员&#xff09;‌ 或 ‌Windows PowerShell&#xff08;管理员&#xff09;‌。 ‌步骤2&#xff1a;检测端口占用状态‌ # 查询指定端口&#xff08;示例为1806&#xff09; netst…...

PHP-FPM 调优配置建议

1、动态模式 pm dynamic; 最大子进程数&#xff08;根据服务器内存调整&#xff09; pm.max_children 100 //每个PHP-FPM进程大约占用30-50MB内存(ThinkPHP框架本身有一定内存开销)安全值&#xff1a;8GB内存 / 50MB ≈ 160&#xff0c;保守设置为100 ; 启动时创建的进程数&…...

我喜欢的vscode几个插件和主题

主题 Monokaione Monokai Python 语义高光支持 自定义颜色为 self 将 class , def 颜色更改为红色 为装饰器修复奇怪的颜色 适用于魔法功能的椂光 Python One Dark 这个主题只在python中效果最好。 我为我个人使用做了这个主题,但任何人都可以使用它。 插件 1.Pylance Pylanc…...

openharmony 地图开发(高德sdk调用)

1.显示地图 2.利用sdk完成搜索功能&#xff0c;以列表形式展示&#xff0c;并提供定位和寻路按钮 3.利用sdk完成寻路&#xff0c;并显示路线信息和画出路线&#xff0c;路线和信息各自点击后可联动到对方信息显示 4.调用sdk 开始导航 商务合作&#xff1a;...

Kotlin-类和对象

文章目录 类主构造函数次要构造函数总结 对象初始化 类的继承成员函数属性覆盖(重写)智能转换 类的扩展 类 class Student { }这是一个类,表示学生,怎么才能给这个类添加一些属性(姓名,年龄…)呢? 主构造函数 我们需要指定类的构造函数。构造函数也是函数的一种,但是它专门…...

LVS+keepalived实战案例

目录 部署LVS 安装软件 创建VIP 创建保存规则文件 给RS添加规则 验证规则 部署RS端 安装软件 页面内容 添加VIP 配置系统ARP 传输到rs-2 客户端测试 查看规则文件 实现keepalived 编辑配置文件 传输文件给backup 修改backup的配置文件 开启keepalived服务 …...

可视化+智能补全:用Database Tool重塑数据库工作流

一、插件概述 Database Tool是JetBrains系列IDE&#xff08;IntelliJ IDEA、PyCharm等&#xff09;内置的数据库管理插件。它提供了从数据库连接到查询优化的全流程支持&#xff0c;让开发者无需离开IDE即可完成数据库相关工作。 核心价值&#xff1a; 统一工作环境&#xf…...

【认知思维】沉没成本谬误:为何难以放弃已投入的资源

什么是沉没成本谬误 沉没成本谬误&#xff08;Sunk Cost Fallacy&#xff09;是指人们倾向于根据过去已经投入的资源&#xff08;时间、金钱、精力等&#xff09;而非未来收益来做决策的一种认知偏差。简单来说&#xff0c;它反映了"我已经投入这么多&#xff0c;不能就这…...

Linux 系统安全基线检查:入侵防范测试标准与漏洞修复方法

Linux 系统安全基线检查&#xff1a;入侵防范测试标准与漏洞修复方法 在 Linux 系统的安全管理中&#xff0c;入侵防范是至关重要的环节。通过对系统进行安全基线检查&#xff0c;可以有效识别潜在的安全漏洞&#xff0c;并采取相应的修复措施&#xff0c;从而降低被入侵的风险…...

【HT周赛】T3.二维平面 题解(分块:矩形chkmax,求矩形和)

题意 需要维护 n n n \times n nn 平面上的整点&#xff0c;每个点 ( x , y ) (x, y) (x,y) 有权值 V ( x , y ) V(x, y) V(x,y)&#xff0c;初始都为 0 0 0。 同时给定 n n n 次修改操作&#xff0c;每次修改给出 x 1 , x 2 , y 1 , y 2 , v x_1, x_2, y_1, y_2, v x…...

目标检测任务常用脚本1——将YOLO格式的数据集转换成VOC格式的数据集

在目标检测任务中&#xff0c;不同框架使用的标注格式各不相同。常见的框架中&#xff0c;YOLO 使用 .txt 文件进行标注&#xff0c;而 PASCAL VOC 则使用 .xml 文件。如果你需要将一个 YOLO 格式的数据集转换为 VOC 格式以便适配其他模型&#xff0c;本文提供了一个结构清晰、…...

2025深圳杯D题法医物证多人身份鉴定问题四万字思路

Word版论文思路和千行Python代码下载&#xff1a;https://www.jdmm.cc/file/2712074/ 引言 法医遗传学中的混合生物样本分析&#xff0c;特别是短串联重复序列&#xff08;Short Tandem Repeat, STR&#xff09;分型结果的解读&#xff0c;是现代刑事侦查和身份鉴定领域的核心…...

利用自适应双向对比重建网络与精细通道注意机制实现图像去雾化技术的PyTorch代码解析

利用自适应双向对比重建网络与精细通道注意机制实现图像去雾化技术的PyTorch代码解析 漫谈图像去雾化的挑战 在计算机视觉领域&#xff0c;图像复原一直是研究热点。其中&#xff0c;图像去雾化技术尤其具有实际应用价值。然而&#xff0c;复杂的气象条件和多种因素干扰使得这…...

Focal Loss 原理详解及 PyTorch 代码实现

Focal Loss 原理详解及 PyTorch 代码实现 介绍一、Focal Loss 背景二、代码逐行解析1. 类定义与初始化 三、核心参数作用四、使用示例五、应用场景六、总结 介绍 一、Focal Loss 背景 Focal Loss 是为解决类别不平衡问题设计的损失函数&#xff0c;通过引入 gamma 参数降低易…...

VScode 的插件本地更改后怎么生效

首先 vscode 的插件安装地址为 C:\Users\%USERNAME%\.vscode\extensions 找到你的插件包进行更改 想要打印日志&#xff0c;用下面方法 vscode.window.showErrorMessage(console.log "${name}" exists.); 打印结果 找到插件&#xff0c;点击卸载 然后点击重新启动 …...

这类物种组织heatmap有点东西

如果想知道研究对象&#xff08;人、小鼠、拟南芥、恒河猴等​​&#xff09;某个时候各个器官的fMRI信号强度、炎症程度等指标的差异&#xff0c;gganatogram可以以热图的形式轻松满足你的需求。 数据准备 以男性为例&#xff0c;数据包含四列&#xff0c; 每列详细介绍 org…...

通讯录程序

假设通讯录可以存放100个人的信息&#xff08;人的信息&#xff1a;姓名、年龄、性别、地址、电话&#xff09; 功能&#xff1a;1>增加联系人 2>删除指定联系人 3>查找指定联系人信息 4>修改指定联系人信息 5>显示所有联系人信息 6>排序&#xff08;…...

无需翻墙!3D 优质前端模板分享

开发网站时&#xff0c;无需撰写 HTML、CSS 和 JavaScript 代码&#xff0c;直接调用模板内现成的组件&#xff0c;通过拖拽组合、修改参数&#xff0c;几天内即可完成核心页面开发&#xff0c;开发速度提升高达 70% 以上。让开发者更专注于业务逻辑优化与功能创新&#xff0c;…...

Shinkai开源程序 是一个双击安装 AI 管理器(本地和远程),它允许您使用简单的 UI 在 5 分钟或更短的时间内创建 AI 代理

​一、软件介绍 文末提供程序和源码下载 Shinkai 开源应用程序在 Web 浏览器中解锁了一流 LLM &#xff08;AI&#xff09; 支持的全部功能/自动化。它允许创建多个代理&#xff0c;每个代理都连接到本地或第三方LLMs&#xff08;例如 OpenAI GPT&#xff09;&#xff0c;这些…...

vscode不能跳转到同一个工作区的其他文件夹

明白了&#xff0c;你说的“第二种情况”是指&#xff1a; 你先打开的是项目文件夹&#xff08;比如 MyProject&#xff09;&#xff0c;然后通过 VS Code 的“添加文件夹到工作区”功能&#xff0c;把 ThirdPartyLib 文件夹添加进来。 结果&#xff0c;项目代码里 #include “…...

containerd 之使用 ctr 和 runc 进行底层容器操作与管理

containerd 是目前业界标准的容器运行时&#xff0c;它负责容器生命周期的方方面面&#xff0c;如镜像管理、容器执行、存储和网络等。而 ctr 是 containerd 自带的命令行工具&#xff0c;虽然不如 Docker CLI 用户友好&#xff0c;但它提供了直接与 containerd API 交互的能力…...

IMU 技术概述

IMU&#xff08;惯性测量单元&#xff0c;Inertial Measurement Unit&#xff09;是一种通过传感器组合测量物体运动状态和姿态的核心设备&#xff0c;广泛应用于导航、控制、智能设备等领域。以下从原理、组成、应用和发展趋势展开说明&#xff1a; 一、核心定义与本质 IMU …...

talk-centos6之间实现

在 CentOS 6.4 上配置和使用 talk 工具&#xff0c;需要注意系统版本较老&#xff0c;很多配置可能不同于现代系统。我会提供 详细步骤 自动化脚本&#xff0c;帮你在两台 CentOS 6.4 机器上实现局域网聊天。 ⸻ &#x1f9f1; 一、系统准备 假设你有两台主机&#xff1a; …...

hivesql是什么数据库?

HiveSQL并非指一种独立的数据库&#xff0c;而是指基于Apache Hive的SQL查询语言接口&#xff0c;Hive本身是一个构建在Hadoop生态系统之上的数据仓库基础设施。 以下是对HiveSQL及其相关概念的详细解释&#xff1a; 一、Hive概述 定义&#xff1a; Hive是由Facebook开发&…...

(1)python开发经验

文章目录 1 安装包格式说明2 PySide支持Windows7 更多精彩内容&#x1f449;内容导航 &#x1f448;&#x1f449;Qt开发 &#x1f448;&#x1f449;python开发 &#x1f448; 1 安装包格式说明 PySide下载地址 进入下载地址后有多种安装包&#xff0c;怎么选择&#xff1a; …...