在作业之间共享和更新对象

时间:2014-04-30 07:17:57

标签: spring spring-batch

我有一个控制器,每个请求并行执行几个作业,如下所示:

@Controller
@RequestMapping("/uploadjob")
public class UploadJobController extends BaseController {
....
   @RequestMapping(value = "/uploadjob", method = RequestMethod.POST)
public String runupload(@ModelAttribute("uploadParameters") UploadParameters uploadParameters,
BindingResult result, HttpServletRequest request){
...
 for (Line i: lines){
     try {

           this.jobLauncher.run(this.uploadProjectDataJobNormal, jobParameters);
 }
}

在某些时候,作业从文件中读取元素(在每个作业执行中不同)并复制到表中但删除了重复的元素。

因为作业是并行执行的,所以在插入元素之前的每个作业中,我们查询数据库中的现有元素以避免重复。我们希望使用:

来避免这种情况
 List<String> existingElements

但是这个对象应该由所有作业共享,并且同时由所有作业更新,因此该对象需要是线程安全的。我在这里看到不同的问题,解决方案可以使用会话对象(HttpSession对象)来存储列表并仔细访问对象以避免在作业的步骤中出现竞争条件。

我说错了吗?是否有另一种方法可以实现相同的结果(不改变实际的工作流程)?

1 个答案:

答案 0 :(得分:0)

尝试不同的解决方案后,我们就这样实现了。我们创建一个对象来存储要共享的对象:

public class JobCache {

    private HashMap<TypeClass,Set<String>> ExistingNames;

    private final UUID id;
...

id字段最终用于同步访问属性existingNames。我们使用下一个语句修改了不同作业之间的缓存:

synchronized (jobCache.getId()){
            jobCache.addNames(names,TypeClass.TYPE1);
        }

我们知道这不是完全线程安全的,但在我们的环境下(因为创建作业的方式)。

获取名称(即使不需要,只是为了确定,我们使用这个:

synchronized(jobCache.getId()){
            this.names = jobCache.getExistingNames(TypeClass.TYPE1);
        }

也许它不是理想和最优雅的解决方案,但它对我们有用。