会签的并发控制

  目前对会签的表单我们采用了两种不同的方案,也代表两种不同的风格。第一种是moss风格,第二种是通达风格。Moss风格不共用会签区,不同的会签人会签意见签署区不同。这种风格的会签人是固定配置在节点上的,如果会签人不固定,那么会签区表单权限控制就会出现混乱;通达风格则是属于共用会签区的形式,不同会签人都在同一个输入框中输入审批信息。点击审批时,审批人、审批时间和审批意见存储在另外一张表里,展示的时候使用拼接html的table的形式展示在相应位置。效果对比如下:

1.moss风格

2.通达风格1

3.通达风格2

  在通达风格,即共用会签区时,我们是不需要考虑并发控制的,因为每次审批形成的审批数据都单独存储在一张表中。对于不共用会签区的,除了考虑权限控制以外,并发控制同样重要。当一个多人参与会签的任务到达后,如有两个以上的会签人打开并签署意见后,先审批的意见就被后审批的会签动作覆盖,其他用户打开查看时,会签意见只有一条。

  以上是对会签并发控制的问题的一个概述。

  针对并发问题,特别是数据库的并发问题,有乐观锁和悲观锁的概念。

悲观锁假定其他用户企图访问或者改变你正在访问、更改的对象的概率是很高的,因此在悲观锁的环境中,在你开始改变此对象之前就将该对象锁住,并且直到你提交了所作的更改之后才释放锁。悲观的缺陷是加锁的时间可能会很长,这样可能会长时间的限制其他用户的访问,也就是说悲观锁的并发访问性不好。

乐观锁则认为其他用户企图改变你正在更改的对象的概率是很小的,因此乐观锁直到你准备提交所作的更改时才将对象锁住,当你读取以及改变该对象时并不加锁。可见乐观锁加锁的时间要比悲观锁短,乐观锁可以用较大的锁粒度获得较好的并发访问性能。但是如果第二个用户恰好在第一个用户提交更改之前读取了该对象,那么当他完成了自己的更改进行提交时,数据库就会发现该对象已经变化了,这样,第二个用户不得不重新读取该对象并作出更改。这说明在乐观锁环境中,会增加并发用户读取对象的次数。

  针对会签并发的特殊性,我们采用了乐观锁的并发控制形式,即在读取和打开审批页面时并没做任何限制,待发表审批意见并提交后系统会检测读取到的时间戳与当前实时时间戳是否一致。如一致,则提交审批意见;如不一致,则提示用户刷新。这种思路严格意义上与乐观锁的定义并不匹配,但却与乐观锁的实现具有异曲同工的效果。

  下面是实现代码:

1.定义时间戳

  时间戳采用流水号形式,所有的表单的时间戳定义需完全一致。

2.提交时进行判断

if(isSign == "1"){
			var overDateDataMap;
			$.oaPlugin.ajaxJson({
				data : paras,
				async : false,
				url : "isDataOverDate.action",
				success : function(result) {
					overDateDataMap = result.overDateDataMap;
					if(overDateDataMap.flag == ‘1‘){
						isDateOver = true;
						$.tipAlert({ tipMsg:"本步骤其他会签用户已经提交审批信息,请刷新页面!!", type: 0 });
						//$.errorMsgAlert("本步骤其他会签用户已经提交审批信息,请刷新页面!!", result.responseText);
					}
				},
				error : function(result){
					//0标识需要提示疑问或者错误信息 1 提示正确信息 
					  $.tipAlert({ tipMsg:"出现错误!", type: 0 });				  

				}
			});
		}

