论坛首页 Java企业应用论坛

如何让在一个线程内DAO对象在一个时刻内只被调用一次?

浏览 9769 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (14) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-04-18  
假设现在有线程TA,TA里的run()方法会调用一个DAO借口实现,DAO里会对一个表进行判断,然后写操作。
public class TA extends Thread{
    BusinessDAO  bDAO;

    public TA(BusinessDAO  daoArg){
        bDAO = daoArg;
    }
  
    public run(){
        boolean b = bDAO.findExist(dataList);
        if(!b){
             bDAO.insert(dataList);
        }else{
             bDAO.update(dataList);
        }
    }
}

请问我现在如何做到就是run()方法体内的代码在一个时刻内只有一个实例在运行?也就是说
bDAO.insert(dataList);这行代码在运新的时候,系统内只有一个dataList被传入,然后跟我的数据库系统已有的数据比较,然后得出结论,然后更新数据库状态。
   这样做的原因是我现在的系统老是出现这样的情况,连续传2次dataList,按说第一次判断系统中没有这个datalist后,将这个dataList的值写入到数据库,那么第2次应该会判断出已经有了这个数据,但是实际情况不是,第二次判断仍然得出是没有的结论。而且在传入多次的情况下,结果都是一样。
   这种结果从表面上看来就好像2次上传,第一次和第二次毫无关系一样,难道是2次是并发执行了?

   请问这可能是什么原因造成的?那么我如何控制这种并发,保证我第一次判断,然后写入,然后才执行我第二次判断,第二次写入。
   这个bug跟我的数据库的事务设置有关吗?
   怎么解决这个问题? 还是要将我的程序设置成Singleton模式的? 怎么将我的程序设置成singleton模式的?

我的程序的实际架构是:Struts1.2+Spring2.0+iBatis3,以上的代码我抽象了一下。 线程TA是通过Spring的
org.springframework.core.task.TaskExecutor来调度的。

   发表时间:2008-04-18  
这和单例无关,即使只有一个实例,那么如果不进行同步的话还是有线程并发。
问题的原因是线程并发的时候,第一线程插入DB表后还没有commit时,第二线程读取了这个表的纪录,当然就会出现你说的问题。
所以解决的方法是:
1、DAO方法执行开始就锁表,如果失败则等待直到超时;
2、Spring可以通过配置只生成一个实例,把BusinessDAO做成单例,然后注入,
但是下面的代码需要写到一个方法内并进行同步。
boolean b = bDAO.findExist(dataList); 
if(!b){ 
bDAO.insert(dataList); 
}else{ 
bDAO.update(dataList); 

改成
bDAO.do(dataList)
void do() {
    boolean b = findExist(dataList); 
    if(!b){ 
        insert(dataList); 
    }else{ 
        update(dataList); 
    }
}
0 请登录后投票
   发表时间:2008-04-18  
可不可以这样做?
将方法
public run(){
boolean b = bDAO.findExist(dataList);
if(!b){
bDAO.insert(dataList);
}else{
bDAO.update(dataList);
}

改成

public run(){
synchronized(this){
boolean b = bDAO.findExist(dataList);
if(!b){
bDAO.insert(dataList);
}else{
bDAO.update(dataList);
}
}

0 请登录后投票
   发表时间:2008-04-18  
taikeqi 写道
可不可以这样做?
将方法
public run(){
boolean b = bDAO.findExist(dataList);
if(!b){
bDAO.insert(dataList);
}else{
bDAO.update(dataList);
}

改成

public run(){
synchronized(this){
boolean b = bDAO.findExist(dataList);
if(!b){
bDAO.insert(dataList);
}else{
bDAO.update(dataList);
}
}



run方法是属于某个线程的方法,不会涉及到多线程的并发。
发生问题的原因是有很多线程也就是很多run方法并发调用DAO或者说并发操作数据库,
所以解决问题的地方也是在DAO或者数据库。
向上面的修改方法我想是不起作用的
0 请登录后投票
   发表时间:2008-04-18  
javazhujf 写道
taikeqi 写道
可不可以这样做?
将方法
public run(){
boolean b = bDAO.findExist(dataList);
if(!b){
bDAO.insert(dataList);
}else{
bDAO.update(dataList);
}

改成

public run(){
synchronized(this){
boolean b = bDAO.findExist(dataList);
if(!b){
bDAO.insert(dataList);
}else{
bDAO.update(dataList);
}
}



run方法是属于某个线程的方法,不会涉及到多线程的并发。
发生问题的原因是有很多线程也就是很多run方法并发调用DAO或者说并发操作数据库,
所以解决问题的地方也是在DAO或者数据库。
向上面的修改方法我想是不起作用的

楼上的说错了吧?
synchronized(this)就是用来防止多线程共享资源的问题,像上面那样加锁,我觉的可行,不过要加事务提交,不然insert的dataList还是不存在吧,并等事务提交好再让另一个线程执行应该不会错的
0 请登录后投票
   发表时间:2008-04-18  
run方法是线程实例的方法,它只是在某个线程内执行。
0 请登录后投票
   发表时间:2008-04-18  
是的但是run方法里面涉及的资源操作
run(){
某个公共资源的操作,
比如你的存款余额,
},
既然继承了线程那这么说,这个类在生命周期内就不会只被调用一次,而且可能是不同的人同时调用,假如你的存款是1000,然后当扣了七七八八的费用电话,水电时候(假设扣了1000),你又去取了1000因为没有加锁,你钱也取了,费用也扣了那不是high死你了,那请问这是并发操作吧,我可以让它在两个线程里跑起来
你觉的不需要synchronized(this)起来吗
0 请登录后投票
   发表时间:2008-04-18  
是我说错了,在run里同步没有问题,
不过按照封装的原则还是最好把同步操作封装到你说的“某个公共资源的操作”的方法里,
也就是楼主的DAO中。
0 请登录后投票
   发表时间:2008-04-18  
是吗,我只是就是论事
楼主的主题如下:
主题:如何让在一个线程内DAO对象在一个时刻内只被调用一次?
,既然楼主要把dao封装到线程里,那在同一个时刻DAO对象要被只被调用一次当然要同步了,当然要不然new两个线程对象,同时执行的话那同一时刻不是有两个dao对象,进行对公共数据的操作了吗
当然你的想法是对的,一般我们只对调用共享资源的方法同步。
0 请登录后投票
   发表时间:2008-04-20  
明明就是一个事务的问题,用的着这么麻烦吗,还是二楼的方法比较好,我觉得
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics