java 多线程 出现数据重复调用有关问题

   阅读
java 多线程 出现数据重复调用问题
线程操作过程描述:
1、线程查询数据库表(table1)数据,并遍历修改记录状态(防止出现数据重复调用)。(此操作加入了同步锁)
2、调用接口,获取返回的状态。
3、把数据插入到数据库(table2)中,并删除table1中相应的数据。

贴代码:
数据操作类 messageMgrFacadeImpl
public synchronized List findPushList(HashMap searchMap) {
// TODO Auto-generated method stub
this.status = transactionManager.getTransaction(definition);
definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
//获取全部的未发送信息
List list = this.queryForList("findPushList",
searchMap);
try {
//修改信息状态
for(int n=0;n<list.size();n++){
HashMap listMap = (HashMap)list.get(n);
searchMap.put("smsId", listMap.get("SMS_ID"));
this.update("updatePushListById",searchMap);
}
transactionManager.commit(status);
} catch (Exception e) {
transactionManager.rollback(status);
throw new RuntimeException(e);
}
return list;
}
public synchronized void insertPushLog(HashMap searchMap) {
// TODO Auto-generated method stub
this.status = transactionManager.getTransaction(definition);
definition
.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
try {
this.insert("insertPushLog", searchMap);//添加数据操作记录
this.delete("deletePushList", searchMap);//删除原表记录
transactionManager.commit(status);
} catch (Exception e) {
transactionManager.rollback(status);
throw new RuntimeException(e);
}
}

进程操作类

public class Pusher implements Runnable {
private Message message = new Message();
private HashMap<String, Object> searchMap = new HashMap<String, Object>();
private volatile boolean stop = false;
private MessageMgrFacadeImpl messageMgrFacadeImpl = null;

@Override
public void run() {
// 注入DAO
ApplicationContext context = new ClassPathXmlApplicationContext(
"applicationContext.xml");
messageMgrFacadeImpl = (MessageMgrFacadeImpl) context
.getBean("messageMgrFacade");
searchMap.put("pushTime", DateUtil.getCurrentTimeFull());
searchMap.put("maxCount", Config.getInstance().getMaxCount());
// 获取未发送信息记录
List list = messageMgrFacadeImpl.findPushList(searchMap);
if (list.size() > 0) {
for (int i = 0; i < list.size(); i++) {
HashMap listMap = (HashMap) list.get(i);
System.out.println("++++==" + i + ":" + listMap);
//.....接口操作                         HashMap<String, Object> search = new HashMap<String, Object>();
search.put("smsId", smsId);
search.put("errorCode", returnResult);
search.put("errorMsg", ReturnMessage.getInstance()
.getMsgByCode(returnResult));
// 保存返回信息
messageMgrFacadeImpl.insertPushLog(search);
}
} else {
// 休息1s
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
Log4jInitialize.logger(ManagerThread.class).error(
"Pusher.run方法异常:" + e);
e.printStackTrace();
}
}
}
}

问题:
在执行过程中有部分数据出现重复的现象,由于两张表用的是同一主键标识,造成在插入操作中出现主键重复的错误(特别是在数据库表数据有新数据进入的时候)。

------解决方案--------------------
List list = messageMgrFacadeImpl.findPushList(searchMap);
这里加上同步试试
------解决方案--------------------
数据库加锁,在一个线程用到数据,其他线程不能对这些数据操作,可以等或对出。
但是不针对插入数据,插入数据主键重复的错误,就在生成主键的方法加同步,就可以解决
------解决方案--------------------
这种问题加点日志或debug调试下就能找到原因,我估计事务使用有问题。
------解决方案--------------------
debug 看看具体原因
------解决方案--------------------
不是同步的问题,而是你主键生成方式的问题,主要是因为Table2用的是Table1的主键,Table1删数据之后,重新生成的主键可能会跟着之前被删除的数据的主键一样,但是Table2还有这些主键的数据,所以在插入数据的时候会出现主键重复。可以采取以下方式处理:
1.如果Table1的数据删除了,能否把Table2的中和Table1删除数据的主键一样的也删除,如果可以直接删除就好了;
2.如果Table1的数据删除了,还要保留Table2的中和Table1删除数据的主键一样的数据,那就保证Table1的主键是唯一并且是之前没有出现过的,可以使用数据库的Id自增长生成Table1的主键,或者自己定义一个生成唯一主键的方法,一般是时间戳+随机数。
------解决方案--------------------
阅读