JRT对历史表和$get实现

由于Cache没有什么表数据大了查询和插入性能下降的问题,而关系库在数据量上千万后会性能下降,之前关注点都是Java业务脚本化和开发部署简单,还没管关系库单表大问题和级联查询复杂后慢的问题,现在开始解决这俩问题,这是第一阶段实现。

首先对单表数据太多导致性能下降的问题还是采用历史表解决,既为主业务建立几个甚至上10个历史表,历史表的主键不自增,然后ORM提供API把数据迁移到历史表。

首先给表注解加上维护历史表的地方和历史数据切割所用的字段:
在这里插入图片描述
实现两个兼容查历史数据的API给业务

/**
     * 根据条件+字段查询,查询结果按指定的页面把数据按List返回。由ORM根据参数决定顺带查询所有历史数据或者最近历史数据,或者不查历史数据
     * 开发者为主业务表建立同结果非自增主键的表来供业务数据往历史表迁移,在实体特性维护所有历史表,历史表按每个存满指定数据后换下一个历史表,
     * ORM按历史表依次调用查询合并结果
     * 以此解决单表数据太大查询和插入慢问题
     * 不分页
     *
     * @param findHisNum  查询历史表的数量,0:不查历史表 大于0的数就是最多查从最近使用历史表往前推的指定数量的历史表
     * @param model       实体对象
     * @param param       查询条件参数,数据列名和值的键对
     * @param orderFields 排序字段,如RowID Desc
     * @param pageSize    页大小。为-1,无条件查所有数据
     * @param pageIndex   第几页。为-1,无条件查询所有数据
     * @param fields      显示字段,为空显示所有列,字段名称以英文','隔开,如:RowID,Code,Name
     * @param joiner      连接符,为空或不给则查询条件以且连接,给的话长度比参数少1
     * @param operators   操作符,为空或不给的话条件以等来判断,给的话与参数长度一致。如!=,<,>
     * @param <T>         限定实体类型
     * @return 查询实体列表List<T>
     */
    public <T> List<T> DolerFindAll(int findHisNum, T model, List<ParamDto> param, String orderFields, int pageSize, int pageIndex, String fields, List<String> joiner, List<String> operators) throws Exception
    {
        //存储返回的对象数据
        List<T> retList = new ArrayList<T>();
        //查询起始行数
        int fromRow = -1;
        //查询结束行数
        int toRow = -1;
        //是否查询全部数据
        boolean findAll = false;
        //记录总行数
        int rowCount = 0;
        //处理显示字段
        if (fields != null && !fields.isEmpty()) {
            fields = "," + fields + ",";
        }
        //如果未传入分页数据其中一个未-1,则认为部分页而查询所有数据
        if (pageIndex == -1 || pageSize == -1) {
            findAll = true;
        }
        //计算查询起始和结束行数
        else {
            fromRow = (pageIndex - 1) * pageSize;
            toRow = pageIndex * pageSize;
        }
        PreparedStatement pstat = null;
        ResultSet rst = null;
        //表信息
        JRT.DAL.ORM.Common.TableInfo tableInfo = JRT.DAL.ORM.Common.ModelToSqlUtil.GetTypeInfo(model);
        List<TableInfo> findTableList=new ArrayList<>();
        findTableList.add(tableInfo);
        if(findHisNum>0)
        {
            String HisTableName=tableInfo.TableInfo.HisTableName();
            if(!HisTableName.isEmpty())
            {
                String [] HisTableNameArr=HisTableName.split("^");
                boolean StartCal=false;
                for(int h=HisTableNameArr.length-1;h>=0;h--)
                {
                    String HisModelName=HisTableNameArr[h];
                    Class cHis = GetTypeByName(HisModelName);
                    if (cHis != null) {
                        Object oHis = cHis.getConstructor().newInstance();
                        String UseHisTableName=TryGetUseHisTableName(model.getClass().getSimpleName(),oHis);
                        if(UseHisTableName!=null&&!UseHisTableName.isEmpty())
                        {
                            StartCal=true;
                        }
                        if(StartCal==true&&findHisNum>0) {
                            findHisNum--;
                            TableInfo tableInfoHis = JRT.DAL.ORM.Common.ModelToSqlUtil.GetTypeInfo(oHis);
                            findTableList.add(tableInfoHis);
                        }
                    }
                }
                //所有的历史表都没数据那么认为第一个历史表在用
                if(StartCal==false)
                {
                    CurHisTable.put(model.getClass().getSimpleName(),"");
                }
            }
        }
        //循环查多个表的数据
        for(TableInfo tbInfo:findTableList) {
            //根据表信息将查询参数组装成Select SQL
            String sql = JRT.DAL.ORM.Common.ModelToSqlUtil.GetSelectSqlByTableInfo(Manager().GetIDbFactory(factoryName), tbInfo, param, operators, joiner, orderFields, false, -1);
            //写SQL日志
            JRT.Core.Util.LogUtils.WriteSqlLog("执行QueryAll返回List<T>查询SQL:" + sql);
            Class<?> clazzz = model.getClass();
            try {
                pstat = Manager().Connection().prepareStatement(sql);
                String paraSql = DBParaUtil.SetDBPara(pstat, param);
                rst = pstat.executeQuery();
                JRT.Core.Util.LogUtils.WriteSqlLog("参数:" + paraSql);
                while (rst.next()) {
                    rowCount++;     //总行数加一
                    //查询全部,或者取分页范围内的记录
                    if (findAll || (rowCount > fromRow && rowCount <= toRow)) {
                        T obj = (T) clazzz.getConstructor().newInstance();
                        for (int coli = 0; coli < tbInfo.ColList.size(); coli++) {
                            String name = tbInfo.ColList.get(coli).Name;
                            Object value = rst.getObject(name);
                            JRT.Core.Util.ReflectUtil.SetObjValue(obj, name, value);
                        }
                        retList.add(obj);
                    }
                }
            } catch (Exception ex) {
                //查询异常清空数据
                retList.clear();
                throw ex;
            }
            //操作结束释放资源,但是不断连接,不然没法连续做其他数据库操作了
            finally {
                if (rst != null) {
                    rst.close();
                }
                if (pstat != null) {
                    pstat.close();
                }
                //如果上层调用未开启事务,则调用结束释放数据库连接
                if (!Manager().Hastransaction) {
                    manager.Close();
                }
            }
        }
        return retList;
    }


    /**
     * 根据条件+字段查询,查询结果按指定的页面把数据按JSON返回;
     * 开发者为主业务表建立同结果非自增主键的表来供业务数据往历史表迁移,在实体特性维护所有历史表,历史表按每个存满指定数据后换下一个历史表
     * ORM按历史表依次调用查询合并结果
     * 以此解决单表数据太大查询和插入慢问题
     * 该方法不带分页
     * @param findHisNum  查询历史表的数量,0:不查历史表 大于0的数就是最多查从最近使用历史表往前推的指定数量的历史表
     * @param model       实体对象
     * @param param       查询条件参数,数据列名和值的键对
     * @param orderFields 排序字段,如RowID Desc
     * @param returnCount 是否输出数据总行数
     * @param pageSize    页大小。为-1,无条件查所有数据
     * @param pageIndex   第几页。为-1,无条件查询所有数据
     * @param fields      显示字段,为空显示所有列,字段名称以英文','隔开,如:RowID,Code,Name
     * @param joiner      连接符,为空或不给则查询条件以且连接,给的话长度比参数少1
     * @param operators   操作符,为空或不给的话条件以等来判断,给的话与参数长度一致。如!=,<,>
     * @param top         查询返回的行数,-1就返回所有行
     * @return 查询json串
     */
    public <T> String DolerQueryAllTop(int findHisNum,T model, List<ParamDto> param, String orderFields, boolean returnCount, int pageSize, int pageIndex, String fields, List<String> joiner, List<String> operators, int top) throws Exception
    {
        //json数据组装容器
        StringBuilder jsonsb = new StringBuilder();
        //查询起始行数
        int fromRow = -1;
        //查询结束行数
        int toRow = -1;
        //是否查询全部数据
        boolean findAll = false;
        //记录总行数
        int rowCount = 0;
        //处理显示字段
        if (fields != null && !fields.isEmpty()) {
            fields = "," + fields + ",";
        }
        //如果未传入分页数据其中一个未-1,则认为部分页而查询所有数据
        if (pageIndex == -1 || pageSize == -1) {
            findAll = true;
        }
        //计算查询起始和结束行数
        else {
            fromRow = (pageIndex - 1) * pageSize;
            toRow = pageIndex * pageSize;
        }
        PreparedStatement pstat = null;
        ResultSet rst = null;
        JRT.DAL.ORM.Common.TableInfo tableInfo = JRT.DAL.ORM.Common.ModelToSqlUtil.GetTypeInfo(model);
        List<TableInfo> findTableList=new ArrayList<>();
        findTableList.add(tableInfo);
        if(findHisNum>0)
        {
            String HisTableName=tableInfo.TableInfo.HisTableName();
            if(!HisTableName.isEmpty())
            {
                String [] HisTableNameArr=HisTableName.split("^");
                boolean StartCal=false;
                for(int h=HisTableNameArr.length-1;h>=0;h--)
                {
                    String HisModelName=HisTableNameArr[h];
                    Class cHis = GetTypeByName(HisModelName);
                    if (cHis != null) {
                        Object oHis = cHis.getConstructor().newInstance();
                        String UseHisTableName=TryGetUseHisTableName(model.getClass().getSimpleName(),oHis);
                        if(UseHisTableName!=null&&!UseHisTableName.isEmpty())
                        {
                            StartCal=true;
                        }
                        if(StartCal==true&&findHisNum>0) {
                            findHisNum--;
                            TableInfo tableInfoHis = JRT.DAL.ORM.Common.ModelToSqlUtil.GetTypeInfo(oHis);
                            findTableList.add(tableInfoHis);
                        }
                    }
                }
                //所有的历史表都没数据那么认为第一个历史表在用
                if(StartCal==false)
                {
                    CurHisTable.put(model.getClass().getSimpleName(),HisTableNameArr[0]);
                }
            }
        }
        //如果返回总行数,返回总行数写法
        if (returnCount) {
            jsonsb.append("{");
            jsonsb.append("\"rows\":[");
        }
        //否则采用普通数组写法
        else {
            jsonsb.append("[");
        }
        StringBuilder rowAllsb = new StringBuilder();
        //循环查多个表的数据
        for(TableInfo tbInfo:findTableList) {
            //根据表信息将查询参数组装成Select SQL
            String sql = JRT.DAL.ORM.Common.ModelToSqlUtil.GetSelectSqlByTableInfo(Manager().GetIDbFactory(factoryName), tbInfo, param, operators, joiner, orderFields, false, top);
            //写SQL日志
            JRT.Core.Util.LogUtils.WriteSqlLog("执行QueryAll返回String查询SQL:" + sql);

            try {
                pstat = Manager().Connection().prepareStatement(sql);
                String paraSql = DBParaUtil.SetDBPara(pstat, param);
                rst = pstat.executeQuery();
                JRT.Core.Util.LogUtils.WriteSqlLog("参数:" + paraSql);
                //标识是否第一行
                boolean isFirstRow = true;
                while (rst.next()) {
                    rowCount++;     //总行数加一
                    //查询全部,或者取分页范围内的记录
                    if (findAll || (rowCount > fromRow && rowCount <= toRow)) {
                        ResultSetMetaData metaData = rst.getMetaData();
                        //获取列数
                        int colCount = metaData.getColumnCount();
                        //单行数据容器
                        StringBuilder rowsb = new StringBuilder();
                        rowsb.append("{");
                        //标识是否第一列
                        boolean isFirstCol = true;
                        for (int coli = 1; coli <= colCount; coli++) {
                            //获取列名
                            String colName = metaData.getColumnName(coli);
                            //获取列值
                            Object colValue = rst.getObject(coli);
                            if (colValue == null) colValue = "";
                            //如果传了显示的字段,过滤不包含的字段
                            if (fields != null && !fields.isEmpty() && fields.indexOf("," + colName + ",") < 0) {
                                continue;
                            }
                            if (isFirstCol) {
                                rowsb.append("\"" + colName + "\":");
                                rowsb.append("\"" + colValue + "\"");
                                isFirstCol = false;
                            } else {
                                //非第一列插入","
                                rowsb.append(",");
                                rowsb.append("\"" + colName + "\":");
                                rowsb.append("\"" + colValue + "\"");
                            }
                        }
                        rowsb.append("}");
                        if (isFirstRow) {
                            rowAllsb.append(rowsb.toString());
                            isFirstRow = false;
                        } else {
                            rowAllsb.append(",");
                            rowAllsb.append(rowsb.toString());
                        }
                    }
                }
            } catch (Exception ex) {
                //查询异常清空数据记录容器
                rowAllsb.delete(0, rowAllsb.length());
                throw ex;
            }
            //操作结束释放资源,但是不断连接,不然没法连续做其他数据库操作了
            finally {
                if (rst != null) {
                    rst.close();
                }
                if (pstat != null) {
                    pstat.close();
                }
                //如果上层调用未开启事务,则调用结束释放数据库连接
                if (!Manager().Hastransaction) {
                    manager.Close();
                }
            }
        }
        //组装数据记录
        jsonsb.append(rowAllsb.toString());
        //补充数组结尾符
        jsonsb.append("]");
        if (returnCount) {
            jsonsb.append(",");
            jsonsb.append("\"total\":");
            jsonsb.append(rowCount);
            jsonsb.append("}");
        }
        return jsonsb.toString();
    }