3.判断逻辑

	public JSONObject isDataOverData(FlowRunTime flowRunTime) {
		JSONObject overDateDataMap = new JSONObject();
		if(StringUtils.isNotEmpty(flowRunTime.getTableName()) && StringUtils.isNotEmpty(flowRunTime.getPkValue())){
			Map<String, Object> dataMap = dymcQueryService.executeQuery(flowRunTime.getTableName(), flowRunTime.getPkValue());
			String formdata = flowRunTime.getFormData();
			Map<String, Object> map = Json2MapUtil.parseJSON2Map(formdata);
			Map<String, Object> mainMap = (Map<String, Object>)map.get("main");
			Map<String, Object> mainFiledsMap = (Map<String, Object>)mainMap.get("fields");
			JSONObject newValue = new JSONObject();
			JSONObject oldValue = new JSONObject();
			if(mainFiledsMap != null && dataMap != null){
				if(mainFiledsMap.containsKey("zhxgsj") && dataMap.containsKey("f_zhxgsj")){
					if(mainFiledsMap.get("zhxgsj") != null){
						if(!mainFiledsMap.get("zhxgsj").toString().equals(dataMap.get("f_zhxgsj").toString())){
							overDateDataMap.put("flag", "1");
		//					for(Entry<String, Object> entry : mainFiledsMap.entrySet()){
		//						if(dataMap.containsKey("f_" + entry.getKey())){
		//							if(StringUtils.isNotEmpty(entry.getValue().toString()) && !entry.getValue().toString().equals(dataMap.get("f_" + entry.getKey()).toString())){
		//								newValue.put(entry.getKey(), entry.getValue());
		//								oldValue.put(entry.getKey(), dataMap.get("f_" + entry.getKey()));
		//							} else if((StringUtils.isEmpty(entry.getValue().toString()) && StringUtils.isNotEmpty(dataMap.get("f_" + entry.getKey()).toString()))  || (StringUtils.isNotEmpty(entry.getValue().toString()) && StringUtils.isEmpty(dataMap.get("f_" + entry.getKey()).toString()))){
		//								newValue.put(entry.getKey(), entry.getValue());
		//								oldValue.put(entry.getKey(), dataMap.get("f_" + entry.getKey()));
		//							}
		//						}else {
		//							if(StringUtils.isNotEmpty(entry.getValue().toString())){
		//								newValue.put(entry.getKey(), entry.getValue());
		//								oldValue.put(entry.getKey(), "");
		//							}
		//						}
		//					}

						} else {
							overDateDataMap.put("flag", "0");
						}
					} else {
						overDateDataMap.put("flag", "0");
					}
				} else {
					overDateDataMap.put("flag", "0");
				}
				overDateDataMap.put("new", newValue);
				overDateDataMap.put("old", oldValue);
			}else {
				overDateDataMap.put("flag", "0");
			}
		}
		return overDateDataMap;
	}

  逻辑释义:当前表单数据中的时间戳字段与实时数据库中的时间戳字段如果不一致,则可以判断数据过期;如果一致,则表明无其他会签改变数据,可以提交。注释掉的部分,则是将不一致的数据按属性名:属性值的形式取出,在前端将实时数据合并后在向后端发送保存。

4.时间戳的更新:

  if(formData.getMainFields().containsKey("f_zhxgsj")){
    	  formData.getMainFields().put("f_zhxgsj", DateUtils.getNowDateTimeToStr("yyyyMMddhhmmss"));
      }

  通过以上思路,可以有效解决会签时的并发问题。

时间: 2024-08-02 21:04:56

会签的并发控制的相关文章

嵌入式环境下并发控制与线程安全

嵌入式环境下并发控制与线程安全 代码规模日益增大和基于RTOS的多线程技术使嵌入式软件开发越来越关注"并发控制和线程安全",当多个执行线程(指正在运行代码的任意上下文,包括线程和中断服务程序)需要访问相同的共享资源时(包括软件数据和硬件资源),就可能因为竞态而导致错误.这种错误容易制造,但很难找到,从设计上保证正确性收益更大. 竞态的产生 当一个共享资源被多个执行线程"非原子性"访问时,一个执行线程的操作被另一个执行线程打断而带来错误就叫"竞态"

mysql的mvcc(多版本并发控制)

mysql的mvcc(多版本并发控制) 我们知道,mysql的innodb采用的是行锁,而且采用了多版本并发控制来提高读操作的性能. 什么是多版本并发控制呢 ?其实就是在每一行记录的后面增加两个隐藏列,记录创建版本号和删除版本号, 而每一个事务在启动的时候,都有一个唯一的递增的版本号. 1.在插入操作时 : 记录的创建版本号就是事务版本号. 比如我插入一条记录, 事务id 假设是1 ,那么记录如下:也就是说,创建版本号就是事务版本号. id name create version delete

