【NC】NC6系列对于并发过程处理的分析

抽点时间分析一下NC6系列对于并发过程处理的分析

ERP产品中,并发的场景一般来说比较多出现在多个业务人员操作同一张单据,或者某个业务人员做的操作影响到了其他单据的数据两个人同时做操作,会导致出现并发的问题,也就是在业务层面出现的脏数据。

为保证其正确性,1.同一时刻只能有一人修改同一个资源;2.当修改资源的时候需要保证此资源和数据库中的版本保持一致,不能待修改的资源在数据库中已经变化了,也就是我们不能去修改一条“脏”数据,这两条分别对应上面提到的两个例子。所以我们引入了并发控制,在NC系统中就是加锁和校验时间戳。

加锁

NC中传统的锁是指内存级别的中间件锁,是指我们在代码中对一个资源去主动加锁,比如对单据pk这个字符串加锁,或者对客户pk这个字符串加锁,由于这个锁是全局级别的,整个系统中只可能有一个事务对其加锁成功。我们并没有用数据库DB自身的锁去控制并发。 NC中间件锁在最外层同一线程中,可对同一个资源重复加锁,对于不同的线程,锁是互斥的。

  • 加锁的目的
    为了实现在同一时刻,只能有一个人能够操作数据,进行删改,常见的场景是修改、保存、删除、审批、弃审、生效等等。在写操作数据的代码时要首先考虑到并发的处理,因为数据的准确性是一切业务处理的前提。

锁的种类

1.从锁的互斥性角度来考虑分为:排它锁、共享锁

1.1 排他锁(业务锁或者独占锁)
不同的线程中,锁是互斥的,如果要申请成功排它锁,其它线程中既不能有排它锁也不能有共享锁,而同一个线程中锁是可以重复申请得的。
简单的来说就是,如果我对一条数据加锁了,那么其他线程不能以任何方式再给这条数据加锁,但是我自己的这个线程是可以重复给这条数据加锁的。
在NC调用API如下:

boolean success = false;
//其中lockObject 是待锁定的字符串。一般我们放单据的主键
success = PKLock.getInstance().addBatchDynamicLock(lockObject);

大部分单据的保存、审批、回写都是加这样的锁。
1.2 共享锁
共享锁是指在没有排他锁的情况下,重复申请共享锁可以成功;无论同一线
程还是多个不同线程。相当于共享锁之间可以重复申请,共享锁和排它锁在不同
的事务中是互斥的。如下表所
【NC】NC6系列对于并发过程处理的分析_第1张图片
如上表所示,线程1 先对A 加共享锁成功,则线程2 再对A 加共享锁成功,
加排它锁失败,而同一个线程1 中调用其他服务对A 加排它锁失败,加共享锁成
功。加共享锁的底层调用如下:其中tempIDs 是待锁定的字符串,只不过它需要
加上UAP 指定的常量IPKLockBS.STR_SHARED_LOCK
调用API:

for (int i = 0; i < length; i++) {
tempIDs[i] += IPKLockBS.STR_SHARED_LOCK;
}
boolean flag = PKLock.getInstance().addBatchDynamicLock(tempIDs);

2 从锁的使用上考虑,分为:静态锁、动态锁

2.1 静态锁
加锁手工调用、释放锁也需要业务组手工写代码释放,虽然现在我
们还提供这样的机制,但在v6 系列里几经基本上不这样做了,因为手工
释放的操作风险很大,对锁的控制需要十分精细,程序员容易犯错,并且
还需要多写代码。
2.2 动态锁
这是目前正在普遍使用的锁,它的加锁同样代码主动调用,但释
放锁是动态的,当加锁所在的事务结束后,自动释放锁,以供下次加锁使
用,这种方式即简单方便,又可避免程序员人为忘记释放锁的错误,对数
据的控制也更加严谨。我们上述代码示例都是使用的动态锁。代码示例如

API 如下

PKLock.getInstance().addBatchDynamicLock(tempIDs);

校验时间戳

我们刚才谈加锁控制住了资源被同时修改的风险,但如何来保证我
们在内存中读取到的待修改使用的数据和数据库中对应的数据是一致的呢?
TS是我们在设计表结构的时候默认添加的字段(TimeStamp)我们在与数据做操作的过程中TS记录了最后修改数据的时间
内存读取到的ts值与数据库中的ts做比较,如果ts值不同的话,数据肯定是不同的,我们就不能再使用原来的脏数据,需要重新查询数据库获取最新的数据。

加锁和校验时间戳的配合使用

我们来讲一下场景

【NC】NC6系列对于并发过程处理的分析_第2张图片
【NC】NC6系列对于并发过程处理的分析_第3张图片

总结一下,如果在方法的最开始就有我们可以加锁的资源,我们应该毫不犹
豫首先加锁,再去校验TS 和处理数据。与我们所了解的乐观锁和悲观锁很相近

排它锁和共享锁的综合运用

一般说是对多个关联单据的锁的应用,比如我们做销售订单的业务数据,这个时候我们要对销售订单的数据加上排它锁,销售订单保存时可能会有信用的管理,对于信用额的处理我们要申请 信用单据的共享锁,这样保证没有人同时操作同一条信用数据。

锁的选择是根据业务+设计的综合考虑,并不是单纯的单据PK 锁,同时NC65 UF工厂2和PUBAPP已经进行了业务场景丰富的并发处理的代码封装,标准的保存、删除、提交、审核、回写等已经封装了对于并发的处理操作,此处不给出API,但是大家还是需要了解一下实现原理

实际上说了么多只讲了API没有谈代码实现,实际的底层实现还是使用了JDK提供的读写锁(ReentrantReadWriteLock)共享锁和排他锁的概念也是从读写锁中引入进来的,感兴趣的话可以读一读相关源码。讲到这就不得不说并发编程,有时间在分享吧

你可能感兴趣的:(NC65)