对应$get的实现,首先抽取节点对象,记录每个数据的时间

package JRT.DAL.ORM.Global;

/**
 * 一个global的管理节点
 */
public class OneGlobalNode {
    /**
     * Java内部时间
     */
    public Long Time;

    /**
     * 对象数据
     */
    public Object Data;
}

实现缓存管理

package JRT.DAL.ORM.Global;

import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.atomic.AtomicInteger;

import JRT.Core.MultiPlatform.JRTConfigurtaion;
import JRT.Core.Util.LogUtils;
import JRT.DAL.ORM.Global.OneGlobalNode;

/**
 * 实现内存模拟global的效果
 */
public class GlobalManager {
    /**
     * 在内存里缓存热点数据
     */
    private static ConcurrentHashMap<String, ConcurrentHashMap<String, OneGlobalNode>> AllHotData = new ConcurrentHashMap<>();

    /**
     * 要缓存数据的队列
     */
    private static ConcurrentLinkedDeque TaskQuen = new ConcurrentLinkedDeque();

    /**
     * 管理缓存的定时器
     */
    private static Timer ManageTimer = new Timer();

    /**
     * 缓存的最大对象数量
     */
    public static Integer GlobalCacheNum = 100000;

    /**
     * 当前的缓存数量
     */
    private static AtomicInteger CurCacheNum=new AtomicInteger(0);

