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

学习记录:DAY23

项目开发与学习记录:字段注入优化

前言


我总有一种什么大的要来了的危机感。还是尽快把项目做起来吧,现在全在弄底层的框架。这是一个两天的blog,前一天bug没修好,气到连blog都没写。

日程


5月7日

  • 晚上7点:本来想玩游戏的,但转念一想,还是学习吧。
  • 晚上9点:做完blog后针对并发安全性进行了优化,看看网课,补补学科内容。

学习记录


计算机网络

  1. CIDR
  2. 路由聚合

操作系统

  1. 虚拟内存
  2. 请求分页管理:缺页中断结构
  3. 页面置换算法

学习内容


省流

  1. params字段注入

1. params字段注入

这部分要完成的任务看上去比较简单。这是原来的手动注入模式:

String sql = "UPDATE movies SET " +"title = COALESCE(?, title), " +"release_date = COALESCE(?, release_date), " +"poster_url = COALESCE(?, poster_url), " +"duration = COALESCE(?, duration), " +"genre = COALESCE(?, genre), " +"rating = COALESCE(?, rating), " +"status = COALESCE(?, status), " +"updated_at = NOW() " +"WHERE id = ?";
JdbcUtils.executeUpdate(sql,movie.getTitle(),movie.getReleaseDate(),movie.getPosterUrl(),movie.getDuration(),movie.getGenre(),movie.getRating(),movie.getStatus(),movie.getId());

目标是将SQL改造成这样,然后直接通过movie的字段进行注入:

String sql = "UPDATE movies SET " +"title = COALESCE(#{title}, title), " +"release_date = COALESCE(#{releaseDate}, release_date), " +"poster_url = COALESCE(#{posterUrl}, poster_url), " +"duration = COALESCE(#{duration}, duration), " +"genre = COALESCE(#{genre}, genre), " +"rating = COALESCE(#{rating}, rating), " +"status = COALESCE(#{status}, status), " +"updated_at = NOW() " +"WHERE id = #{id}";

一开始想实现像mybatis那样的注解扫描模式。但发现这是一个大工程,因为我原有的bean注册器没有针对代理类的处理,而且这需要额外构建JdbcUtils的方法句柄,这动摇到了我一开始的分模块理念。工具类是不应该出现在核心模块当中的,一个代理类的方法,外面再套了一层AOP,我不知道这中间的通知链是否会出问题(猜测不会)。除此之外,一旦进行了代理,调试起来就会变得比较复杂,而我连最基本的注入处理都没有弄好。所以这个想法暂时放弃了(真不是我懒哈)。

现在的方案是基于实体类的字段反射注入。

1)向外提供SQL参数提取方法
public static Object[] extractParams(String sql, Object... params) {SqlTemplate template = Cache.SQL_TEMPLATE_CACHE.computeIfAbsent(sql, SqlTemplate::new);Object[] result = new Object[template.paramNames.size()];for (int i = 0; i < template.paramNames.size(); i++) {String paramName = template.paramNames.get(i);result[i] = findParamValue(paramName, params);}return result;
}
2)关键方法:从实体类中查找字段
for (Object param : params) {if (param == null || param instanceof Map || param instanceof String) {continue;}Class<?> clazz = param.getClass();Map<String, MethodHandle[]> accessors = Cache.ACCESSOR_CACHE.computeIfAbsent(clazz, KatSimpleMapper::createAccessors);MethodHandle getter;try {getter = accessors.get(paramName)[0]; // [0]是getter} catch (Exception e) {log.error("Failed to access field: {}", paramName);log.error("Check accessors: {}", accessors);throw new RuntimeException(e);}if (getter != null) {try {return getter.invoke(param); //调用实体类param的getter方法句柄获取值} catch (Throwable e) {throw new RuntimeException("Failed to access field: " + paramName, e);}}
}

增加对map和显式键值对的兼容:

// 1:查找显式键值对(如 "id", 123)
for (int i = 0; i < params.length; i++) {if (params[i] instanceof String key && i + 1 < params.length) {if (key.equals(paramName)) {return params[i + 1];}}
}// 2:查找 Map 中的参数
for (Object param : params) {if (param instanceof Map<?, ?> map) {if (map.containsKey(paramName)) {return map.get(paramName);}}
}

并确定了查找优先级:键值对 > Map > 实体类字段。

3)缓存优化

对sql模板进行了缓存(貌似没有优化多少):

//sql模板缓存
private static final Map<String, SqlTemplate> SQL_TEMPLATE_CACHE = new ConcurrentHashMap<>();

将原来的setter缓存改成了更通用的字段缓存,这样无论是进行结果集映射还是字段注入,同一个类只需要缓存一次:

//缓存访问器数组 [getter, setter]
static final Map<Class<?>, Map<String, MethodHandle[]>> ACCESSOR_CACHE = new ConcurrentHashMap<>();
4)正则替换,将当前的特殊sql转回防注入sql
/*** 将#{param}替换为?*/
public static String replaceParamPlaceholders(String sql) {return sql.replaceAll("#\\{\\w+}", "?");
}

结语


抓紧时间bro。

http://www.xdnf.cn/news/316873.html

相关文章:

  • 发那科机器人3(机器人编程基础)
  • Python小酷库系列:5个常用的dict属性化访问扩展库
  • Kubernetes调度技术:污点与容忍生产级应用指南
  • Selenium使用指南
  • 7.2.安全防御
  • 一个项目的周测试的文档(Billing Service 测试文档)
  • pcie协议复位
  • 1688拍立淘搜索相似商品API接口概述,json数据示例参考
  • 适合java程序员的Kafka消息中间件实战
  • 用 NGINX 打造高性能 FastCGI 加速 `ngx_http_fastcgi_module`
  • 深入理解Java三大特性:封装、继承和多态
  • 国家信息中心:基于区块链和区块链服务网络(BSN)的可信数据空间建设指引
  • jenkins配置多nexus仓库多maven版本
  • 深入解析华为交换机中的VRRP原理
  • P值、置信度与置信区间的关系:统计推断的三大支柱
  • 三、Hadoop1.X及其组件的深度剖析
  • iOS蓝牙技术实现及优化
  • 【神经网络与深度学习】VAE 在解码前进行重参数化
  • 指定Docker镜像源,使用阿里云加速异常解决
  • lvgl多语言设置
  • Diamond iO:实用 iO 的第一缕曙光
  • 台州智惠自动化签约智橙PLM,让创新持续发生
  • 开发搭载阿里云平台的物联网APP(支持数据接收与发送)
  • 【C++】类和对象
  • Vue3+TS+vite项目本地测试数据接口搭建
  • 1.1.2 简化迭代器 yield return的使用
  • 音乐网站|基于SprinBoot+vue的音乐网站(源码+数据库+文档)
  • RPA与After Effects 2024深度融合:自动化影视特效全链路革命
  • ESP32蓝牙开发笔记(十五)
  • 开发 Chrome 扩展中的侧边栏图标设置实录(Manifest V3)