## 一、与主程序事务冲突问题
典型的,如果我们部署一套主程序,一套jobserver或者workserver等,由于两者共享同一个数据库,而两者由于各自事务中,如果一方有某个长时间事务性(比如循环的全表扫描)的锁定某张表的操作,而恰恰对方的业务中需要访问该表,就会抛出 com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction。
解决的方案:将jobserver中,全表扫描的操作,改为短事务,简单的做法,就是循环全表扫描的过程中,每次操作都是一个完整事务的,而不是全部操作放在一个事务里面,更具体来说,就是事务部放到manager层面,而是放在dao层面。
具体的例子:
Manager层面:
事务的:


非事务的:


注意,这里面的dao必须是事务的了,否则,无法修改、删除、新增实体对象。
Job层面:
事务的:

非事务的:

非事务中,对实体的操作:

但是,这里还是有一个问题,就是由于事务控制在dao层面,会导致每个dao操作都会提交事务,对于每一轮循环操作里面组合了若干个dao操作的,这样会出现事务脏数据的问题。
解决的方案是:
继续抽取api,将循环体里面的所有dao操作组合起来,合并为一个api,将事务控制,由原dao层面,提升到该api的事务操作类层面,并将该事务操作类纳入applicationContext-*.xml里面,通过serviceLocator.getObjectFromContext获取即可。

这个方案确保了循环体里面的操作都是完整的事务,循环体之间不是同一个事务,兼顾了事务完整性和避免长事务。
## 二、事务内死循环问题
死循环的操作,除了上述问题之外,即使是一张独占的表,还会带来事务永远无法提交的问题,所以不能用死循环的方式来处理长时间事务的。
比如:


这个方案里面,由于doTest永远无法结束,导致内部的事务无法提交,一直处于事务中。故不能采用这种方案,只能是用减小间隔的方式。
## 三、多job之间事务并发机制
多个job中,如果都循环操作同一个表,会出现脏数据的问题,比如某个job修改后,另外一个job拿到了继续修改,但由于事务未提交,会出现脏数据。
解决办法,用数据库的锁机制解决。平台推荐用乐观锁,增加版本号来解决冲突。具体可以参考《高级指南》中的乐观锁悲观锁章节了解;
## 四、全局单一事务job
有时候,有些业务并非长事务,但需要保障业务事务的完整性,平台提供了一种单一事务job机制。该job里面所有业务逻辑,都在一个事务里面执行,如果执行过程有异常,则会回滚;
具体做法如下:
1、该job与普通job不同,继承自UniframeworkTimerSingleTransactionJob
2、实现自己的事务内操作,实现自己的SingleTransactionJobOperator类
示例如下:

## 五、循环独立事务job
对于长时间的事务,整个job的执行跨度非常长(参考4.1),循环遍历业务,且每个循环的业务都各自独立,互补影响,那么,就非常适合用循环独立事务job,job里面的业务,通过循环来实现,每一轮循环体内的业务,在一个事务里面执行,如果执行过程有异常,则仅循环体内事务回滚,不影响整体job的执行;
具体做法如下:
1、job继承自UniframeworkTimerJob
2、定义自己的manager,logic及api;
各种定义配置如下:

代码实现的时候,特别注意,异常的处理,在logic循环内来处理,否则,因为api层面必须抛出异常,才能实现事务回滚,所以不可以在api里面来处理异常,直接让它抛出即可;
具体的实例明细如下:
Job:

Manager:

Logic:

这里是关键,这里处理异常,确保不会因为一次失败,终止整个调度,仅终止该次循环的调度逻辑,而且能确保该次逻辑也是完整事务的,出错会回滚;这里是在循环体内,捕捉每次api调用的异常;
Api:

Api里面,不要处理异常,直接抛出即可;
## 六、跨数据源job
在一个job中,跨两个数据库进行操作;
首先、uniframework.properties中配置;

server.jobserver.anotherds.enabled必须设定为true,才会加载;
然后、在job中,调用第二数据源的dao,即可;
this.serviceLocator.getJobserverAnotherDatasourceDao()
举例如下:
核心业务代码中,这样来调用第二数据源:

- 前言
- 01、系统平台
- 系统管理
- 组织类型
- 单位管理
- 基本功能
- SAAS功能
- 组织管理
- 角色管理
- 人员管理
- 账号管理
- 账户体系
- 账号绑定
- 账号锁定
- 团队管理
- 模板管理
- 补丁管理
- 字段管理
- 静态字典
- 动态字典
- 系统配置
- 菜单配置
- 路由配置
- 编码规则
- 访问控制
- 系统参数
- 字典配置
- 参数定义
- 参数配置
- 属性定义
- 属性设置
- 树形定义
- 树形设置
- 系统监控
- 业务维护
- 工作监控
- 调度监控
- 导入监控
- 日志管理
- 在线监控
- 附件管理
- 附件监控
- 附件应用
- 附件授权
- 上传监控
- 字段监控
- 系统提醒
- 场景配置
- 事件监控
- 提醒记录
- 事件历史
- 日期设置
- 节假日期
- 工作时间
- 日历编制
- 工作日历
- 开放平台
- 微信应用
- 配置信息
- 更新菜单
- 钉钉应用
- 配置信息
- 开放服务
- 应用设置
- 服务管理
- 请求监控
- 请求跟踪
- 移动应用
- 发布管理
- 导航菜单
- 个人管理
- 个人资料
- 内部消息
- 短信中心
- 流程管理
- 流程定义
- 流程环节
- 处理人
- 流程提醒
- 流程签收
- 流程目录
- 流程微调
- 转移动作
- 定义校验
- 流程绑定
- 流程实体设定
- 单业务多流程
- 动态表单绑定
- 环节字段设定
- 转移路由设定
- 流程监控
- 流程催办
- 流程会话
- 流程启动
- 通用待办
- 流程驱动
- 通用已办
- 示范实例
- 流程启动
- 流程待办
- 流程已办
- 常见问题
- 表单管理
- 预留字段
- 字段定义
- 业务应用
- 动态辅表
- 辅表定义
- 辅表应用
- 辅表监控
- 动态主表
- 主表定义
- 业务定义
- 元数据
- 产生机制
- 应用场景
- 02、技术平台
- 重要组件
- 表单引擎
- 流程引擎
- 基础设施
- 系统安全
- 服务集成
- 核心组件
- 核心平台
- 调度容器
- 代码调试
- 相关配置
- 常见问题
- 多线程
- 工作容器
- 开放服务
- 富客户端
- 代理容器
- https
- SSLPinning
- 03、手机应用
- 参数配置
- 技术平台
- 功能设计
- 系统功能
- 应用升级
- 业务模块
- 04、微信应用
- 参数配置
- 多公众号
- 技术平台
- 业务功能
- 平台功能
- 微信客服
- 微信公号
- 05、开放服务
- 接入示例
- 实施方案
- nginx安装
- nginx配置
- nginx运行
- nginx限流
- 实现方案
- 业务操作
- 代码示意
- 06、常见问题
- 性能优化
- 启动优化
- 解决方案
- 实体操作冲突
- 算法说明
- 检验算法
- 注意事项
- 浏览器
- 插件
- 邮箱配置
- 系统维护
- 维护日志
- 维护脚本
- 开发环境
- 07、版权信息
- 平台版权
- 产品版权
- 后记