• CPA-IBE


    1.Transaction ID 生成机制

    在有的情况下,我们需要得到固定格式的序列号,而不是数据库默认的自增序列号,

    1.1 通常方式(隐式生成并通过触发器实时插入相关表)

    例如我们要求此序列号必须有固定前缀,长度必须固定为12为,必须自增,要怎么实现呢。 

    通常情况下,可以在Oracle中定义一个序列,

    1 CREATE SEQUENCE seqTest
    2 INCREMENT BY 1 -- 每次加几个
    3 START WITH 1 -- 从1开始计数
    4 NOMAXvalue -- 不设置最大值
    5 NOCYCLE -- 一直累加,不循环
    6 CACHE 10; --设置缓存cache个序列,如果系统down掉了或者其它情况将会导致序列不连续,也可以设置为---------NOCACHE

    定义好sequence后,你就可以用currVal,nextVal取得值。

    1 SELECT Sequence名称.CurrVal FROM DUAL; 
    select seqtest.currval from dual

    我们可以将这个序列通过触发器绑定到某个表上,例如下面,

     1 create sequence SEQ_ID
     2 minvalue 1
     3 maxvalue 99999999
     4 start with 1
     5 increment by 1
     6 nocache
     7 order;
     8 
     9 建解发器代码为:
    10 
    11 create or replace trigger tri_test_id
    12   before insert on S_Depart   --S_Depart 是表名
    13   for each row
    14 declare
    15   nextid number;
    16 begin
    17   IF :new.DepartId IS NULLor :new.DepartId=0 THEN --DepartId是列名
    18     select SEQ_ID.nextval --SEQ_ID正是刚才创建的
    19     into nextid
    20     from sys.dual;
    21     :new.DepartId:=nextid;
    22   end if;
    23 end tri_test_id;

    这样就实现了在表中插入数据时候自定义的序列可以自增了。

    ———————————————————— 

    2.2.IBE的实现方式:显示生成,后续手动插入相关表

    在IBE在PRE_PAYMENT的ACTION中,将会生成一个唯一的transaction ID, 这个ID会根据不同的业务类型分配不同的前缀,例如RR,RB,RH等。

    可以看到,在数据库中创建了如下序列,

    1 CREATE SEQUENCE TXCTLADMIN.SQ_TXCTL_ONLINE_REVENUE_BKG INCREMENT BY 1 MAXVALUE 99999999 MINVALUE 1 CYCLE NOCACHE ORDER

    其实这个步骤也可以在Hibernate中进行配置,像下面这样,

    1   <id name="id" type="long">
    2    <column name="ID" not-null="true" sql-type="NUMBER" unique="true"/>
    3    <generator class="sequence">
    4     <param name="sequence">SQ_TXCTL_ONLINE_REVENUE_BKG</param>   
    5    </generator>
    6   </id>

    接着在java代码OnlineTransactionDataProviderImpl中,通过以下方式获取下一个序列号,

    1     @Override
    2     public Long getSequenceNum(final String sequenceName) {
    3 
    4         return (Long) this.getSessionFactory().getCurrentSession()
    5             .createSQLQuery("select " + sequenceName + ".NEXTVAL as id from dual").addScalar("id", Hibernate.LONG)
    6             .uniqueResult();
    7 
    8     }

    关键代码为select " + sequenceName + ".NEXTVAL as id from dual 这一句,结合上面java代码的上下文,这里的sequenceName为SQ_TXCTL_ONLINE_REVENUE_BKG,

    即,如果已经在数据库中创建了一个序列,则获取下一个序列是借助虚拟表DUAL获取的,像下面这样,

    1 SELECT TXCTLADMIN.SQ_TXCTL_ONLINE_REVENUE_BKG.NEXTVAL FROM DUAL;

    通过上面的方式可以生成一个transaction ID, 我们可以验证当前生成的ID值, 

    1 SELECT TXCTLADMIN.SQ_TXCTL_ONLINE_REVENUE_BKG.CURRVAL FROM DUAL;

    在简单的插入数据的业务中,完全可以配置一个触发器,每当插入数据到指定表的时候,就获取上面的序列并随之插入新行中,

    但是IBE在这里获取了序列号之后,新行并不是需要马上插入数据库,因为后面还有大量业务需要处理,所以这里只是先显式生成序列号。

    2. servlet的ThreadLocal机制

    传统的Java多线程经常使用synchronized来同步线程,它依靠JVM的锁机制来实现临界区的函数或者变量在访问中的原子性。

    在Web容器默认采用单实例(单Servlet实例)多线程的方式来处理Http请求,但是,这样的处理方式会导致变量访问的线程安全问题。也就是说,Servlet对象并不是一个线程安全的对象。

    为了解决web容器多线程的线程安全问题,可以使用ThreadLocal机制来解决这个问题。

    ThreadLocal同步机制

    在IBE中,各个service bean都是无状态的,用户的状态都保存在session中,但是多个用户的所有操作日志都将打印在同一个日志文件中,如果没有一个标识符号,根本无法区分哪条日志是谁的。

    因此在IBE中,就是先定义了一个ThreadLocal类型的关联ID:correlationInfo,当用户的第一个请求到达服务器时,先生成一个correlationInfo变量,每次写日志时用这个变量作为唯一标识符,

    多个线程之间的correlationInfo则能起到唯一标识作用,在日志上就能区分每个用户的内容了。当用户操作发生跳转,有新的请求的时候,可以将correlationInfo放在session或者放在URL中,当同

    一个用户的请求到达时候,再读出这个corrleationInfo,继续写日志。

    1 private static ThreadLocal<CorrelationInfo> corrInfo = new ThreadLocal<CorrelationInfo>();

    获取corrInfo的方法,可以看到用的是JDK自带的UUID算法,可以保证唯一性。

    1     public static CorrelationInfo getCorrelationInfo() {
    2         CorrelationInfo correlationInfo = ThreadLocalUtil.corrInfo.get();
    3         if (correlationInfo == null || correlationInfo.isBlankCorrelationInfo()) {
    4             correlationInfo = new CorrelationInfo("null", UUID.randomUUID().toString(), "WEB");
    5         }
    6         return correlationInfo;
    7     }

    接着,在做payment之前,因为此payment请求是从第三方跳转到IBE的,甚至是在内部和外部系统进行多次来回跳转,此时需要先获取这个correlationId,写日志的时候就不会混乱。

    1 bookingDetail.setCorrelationInfo(ThreadLocalUtil.getCorrelationInfo());

    3.IBE的状态维持及事务管理

    IBE由SpringMVC实现业务层,单例sevelet将每个http请求分配到独立线程,通过FacadeController找到具体的service进行执行,这个过程中,IBE与内外系统有来回交互,在Service层中的bean几乎是无状态的(除了一些需要注入的handler),所有用户状态都保存在session中,另外通过correctlation ID可以将请求与线程绑定,即每次都能保证在内外系统通过http交互时,同一个人的请求总是由同一个线程继续处理。http请求默认是重写URL实现,每一个http请求中,都附带有JSESSION ID,默认的session ID是IBE自己生成并用来保存用户状态,但此JSESSION ID则是由外部系统1A生成,用来与具体事务关联的(例如锁定票务事务,票务是由第三方提供的)。

     4.时序图

    Web容器默认采用单实例(单Servlet实例)多线程的方式来处理Http请求
  • 相关阅读:
    加入mapstruct后出现 找不到符号 符号: 方法 setXX 的解决方法
    解决docker容器日志导致主机磁盘空间满了的情况
    prometheus安装(docker)
    在Github或Gitee上用hexo搭建个人博客
    解决github打不开
    jenkins更新为国内源
    让sentinel-dashboard的流控配置持久化到nacos
    Yarn和Zookeeper的区别
    flink安装启动(docker)
    jQuery 事件源码定位
  • 原文地址:https://www.cnblogs.com/fysola/p/6509609.html
Copyright © 2020-2023  润新知