## 一、与主程序事务冲突问题
典型的,如果我们部署一套主程序,一套jobserver或者workserver等,由于两者共享同一个数据库,而两者由于各自事务中,如果一方有某个长时间事务性(比如循环的全表扫描)的锁定某张表的操作,而恰恰对方的业务中需要访问该表,就会抛出 com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction。
解决的方案:将jobserver中,全表扫描的操作,改为短事务,简单的做法,就是循环全表扫描的过程中,每次操作都是一个完整事务的,而不是全部操作放在一个事务里面,更具体来说,就是事务部放到manager层面,而是放在dao层面。
具体的例子:
Manager层面:
事务的:
![](https://img.kancloud.cn/c6/82/c6829f2191315214f3a36fa7bc67e5f9_454x128.png)
![](https://img.kancloud.cn/95/fe/95fea39633fec3e9c0f642a336c380d3_469x203.png)
非事务的:
![](https://img.kancloud.cn/8e/84/8e8420b5cd1d149d41720afeb2cba020_487x69.png)
![](https://img.kancloud.cn/ed/ef/edef2573bdb71e7b9fa9f4067a9901cf_485x93.png)
注意,这里面的dao必须是事务的了,否则,无法修改、删除、新增实体对象。
Job层面:
事务的:
![](https://img.kancloud.cn/bf/2c/bf2c0374795c4f66061faaa0f8a294c9_495x165.png)
非事务的:
![](https://img.kancloud.cn/64/00/64004eb4def6063b735d633730f4a4e1_465x95.png)
非事务中,对实体的操作:
![](https://img.kancloud.cn/e4/69/e46947c84b3ab9d6cc209c2f28d0a408_444x49.png)
但是,这里还是有一个问题,就是由于事务控制在dao层面,会导致每个dao操作都会提交事务,对于每一轮循环操作里面组合了若干个dao操作的,这样会出现事务脏数据的问题。
解决的方案是:
继续抽取api,将循环体里面的所有dao操作组合起来,合并为一个api,将事务控制,由原dao层面,提升到该api的事务操作类层面,并将该事务操作类纳入applicationContext-*.xml里面,通过serviceLocator.getObjectFromContext获取即可。
![](https://img.kancloud.cn/af/e4/afe43e3942f34d6d7c727974d998a180_554x248.png)
这个方案确保了循环体里面的操作都是完整的事务,循环体之间不是同一个事务,兼顾了事务完整性和避免长事务。
## 二、事务内死循环问题
死循环的操作,除了上述问题之外,即使是一张独占的表,还会带来事务永远无法提交的问题,所以不能用死循环的方式来处理长时间事务的。
比如:
![](https://img.kancloud.cn/5a/cd/5acdab8fb109193f73fe787c230ac756_554x180.png)
![](https://img.kancloud.cn/5a/cd/5acdab8fb109193f73fe787c230ac756_554x180.png)
这个方案里面,由于doTest永远无法结束,导致内部的事务无法提交,一直处于事务中。故不能采用这种方案,只能是用减小间隔的方式。
## 三、多job之间事务并发机制
多个job中,如果都循环操作同一个表,会出现脏数据的问题,比如某个job修改后,另外一个job拿到了继续修改,但由于事务未提交,会出现脏数据。
解决办法,用数据库的锁机制解决。平台推荐用乐观锁,增加版本号来解决冲突。具体可以参考《高级指南》中的乐观锁悲观锁章节了解;
## 四、全局单一事务job
有时候,有些业务并非长事务,但需要保障业务事务的完整性,平台提供了一种单一事务job机制。该job里面所有业务逻辑,都在一个事务里面执行,如果执行过程有异常,则会回滚;
具体做法如下:
1、该job与普通job不同,继承自UniframeworkTimerSingleTransactionJob
2、实现自己的事务内操作,实现自己的SingleTransactionJobOperator类
示例如下:
![](https://img.kancloud.cn/4d/f3/4df3b0fb14530182fd69d586508ab473_554x269.png)
## 五、循环独立事务job
对于长时间的事务,整个job的执行跨度非常长(参考4.1),循环遍历业务,且每个循环的业务都各自独立,互补影响,那么,就非常适合用循环独立事务job,job里面的业务,通过循环来实现,每一轮循环体内的业务,在一个事务里面执行,如果执行过程有异常,则仅循环体内事务回滚,不影响整体job的执行;
具体做法如下:
1、job继承自UniframeworkTimerJob
2、定义自己的manager,logic及api;
各种定义配置如下:
![](https://img.kancloud.cn/04/32/04320f2d986176866d9da73af90f542e_554x154.png)
代码实现的时候,特别注意,异常的处理,在logic循环内来处理,否则,因为api层面必须抛出异常,才能实现事务回滚,所以不可以在api里面来处理异常,直接让它抛出即可;
具体的实例明细如下:
Job:
![](https://img.kancloud.cn/80/2a/802afb5b672392925a2b5fcc8956dcaa_554x242.png)
Manager:
![](https://img.kancloud.cn/f1/01/f1013f6b2bdbdc96d5a0742ca5ab6325_554x318.png)
Logic:
![](https://img.kancloud.cn/d1/52/d15230b0181017a11f2e67a3ff5e465f_554x186.png)
这里是关键,这里处理异常,确保不会因为一次失败,终止整个调度,仅终止该次循环的调度逻辑,而且能确保该次逻辑也是完整事务的,出错会回滚;这里是在循环体内,捕捉每次api调用的异常;
Api:
![](https://img.kancloud.cn/c6/9d/c69d15eddc54bc0e20c687ef01959ffc_553x128.png)
Api里面,不要处理异常,直接抛出即可;
## 六、跨数据源job
在一个job中,跨两个数据库进行操作;
首先、uniframework.properties中配置;
![](https://img.kancloud.cn/a0/5e/a05ee0c9a1e4b219ba5f423c890074f0_553x71.png)
server.jobserver.anotherds.enabled必须设定为true,才会加载;
然后、在job中,调用第二数据源的dao,即可;
this.serviceLocator.getJobserverAnotherDatasourceDao()
举例如下:
核心业务代码中,这样来调用第二数据源:
![](https://img.kancloud.cn/9a/56/9a56e9304fc0068e1c8581042e2a63fc_554x88.png)
- 前言
- 01、系统平台
- 系统管理
- 组织类型
- 单位管理
- 基本功能
- SAAS功能
- 组织管理
- 角色管理
- 人员管理
- 账号管理
- 账户体系
- 账号绑定
- 账号锁定
- 团队管理
- 模板管理
- 补丁管理
- 字段管理
- 静态字典
- 动态字典
- 系统配置
- 菜单配置
- 路由配置
- 编码规则
- 访问控制
- 系统参数
- 字典配置
- 参数定义
- 参数配置
- 属性定义
- 属性设置
- 树形定义
- 树形设置
- 系统监控
- 业务维护
- 工作监控
- 调度监控
- 导入监控
- 日志管理
- 在线监控
- 附件管理
- 附件监控
- 附件应用
- 附件授权
- 上传监控
- 字段监控
- 系统提醒
- 场景配置
- 事件监控
- 提醒记录
- 事件历史
- 日期设置
- 节假日期
- 工作时间
- 日历编制
- 工作日历
- 开放平台
- 微信应用
- 配置信息
- 更新菜单
- 钉钉应用
- 配置信息
- 开放服务
- 应用设置
- 服务管理
- 请求监控
- 请求跟踪
- 移动应用
- 发布管理
- 导航菜单
- 个人管理
- 个人资料
- 内部消息
- 短信中心
- 流程管理
- 流程定义
- 流程环节
- 处理人
- 流程提醒
- 流程签收
- 流程目录
- 流程微调
- 转移动作
- 定义校验
- 流程绑定
- 流程实体设定
- 单业务多流程
- 动态表单绑定
- 环节字段设定
- 转移路由设定
- 流程监控
- 流程催办
- 流程会话
- 流程启动
- 通用待办
- 流程驱动
- 通用已办
- 示范实例
- 流程启动
- 流程待办
- 流程已办
- 常见问题
- 表单管理
- 预留字段
- 字段定义
- 业务应用
- 动态辅表
- 辅表定义
- 辅表应用
- 辅表监控
- 动态主表
- 主表定义
- 业务定义
- 元数据
- 产生机制
- 应用场景
- 02、技术平台
- 重要组件
- 表单引擎
- 流程引擎
- 基础设施
- 系统安全
- 服务集成
- 核心组件
- 核心平台
- 调度容器
- 代码调试
- 相关配置
- 常见问题
- 多线程
- 工作容器
- 开放服务
- 富客户端
- 代理容器
- https
- SSLPinning
- 03、手机应用
- 参数配置
- 技术平台
- 功能设计
- 系统功能
- 应用升级
- 业务模块
- 04、微信应用
- 参数配置
- 多公众号
- 技术平台
- 业务功能
- 平台功能
- 微信客服
- 微信公号
- 05、开放服务
- 接入示例
- 实施方案
- nginx安装
- nginx配置
- nginx运行
- nginx限流
- 实现方案
- 业务操作
- 代码示意
- 06、常见问题
- 性能优化
- 启动优化
- 解决方案
- 实体操作冲突
- 算法说明
- 检验算法
- 注意事项
- 浏览器
- 插件
- 邮箱配置
- 系统维护
- 维护日志
- 维护脚本
- 开发环境
- 07、版权信息
- 平台版权
- 产品版权
- 后记