    /**
     * 最后删除数据的时间
     */
    private static Long LastDeleteTime=null;

    /**
     * 加入缓存,直接缓存,具体的后续有缓存管理器线程维护缓存,这里只管加入队列即可
     *
     * @param obj
     * @throws Exception
     */
    public static void InCache(Object obj) throws Exception{
        TaskQuen.add(JRT.Core.Util.JsonUtil.CloneObject(obj));
    }

    /**
     * 通过主键查询数据
     * @param model
     * @param id
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T> T DolerGet(T model,Object id) throws Exception
    {
        //实体的名称
        String modelName = model.getClass().getName();
        if(AllHotData.containsKey(modelName))
        {
            //命中数据,克隆返回
            if(AllHotData.get(modelName).containsKey(id))
            {
                Object obj=JRT.Core.Util.JsonUtil.CloneObject(AllHotData.get(modelName).get(id));
                return (T)obj;
            }
        }
        return null;
    }

    /**
     * 启动缓存数据管理的线程
     */
    public static void StartGlobalManagerTask() throws Exception{
        //最大缓存数量
        String GlobalCacheNumConf = JRTConfigurtaion.Configuration("GlobalCacheNum");
        if (GlobalCacheNumConf != null && !GlobalCacheNumConf.isEmpty()) {
            GlobalCacheNum = JRT.Core.Util.Convert.ToInt32(GlobalCacheNumConf);
        }
        //定时任务
        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                try {
                    //缓存队列的数据并入缓存
                    while (TaskQuen.size() > 0) {
                        //处理要加入缓存的队列
                        DealOneDataQuen();
                    }
                    //清理多余的缓存数据,这里需要讲究算法,要求在上百万的缓存数据里快速找到时间最久远的数据
                    if(CurCacheNum.get()>GlobalCacheNum)
                    {
                        //每轮清理时间处于上次清理时间和当前时间前百分之5的老数据
                        long Diff=(JRT.Core.Util.TimeParser.GetTimeInMillis()-LastDeleteTime)/20;
                        //留下数据的最大时间
                        long LeftMaxTime=LastDeleteTime+Diff;
                        //遍历所有的热点数据
                        for (String model : AllHotData.keySet()) {
                            ConcurrentHashMap<String, OneGlobalNode> oneTableHot=AllHotData.get(model);
                            //记录要删除的数据
                            List<String> delList=new ArrayList<>();
                            for (String key : oneTableHot.keySet()) {
                                OneGlobalNode one=oneTableHot.get(key);
                                //需要删除的数据
                                if(one.Time<LeftMaxTime)
                                {
                                    delList.add(key);
                                }
                            }
                            //移除时间久的数据
                            for(String del:delList)
                            {
                                oneTableHot.remove(del);
                            }
                        }
                    }
                    //清理时间久远的缓存数据
                } catch (Exception ex) {
                    LogUtils.WriteExceptionLog("处理Global缓存异常", ex);
                }
            }
        };
        ManageTimer.schedule(timerTask, 0, 500);
    }


    /**
     * 处理队列里的一条数据并入缓存
     */
    private static void DealOneDataQuen() {
        try {
            Object obj = TaskQuen.pop();
            if (obj != null) {
                JRT.DAL.ORM.Common.TableInfo tableInfo = JRT.DAL.ORM.Common.ModelToSqlUtil.GetTypeInfo(obj);
                //实体的名称
                String modelName = obj.getClass().getName();
                //得到数据的主键
                String id = tableInfo.ID.Value.toString();
                if (!AllHotData.containsKey(modelName)) {
                    ConcurrentHashMap<String, OneGlobalNode> map = new ConcurrentHashMap<>();
                    AllHotData.put(modelName, map);
                }
                //更新数据
                if (AllHotData.get(modelName).containsKey(id)) {
                    AllHotData.get(modelName).get(id).Data = obj;
                    AllHotData.get(modelName).get(id).Time = JRT.Core.Util.TimeParser.GetTimeInMillis();
                }
                //加入到缓存
                else {
                    OneGlobalNode node = new OneGlobalNode();
                    node.Data = obj;
                    node.Time = JRT.Core.Util.TimeParser.GetTimeInMillis();
                    AllHotData.get(modelName).put(id, node);
                    //缓存数量加1
                    CurCacheNum.addAndGet(1);
                    //记录时间
                    if(LastDeleteTime==null)
                    {
                        LastDeleteTime=JRT.Core.Util.TimeParser.GetTimeInMillis();
                    }
                }
            }
        } catch (Exception ex) {
            LogUtils.WriteExceptionLog("处理Global缓存添加异常", ex);
        }
    }
}

实现DolerGet方法

/**
     * 通过主键查询数据,带缓存的查询,用来解决关系库的复杂关系数据获取,顶替Cache的$g
     * @param model 实体
     * @param id 主键
     * @param <T>
     * @return
     * @throws Exception
     */
    public <T> T DolerGet(T model,Object id) throws Exception
    {
        T ret=GlobalManager.DolerGet(model,id);
        //命中缓存直接返回
        if(ret!=null)
        {
            return ret;
        }
        else
        {
            //调用数据库查询
            ret=GetById(model,id);
            //通知存入缓存
            GlobalManager.InCache(ret);
        }
        return ret;
    }

修改数据的API尝试把实体推入缓存队列
在这里插入图片描述
对事务时候在提交事务才推入缓存队列
在这里插入图片描述

在这里插入图片描述

网站初始化时候启动缓存管理器
在这里插入图片描述
配置缓存数量和历史表换表的大小
在这里插入图片描述

这样以一天标本两万的客户算,缓存两天的热点数据应该不会超过100万,和Global一样的给他10-20G的内存做缓存用就行了,这样理论上应该可以在SQL查询的主业务数据后其他分支数据都借助DolerGet得到数据,这里ORM增、删、改方法还没调加入缓存逻辑,增删改之后调用GlobalManager.InCache(ret);再结合TCP通知主站点分发增、删、改信息后更新缓存,缓存能命中的数据就百分百是准确的最新数据,就能达到极高的Get效率,解决关系库复杂维护的问题,思想上高度借鉴Global的$get和缓存思想。缓存的难点一直是怎么把热点数据挑出来,而通过自己实现ORM,然后增、删、改和DolerGet的数据都抛入缓存队列,就可以准确得到热点数据,因为修改的数据和DolerGet请求的数据本身就是最近活动的,然后缓存管理器再把业务放入队列的数据并入缓存,同时清理时间久远的数据,这样内存里的数据就停了的都是热点。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

