日期:2014-05-20  浏览次数:20741 次

多线程并发处理
数据库里有两个表A,表B,结构一样。
需要做的是把表A的数据拿出来,处理后放到表B。
现在我是用线程取,每10秒调用一次存储过程。
每次取100条数据。
存储过程如下:

UPDATE t_tableA SET PushStatus =0 WHERE PushStatus=-1 limit 100
SELECT ID,Name,Content FROM t_tableA WHERE PushStatus = 0;
INSERT INTO t_tableB SELECT * FROM t_tableA WHERE PushStatus = 0;
DELETE FROM t_tableA WHERE PushStatus=0;

然后线程如下

package cn;

public class Thread implements Runnable{

private String sendUrl ;
private int milliSecond ;

public SmsSendThread(String sendUrl, String milliSecond) {
this.sendUrl=sendUrl;
this.milliSecond=Integer.parseInt(milliSecond);
}

public void run() {
while(true){
try {
Thread.sleep(milliSecond);
Service.getInstance().send(sendUrl);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

在Service类的send方法里调用了存储过程取数据,处理数据,并返回值后按照ID进行处理成功的标识更改。
我首先起了一个线程调用三次 如下

Thread sst = new Thread(sendUrl,milliSecond);
new Thread(sst).start();
new Thread(sst).start();
new Thread(sst).start();


速度增加了,但是肯定会有重复的数据。

怎么才能让在没有重复数据的情况下增加处理的速度呢?

如没明白可提问我再补充
多线程

------解决方案--------------------
引用:


UPDATE t_tableA SET PushStatus =0 WHERE PushStatus=-1 limit 100
SELECT ID,Name,Content FROM t_tableA WHERE PushStatus = 0;
INSERT INTO t_tableB SELECT * FROM t_tableA WHERE PushStatus = 0;
DELETE FROM t_tableA WHERE PushStatus=0;

先分析一下,如果像楼主那样处理,会发生什么样的冲突:
1、对于update来说,不同线程间的update不会有影响,因为数据库会处理这个冲突。
2、对于select来说,如果在delete前又有线程update,就会出现重复的数据,这样造成重复的处理;
3、对于insert来说,如果在delete前又有线程insert,就会造成重复的数据插入t_tableB表。
4、对于delete来说,如果一个线程刚update完,还没来得及select和insert,另一个线程就delete了,那么数据就会丢失。
……这里的冲突很多,就不一一列举了。

首先提个建议,楼主之前分别用PushStatus=-1表示未处理,PushStatus=0表示处理中/完毕。
可以再引入一个状态来区分处理中和处理完毕。如PushStatus=0表示处理中,PushStatus=2表示处理完毕。
------------------------------------------

宗旨:减少冲突,减少阻塞,提高并发,尽量批量操作。

方案1-模仿CAS的无阻塞算法:     【缩小更新的粒度】
1、先找出符合要求的100条;
SELECT ID,Name,Content FROM t_tableA WHERE PushStatus=-1 limit 100
2、处理每条数据,处理前先更新,更新成功后再处理。(这样能避免数据的重复处理,把同步的任务交给了数据库)
UPDATE t_tableA SET PushStatus=0 WHERE PushStatus=-1 AND ID=:ID
3、对该条数据进行insert和delete,此处的修改都是按照ID的,所以不会造成冲突。
点评:没有使用锁,线程间不用阻塞等待。但是每条数据都要分开更新,如果每条数据处理时间很短的话,那么效率就会大打折扣。

方案2-读取锁
1、更新-读取-更新:先更新是为了批量获取,获取后再更新是为了批量占用已选数据。
把这个过程锁起来,保证每次读的时候不会冲突,这样就不会产生重复处理的数据了。
UPDATE t_tableA SET PushStatus=0 WHERE PushStatus=-1 limit 100;
SELECT ID,Name,Content FROM t_tableA WHERE PushStatus = 0;
UPDATE t_tableA SET PushStatus=2 WHERE PushStatus=0;
点评:在读取的时候加锁,读取和占用更新都是批量的,既解决了数据冲突的问题,也大大减少数据库的操作次数。
但是,由于加了读取锁,所以要尽量增大每次读取的数量,减少读取的次数,否则锁竞争会影响效率。