tx-lcn icon indicating copy to clipboard operation
tx-lcn copied to clipboard

6.0下 SQL幂等性分析

Open xlorne opened this issue 5 years ago • 15 comments

6.0 相比之前的底层实现上做了些调整。需要依赖分析SQL来完成事务的补偿。目前框架是通过p6spy获取到了执行到的sql,也提供了connection对象,需要基于sql与connection对象获取到。真实影响到的数据。

何为真实影响到的数据? 比如 insert into demo(id,time,name) values(1,123,now()); 中的now() 就是一个可变参数。我们需要拿到now的真实数据,以此理解,还有id的自增长问题,还有修改语句中没有id时,要获取真实影响到的数据。删除语句中真实删除掉的语句。

xlorne avatar Jul 02 '20 01:07 xlorne

SQL parser

SQL的职责就是要获取到落库后的实际数据。

对于insert语句若存在主键自增长的时候,insert语句中是不提现id的,只有插入数据库以后才能获取到。这就是一种需要处理的情况。 对于update语句我们需要获取到真实受影响的数据,例如执行的语句是 update table set name = '123' 这里就需要知道具体影响的数据,然后加一id限制确保数据的幂等性。 对于delete语句来说也是会出现如同上面update语句一样的情况,但是delete语句需要先知道受影响的语句然后在执行delete,因为若先执行了delete就获取不到影响到的数据了。

上述都是id层面的,还有函数层面。例如mysql的now() rand() 等这类的函数参数值。

但是sql parser也并非所有的语句都需要处理,例如 update table set name = 'name' where id = 1 这样的sql就不需要,因为不会再落库后产生差异。因此SQL parser需要先分析,然后需要处理的则再分析处理。

对于SQL Parser的目的是用在事务补偿时。出现事务补偿的情况既在分布式事务通知提交时本模块失去了与TM的联系,当然若分布式事务通知提交则说明本地事务已经正常执行完了事务提交后了,通常这样的情况是发生在TC模块成功执行完业务并加入事务消息后挂掉了。虽然是极小概率但是花费的代价是比较大的。

xlorne avatar Jul 04 '20 08:07 xlorne


/**
 * @author lorne
 * @date 2020/7/3
 * SQL幂等性分析接口,适配各种数据库做差异性适配
 */
public interface SqlAnalyse {

    /**
     * 数据库类型
     * @return
     */
    String sqlType();

    /**
     * SQL幂等性分析
     * 幂等性机制主要是确保在执行补偿的时候重新提交的数据保持与事务执行时的数据一致,因此为了确保数据的一致性,目前的方案是记录实际影响的数据操作,然后在补偿的时候直接提交这些实际数据。
     * insert 语句分析
     * insert 获取落库后的数据信息
     * 实现思路
     * 若sql中有主键值,则直接记录下id,然后再查询影响后的数据
     * 若sql中没有主键,则通过主键策略来查询ID,然后再查询影响后的实际数据。
     * update 语句分析
     * update 获取落库后的数据信息
     * 实现思路
     * 执行完成修改操作以后,按照相同条件下执行查询获取到影响后的实际数据。
     * delete 语句分析
     * delete 获取要真实删除的数据信息
     * 实现思路
     * 再执行delete之前先查询实际删除数据的id,然后再执行删除操作
     * @param sql SQL数据
     * @param statementInformation 执行返回数据
     * @return 满足幂等性的SQL
     */
    String analyse(String sql,StatementInformation statementInformation);

    /**
     * SQL 分析判断检查
     * 仅当CUD操作才需要做幂等性检查
     * @param sql 执行的SQL
     * @return
     */
    boolean preAnalyse(String sql);

}

xlorne avatar Jul 05 '20 13:07 xlorne

这个我想做 @1991wangliang

BigBlackSheep avatar Aug 06 '20 07:08 BigBlackSheep

@BigBlackSheep 你开始写了吗?

xlorne avatar Aug 08 '20 14:08 xlorne

实现思路请参考改接口定义: 实现思路

xlorne avatar Aug 08 '20 14:08 xlorne

目前还没开始写,不过你提供的思路很清晰,我将根据你提供的思路,尽快实现出来。另外我想请教一个问题: 在insert语句中,如果没有指定主键,也就是主键是自增的情况下.那是否可以默认他就是幂等的呢?因为他来本就是自增策略。补偿时也将是自增策略。

BigBlackSheep avatar Aug 08 '20 16:08 BigBlackSheep

或者补偿可能补偿多次的情况下,那么将会出现脏数据的问题,那么需要修改insert 语句为带上主键的.那么 “ 若sql中没有主键,则通过主键策略来查询ID,然后再查询影响后的实际数据。”
这个主键策略,能否给我解释一下。谢谢!

BigBlackSheep avatar Aug 08 '20 16:08 BigBlackSheep

DataBaseContext 全局缓存数据库表信息

在项目第一次获取到connection 对象的时候开始执行数据库表信息分析, 获取出所有的表字段和主键信息,包括自动增长策略,在SQL幂等性分析的 时候,可以采用这些信息分析业务sql。

xlorne avatar Aug 09 '20 02:08 xlorne

#530 非常不错,不过应该还需要考虑如下几点: 1、delete语句若无有效数据时,目前这样的情况下会有异常的。 2、由于分析业务中需要直线insert delete update 三种业务建议这里做一下抽象适配,不要用if else 来区分。 3、单元测试的表记录是不存在的,目前代码build fail,建议将测试的sql脚本提交到sql/init.sql 下。

xlorne avatar Aug 11 '20 13:08 xlorne

收到 下个commit中将会修改

BigBlackSheep avatar Aug 11 '20 16:08 BigBlackSheep

@1991wangliang 请教一下 业务SQL涉及的表中是没有主键的情况下要如何保障幂等呢?

BigBlackSheep avatar Aug 13 '20 14:08 BigBlackSheep

目前的做法是先判断下所涉及的表中如果都没有主键则原SQL返回。

BigBlackSheep avatar Aug 13 '20 16:08 BigBlackSheep

可以先这样来实现,这个地方没有主键确实不好分析

xlorne avatar Aug 14 '20 03:08 xlorne

非常感谢,你这段时间的代码提交,我看基本已经实现了sql分析功能,由于我最近出差去了外地十几天,所以一直没有时间来看项目。我刚看了一下提交的代码。我发现需要优化的地方还是还有很多。 主要体现在两方面: 1、写法不严谨,主要体现在sql的分析处理上。(提高扩展性,多使用接口抽象分割方法内容,定义层次去做sql解析分析) 2、类的功能不明确,违背SCP。建议梳理清楚类的职责。 我简单提交了一个todo,需要你能更好的优化一下这块代码。 😀 😀

xlorne avatar Aug 28 '20 07:08 xlorne

非常开心能够为lcn框架贡献自己的一份力,由于我最近也是加班比较多又想着赶紧实现基本的功能,所以很多地方实现的比较糙!现在我将持续优化这块代码,后续在优化的过程中有什么结构层次不够好的地方或者是出现Bug,我会尽快修复! 😀

BigBlackSheep avatar Aug 28 '20 09:08 BigBlackSheep