socket 一个完整的不错的示例

从客户端向服务器端发送信息时&#xff0c;在服务器端有打印显示&#xff1b; 检测环境常用&#xff0c;备份一下 0&#xff0c;公共头文件代码 //config.h#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #inc…

人工智能的影响与挑战

人工智能是指通过模拟人类智能的各种特性和功能的技术和系统。对于普通大众来说&#xff0c;人工智能的爆发效应还是来源于chatGPT的爆火&#xff0c;大家第一次有了强烈的惊叹和危机。实际上&#xff0c;人工智能已经发展多年&#xff0c;像GPT的发展可以追溯到2018年&#xf…

深度学习笔记《一》:keras_core.layers.Conv2D()

一、说明 卷积&#xff0c;池化&#xff0c;激活函数&#xff0c;这三者号称是深度神经网络的三驾马车&#xff1b;其中卷积是最复杂的一个&#xff0c;因此&#xff0c;对卷积这个东西需要精心认知&#xff0c;这样对后面学习大有帮助。本篇为系列博文&#xff0c;专门介绍Cer…

亮相史上规模最大高交会,Coremail展现邮件技术创新实力

11月19日&#xff0c;第二十五届中国国际高新技术成果交易会在深圳落下帷幕&#xff0c;作为国内邮件行业引领者&#xff0c;Coremail受邀参展。 展览现场&#xff0c;Coremail邮件解决方案及系列产品受到了众多参观者与业内人士的关注与好评。Coremail XT6邮件系统技术成熟&a…

