当前位置: 首页 > 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。

相关文章:

  • 【协程coroutine】async await
  • 互联网大厂Java求职面试:AI集成与云原生架构设计
  • 如何查看电脑显卡配置参数 一文读懂
  • 机器学习——逻辑回归ROC练习
  • 在 Ubuntu 系统中,挂起(Suspend)和休眠(Hibernate)
  • CAN报文逆向工程
  • 四步定位linux内核oops原因
  • dify 部署后docker 配置文件修改
  • 如何在Idea中编写Spark程序并运行
  • 缓存雪崩:高并发系统中的隐形杀手与应对策略
  • XSS 攻击:深入剖析“暗藏在网页中的脚本“与防御之道
  • 代码随想录算法训练营 Day39 动态规划Ⅶ 打家劫舍
  • ChromaDB调用BGE模型的两种实践方式
  • vscode 安装插件
  • java算法的核心思想及考察的解题思路
  • 制作一款打飞机游戏39:鼠标控制
  • 【大模型系列】使用fastapi为langchain应用快速对外提供restful api
  • 学习Linux的第四天
  • nginx 上传文件,413 request entity too large
  • 使用Milvus向量数据库构建具有长期记忆的对话机器人
  • 宣布停火后,印控克什米尔地区再次传出爆炸声
  • 李在明正式登记参选下届韩国总统
  • 泰特现代美术馆25年:那些瞬间,让艺术面向所有人
  • 庆祝上海总工会成立100周年暨市模范集体劳动模范和先进工作者表彰大会举行,陈吉宁寄予这些期待
  • 总粉丝破亿!当网络大V遇见硬核科技,互联网时代如何书写上海故事?
  • 新村回响:一周城市生活