说明:
这个工具只是想把脑海里的想法输出出来,都是以个人兴趣写的,没有想过维护,想到哪写到哪,当作学习交流参考差不多,不能用到真实的项目上,包括以后随时可能不维护。
如果觉得部分功能自己需要,可以拿走自己去做定制和维护。
之前我是想实现很多东西来着,可惜没精力和时间,后面就没兴趣了。有很多代码直接删减了,所以能看到少部分遗留代码。
这个工具的目的是为了解决数据库与缓存间自动托管达到数据一致性。比如 users 表作为热点表,需要放入缓存中只需一个注解 @TableCache 就可以了。
至于缓存的更新,工具会监听sql执行自动更新缓存, 包括缓存查询时实现了自己的 csql 表达式,最大程度契合 sql,作为基础功能以便扩展更多上层建筑。
由于代理了数据源,并且全程跟踪了 jdbc 操作。可以感知到用户什么时候获取的连接、执行了几条 sql、每条 sql 是否为批量、执行参数、影响行数、什么时候提交、关闭连接 之类的细节(详见 com.jiao.table.listener 包下示例)。
所以可以在次基础上的监听器可以做很多事,比如:数据源的使用状态、sql执行的耗时、sql执行的类型。
用户可以扩展 2 种监听器:
数据源监听器:获取连接后事件、关闭连接事件、commit 前事件、commit 后事件
SQL监听器:sql 执行前事件、sql 执行后事件
这个工具只是在这个基础上做了一个缓存自动闭环的上层建筑,如果想 mq、es搜索 之类的闭环
如果一条 sql 从获取连接开始,到结束时候,所有的细节都能感知到,这个时候想象力有多大,能解决的问题就能有多少。
csql 表达式只是实现了简单的 sql 查询功能,只支持格式:select xx from xx where xxx 格式,像子查询、临时表、嵌套查询直接都是不支持的
支持符号与运算符:>=、>、<=、<、!=、between、like、in、not、or、and、( ) 、?、#、*
其中 ? 与 # 为预编译方式执行,目的为了减少表达式的解析过程。? 与 # 不可以同时使用。
* 为查询列。在缓存中都是查询出全部的,保留这个只是为了和 sql 契合。
like 功能目前未实现,预计在 1.1_bate 实现。
where数据类型:int、long、Date(内部转成long计算)、string
@TableCache
注解在类上,被注解的bean字段将会和数据库字段一样对照,在项目启动时候工具会自己加载这个表对应的所有数据。
然后去监听这个张表的数据更新,对应的也更新缓存。
@ColunmMapping
注解到实体上,假如实体列名与数据库不一致,则用这个去映射指定数据库列名.
@PrimaryKey
注解在列上,被 @TableCache 注解的类中,必须有个主键。
@TableIndex 注解在列上,在缓存中自动生成索引,以便快速查找。目前 csql 表达式只支持在索引列中去做数据的筛选。
@ResultColunmMapper
注解在列上,当指定 bean 与存到缓存的 bean 列名不一致时候,使用此注解将指定列结果映射进来。
例如:users bean中有个 u_id 存入了缓存。但是用 UserVO 中的 uId 接收结果时候,就需要这个注解在 uId 列上。
@IgnoreColunm
当被 @TableCache 注解的实体中,存在数据库中不存在的字段时候,需要用这个忽略.
直接使用 demo-start 模块的测试项目就行。几分钟快速上手
执行测试 sql (这里使用的 mysql)
在 demo-start 模块下执行 模拟数据.sql
修改 application.yml 中的数据库和 redis 配置
指定加载的缓存 与 监听器
在 Person 表中指定
@TableCache 就会加载这张表对应的缓存
@TableIndex 指定此类为缓存中的索引列, 用来快速检索,并且 csql 只用检索索引与主键列
实现sql监听 SQLListener(sql监听), ConnectionListener(链接监听)
例如示例:DeleteSQLListener.java InsertSQLListener.java
启动项目
启动 CacheSysApplication.java 类 redis 中会生成如下缓存数据如下:
前缀:cache:sys:table:xxx表名
表数据:cache:sys:table:user:data
元数据:cache:sys:table:aeitem:matedata:xxxx
元数据主要辅助 csql 计算表达式用
索引:cache:sys:table:reguser:index:索引key:索引值
测试缓存
在 PersonController 中测试,在对数据的增删写时候,观察缓存自动更新了。
抛出写异常时候的补偿机制
1. demo-start
用来测试模拟使用场景,里面 Demo 效果可以直接测试
2. jiaocache-cache-support
缓存支持,尽量的将缓存的操作都抽取,不直接依赖 Redis。实现缓存的有 Redis 实现,与内存缓存实现,内存缓存只是实现了大概,没有真的写完。目的是有2点。
2.1. 便于实现更换缓存的实现
2.2. 最初想在远程缓存(Redis) 挂之后,可以自动识别。监听到之后走缓存降级到内存缓存,从数据库加载最新的数据到内存缓存,这个时候会出现数据查时候不一致。但是一定会保证平台一直可用。而且后面想法是让Tomcat间实现通信后,解决一致性问题。这种在远程缓存不可信时走备用方案,用户无感切换的是我想要的。但是需要投入太多实现。
之前主要有2个目的,想在这个模块中做动态缓存切换,和不去强依赖某个缓存工具。
3. jiaocache-cache-syntax
这个主要用作解析 csql 表达式,与计算表达式。
其实有个简单版的降级,如果缓存不可用,那就直接降级到数据库。比如以下形式:
假如用 mybatis 时候用一个切面,切入 @Select(" select * from users ")
这句sql,当缓存可用时候走缓存,当缓存挂了,或者缓存不可信了,就走数据库。
4. jiaocache-common
公共包
6. jiaocache-datasource
代理 DataSource, 全程跟踪数据库的所有操作。在执行 sql 执行前后、conn 开启、关闭、提交 时候执行监听器。
7. jiaocache-datasource-autoconig
主要用于切入数据源,这里的思路为直接自己实现 DataSource 代理数据源,然后内部维护一个实际的 DataSource。
8. jiaocache-table
实现自动加载数据、自动闭环数据、实现表达式查询、使用 lua 保证原子性 内部出错会尝试回滚、 写缓存时容错机制
基本上很多重要的功能都在这里
9. 为实现的 plug 插件包
这部分也是我最想要的, 可以实现很多功能,最初最想实现的就有三个。
9.1 sql 耗时监听
如果你想做一个数据库监控管理,在应用层直接无视各种数据库差异,就能统计出 执行次数最多的sql,最耗时的sql。
9.2 数据源监听
统计各个数据源的链接占用情况,是否数据库链接打满一目了然。
9.3 类似 spring-cache 自动闭环
@Cache(key="'getUserDetail' + usrId", tableNameArr = {'用户表', '积分表', '订单表'})
pubile UserDetail getUserDetail(long usrId) { xxx }
如果 tableNameArr 里面任何一个表发生了变化, 那么挂到这些表下的全部缓存都会删除。
是不是可以让优化变得更简单 ?
9.4 动态缓存缓存切换
1.0 遇到问题
在把这个工具用到用到公司其中一个老项目中,由于老项目各个版本太低遇到很多兼容性问题,最后将大部分工具升级才得以兼容。后面遇到的一些问题都会贴出来给出一个参考。
maven jar中依赖的jar也会冲突,目前试验的项目移除了某些包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.jiao.cachesys</groupId>
<artifactId>jiaocache-datasource-autoconig</artifactId>
<version>1.0</version>
<exclusions>
<exclusion>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
包括一些监听器啊,拦截器什么的旧项目该升级就得升级了。比较新的项目可以忽略很多问题。
不管这个组合是不是最好的,反正跑起来了,也没空去研究细了,太耽误时间。
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。