Arcgis根据样本点的shp文件创建一定范围的圆

导入样本点和数据 在ArcToolbox中&#xff0c;找到 "Analysis Tools" -> "Proximity" -> "Buffer" 工具。&#xff08;"分析工具" -> "邻近性" -> "缓冲区" &#xff09; 导入样本点shp文件&#xff…

智能优化算法应用:基于教与学算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于教与学算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于教与学算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.教与学算法4.实验参数设定5.算法结果6.参考文献7.…

8 款强大工具适合 Python 入门的你

Python是一种开源的编程语言&#xff0c;可用于Web编程、数据科学、人工智能以及许多科学应用。学习Python可以让程序员专注于解决问题&#xff0c;而不是语法。由于Python相对较小&#xff0c;且拥有各式各样的工具&#xff0c;因此比Java和C等语言更具优势&#xff0c;同时丰…

技术必备:接口自动化测试数据校验神器【JSonPath】

我们今天不讲如何开发一款自定义开发校验规则库&#xff0c;而是给大家分享一款在开发自定义校验规则库或者常规的接口自动化测试时&#xff0c;经常会用到的一款数据提取神器&#xff1a;JSonPath。 1. JSonPath介绍 JSonPath是一种简单的方法来提取给定JSON文档的部分内容。…

全网最全卡方检验汇总

一文整理了卡方检验全部内容&#xff0c;包括卡方检验的定义&#xff08;基本思想、卡方值计算、适用条件分析&#xff09;、卡方检验分类&#xff08;2*2四格表卡方、R*C表格卡方、配对卡方、卡方拟合优度检验、分层卡方&#xff09;、卡方检验如何分析&#xff08;数据格式、…

银行合规知识竞赛要怎么策划才高大上

