使用场景:在一张表中,有2条数据重复。排查发现,是由于jms消费时,由于多个一样的消息同时消费,而在消费代码中,处理逻辑比较复杂,导致事务比较长,因此就会出现并发。
消费代码逻辑块中,有包含以下逻辑:
Student student = studentService.getEntityByName(name);
if(null==student){
student = new Student();
student.setName("aa");
...
this.save(student);
}else{
student.setUpdateTime(new Date());
...
this.update(student);
}
此时线程A消费消息A。线程B消费消息B。(消息A和消息B数据一模一样)。则正常结果应该是student表只有1条数据。但是如果消费及时,就有可能线程A和线程B在执行到上述代码块时,从数据库查询到的student对象都是null,则就会出现数据库保存了2条student。原因是:线程A事务还没提交,而线程B获取不到线程A的对象。
解决方案:
Student studeng = studentService.getEntityByName(name);
if(null == student){
student.setName("aa");
...
}else{
studeng.setUpdateTime(new Date());
}
studentDao.saveOrUpdate(student);
studentDao:
public void saveOrUpdate(Student student){
Map<String, Object> params = new HashMap<>(8);
StringBuffer sql = new StringBuffer("insert into studeng(id, name,updateTime, count)");
sql.append(" values(:id, :name,:updateTime, :count)");
sql.append(" on duplicate key update count=(count+1)");
params.put("id", student.getId());
params.put("name", student.getName());
params.put("updateTime", student.getUpdateTime());
params.put("count", student.getCount());
createSqlQuery(sql.toString(),params).executeUpdate();
}
这种去执行测试,发现,在代码update后面,并没有要更新时间,但是代码执行后,updateTime时间却改变了,而count值并没有被修改到。折腾了好久,才发现问题所在。原因是studeng.setUpdateTime(new Date());这句影响到(至于为什么这句会影响到执行结果,目前还不知道………………)。因此将上面的代码修改为:
Student studeng = studentService.getEntityByName(name);
if(null == student){
student.setName("aa");
...
}
studentDao.saveOrUpdate(student);
studentDao:
public void saveOrUpdate(Student student){
Map<String, Object> params = new HashMap<>(8);
StringBuffer sql = new StringBuffer("insert into studeng(id, name,updateTime, count)");
sql.append(" values(:id, :name,:updateTime, :count)");
sql.append(" on duplicate key update updateTime=:updateTime, count=(count+1)");
params.put("id", student.getId());
params.put("name", student.getName());
if(student.getId() != 0){
params.put("updateTime", new Date());
}else{
params.put("updateTime", student.getUpdateTime());
}
params.put("count", student.getCount());
createSqlQuery(sql.toString(),params).executeUpdate();
}
改为这样,便可正常执行count+1