linux驱动程序中的并发控制

   现代操作系统有三大特性:中断处理.多任务处理和多处理器.这些特性导致当多个进程.线程或者CPU同时访问一个资源时,可能发生错误,这些错误是操作系统运行所不允许的.在操作系统中,内核需要提供并发控制机制,对共享资源进行保护.   在操作系统中,并发是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行.并发容易导致竞争的问题.竞争就是两个或两个以上的进程同时访问一个资源,同时引起资源的错误.并发控制机制有以下

PostgreSQL的并发控制

9.3中文文档:http://58.58.27.50:8079/doc/html/9.3.1_zh/mvcc.html 参考博客:中文:http://www.zlovezl.cn/articles/postgresql-concurrency-with-mvcc/ 英文:https://devcenter.heroku.com/articles/postgresql-concurrency 本文描述PostgreSQL数据库系统在多个会话试图同时访问同一数据时的表现.并发控制的目标是为所有会话提

Linux驱动设备中的并发控制

一.基本概念 二.中断屏蔽 三.原子操作 四.自旋锁 五.信号量 六.互斥体 七.自旋锁与信号量的比较 Linux设备驱动中必须解决的一个问题是多个进程对共享资源的并发访问,并发的访问会导致竞态,即使是经验丰富的驱动工程师也常常设计出包含并发问题的bug驱动程序. Linux提供了多种解决竞态问题的方式,这些方式适合不同的应用场景. 一.基本概念 并发(concurrency):指的是多个执行单元同时.并行被执行,而并发的执行单元对共享资源(硬件资源和软件资源上的全局变量.静态变量等)的访问则很

Nodejs爬虫进阶=&gt;异步并发控制

之前写了个现在看来很不完美的小爬虫,很多地方没有处理好,比如说在知乎点开一个问题的时候,它的所有回答并不是全部加载好了的,当你拉到回答的尾部时,点击加载更多,回答才会再加载一部分,所以说如果直接发送一个问题的请求链接,取得的页面是不完整的.还有就是我们通过发送链接下载图片的时候,是一张一张来下的,如果图片数量太多的话,真的是下到你睡完觉它还在下,而且我们用nodejs写的爬虫,却竟然没有用到nodejs最牛逼的异步并发的特性,太浪费了啊. 思路 这次的的爬虫是上次那个的升级版,不过呢,上次那个虽

SQL_事务的并发控制

--多个用户对同一个数据操作时,一个用户的行为结果可能导致另一个用户使用的数据无效,通过事务的并发控制可以确保 --同时发生的行为与数据的有效性不发生冲突 begin transaction select * from teachers with(holdlock) --数据库加锁 waitfor delay '00:00:10' commit transaction --通过commit 或者rollback可以解锁 begin transaction update teachers set

数据库原理--事务并发控制

事务并发:指事务能够在同一时间同时执行 存在的问题: 1.丢失修改(T1和T2同时修改,T2的结果将T1的结果覆盖) 2.读脏数据(T1修改后,T2读取,但是T1撤销修改) 3.不能重复读(T1前后读的数据不同) 并发控制: 锁:互斥锁(X).共享锁(S).U锁 2段锁协议:分两个阶段,第一阶段只能申请锁:第二阶段只能释放锁 注意:2段锁并不是和一次性封锁一样,一次性对所有数据加锁,所以可能存在死锁出现

乐观的并发控制(optimistic concurrency control)

ES是分布式的.当document被create,update,或者delete,这个document的新版本就会冗余到cluster的其他node中.ES是异步和并发的,意味着冗余请求也是并行进行的,并且请求到达也是无次序的.因此需要一个方式保证老版本的document不能重写新版本的数据. 如上所述,当我们讨论index,get和delete请求,我们指出每个document都有一个_version号,这个号码随着document的变化而增长.ES使用这个_version保证document