合规是银行业务永恒的主题&#xff0c;也是银行发展的根本保障。加强合规知识的学习和理解是保障银行业务健康发展的基础。通过竞赛形式的开展&#xff0c;旨在增强员工对风险和合规的敏感度和关注度&#xff0c;推动全行合规水平全面提升。那么如何策划一场高水平的银行合规知…

尤鲁都斯巴格镇社工站开展“我的牙齿我爱护”儿童公益活动

为了提高儿童的口腔健康意识&#xff0c;尤鲁都斯巴格镇社工站于2023年11月20日在尤鲁都斯巴格镇第一小学开展了一场《我的牙齿我爱护》儿童公益活动。本次活动主要针对小学阶段的儿童&#xff0c;旨在通过口腔健康宣讲等形式&#xff0c;普及口腔保健知识&#xff0c;引导孩子…

鸿蒙原生应用/元服务开发-AGC分发如何生成密钥和和证书请求文件

HarmonyOS通过数字证书&#xff08;.cer文件&#xff09;和Profile文件&#xff08;.p7b文件&#xff09;等签名信息来保证应用的完整性&#xff0c;应用如需上架到华为应用市场必须通过签名校验。因此&#xff0c;开发者需要使用发布证书和Profile文件对应用进行签名后才能发布…

C语言:编程实现1!+2!+3!+4!+……+n!

分析&#xff1a; #include<stdio.h>//这是一个预处理指令&#xff0c;将stdio.h头文件包含到程序中&#xff0c;以便使用输入输出函数。 int main()//这是程序的主函数&#xff0c;是程序执行的入口点。 int i, a 1, t 0, n;//定义了整型变量i、a、t和n。其中&#x…

C/C++ 发送与接收HTTP/S请求

HTTP&#xff08;Hypertext Transfer Protocol&#xff09;是一种用于传输超文本的协议。它是一种无状态的、应用层的协议&#xff0c;用于在计算机之间传输超文本文档&#xff0c;通常在 Web 浏览器和 Web 服务器之间进行数据通信。HTTP 是由互联网工程任务组&#xff08;IETF…

邮件群发:避免垃圾邮箱,提升营销效果

群发邮件为什么会进入垃圾邮箱呢&#xff1f;常见的原因有&#xff1a;邮件内容出现问题、域名和IP的信誉度不高、退订数或投诉过多等原因。所以&#xff0c;营销人员在做EDM的时候&#xff0c;应该把握方式技巧&#xff0c;才能获取良好的营销效果&#xff0c;避免邮件成为垃圾…

工具 | docker删除不使用的容器

工具 | docker删除不使用的容器 Docker 清理命令

java.sql.SQLException: No suitable driver 问题解决

问题出现 自己在写一个连接C3P0数据库连接池库的测试类&#xff0c;运行该类后出现了下图这个问题 这是我写的测试类 package demo;import com.mchange.v2.c3p0.ComboPooledDataSource;import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLExcept…

【密码学引论】密码学的基本概念

第二章 密码学的基本概念 1、密码学定义 密码编制学和密码分析学共同组成密码学 密码编制学&#xff1a;研究密码编制密码分析学&#xff1a;研究密码破译 2、密码体制的五个组成部分 明文空间M&#xff0c;全体明文的集合密文空间C&#xff0c;全体密文的集合密钥空间K&am…

【Linux系统编程】进程概念详解(什么是进程?如何查看进程?)

目录 一、前言 二、 什么是进程&#xff1f; &#x1f4a6;引出进程 &#x1f4a6;进程的基本概念 &#x1f4a6;理解进程 ⭐描述进程--PCB&#xff08;进程控制块&#xff09; ⭐组织进程 三、查看进程 &#x1f4a6; 通过 ps 命令查看进程 &#x1f4a6; 通过 l…

怎么判断香港服务器的性能好不好?

随着互联网的不断发展&#xff0c;越来越多的人开始使用香港服务器来搭建自己的网站或者应用。但是&#xff0c;对于初次使用香港服务器的用户来说&#xff0c;往往会遇到一个问题&#xff1a;怎么判断香港服务器的性能好不好? 首先我们需要了解香港服务器的性能主要取决于哪些…