java-多线程编程中,2个线程同时调用一个存储过程…………

问题描述

多线程编程中,2个线程同时调用一个存储过程…………

最近自学的时候遇到了这么一个问题……
要求是这样的:
1.在数据库中新建一个用户状态表。里面包含2个字段。user_status(userid bigint,status int)
userid为自增。
status默认为0;
插入1000条记录。

2.写一个存储过程,从user_status表中获取一条status=0的userid字段的值,取出userid时,需要同时把这条记录对应的status从0修改为1.

3.开启2个线程,在线程中循环调用第2步中的存储过程,直到user_status表中记录全部取完(即status全部为1)。要求:在2个线程中取出的userid不能重复。并把取出的userid,打印到某个文件中,一行一个userid

第一点,没啥问题吧应该,我在数据库里建好了。

第二点的话,我写的存储过程是:

create procedure sp_getuserid
as
declare @userid int
select top 1 @userid=userid from user_status where status=0 order by newid()
update user_status set status=1 where status=0 and userid =@userid
select userid from user_status where userid=@userid

第三点的代码:

public class Status implements Runnable {
    private int num;
    @Override
    public void run() {
        Boolean flag = true;
        while(flag)
        {
            flag=this.writeFile(this.getUserid());
        }
    }
    @SuppressWarnings("unchecked")
    public List<UserBean> getUserid() {
        // 创建数据库连接
        Connection conn = ConnectDb.Connect();
        QueryRunner qRunner = new QueryRunner();
        List<UserBean> list = new ArrayList<UserBean>();
        try {
            list = qRunner.query(conn, "exec sp_getuserid",
                    new BeanListHandler(UserBean.class));
        } catch (Exception e) {
            e.printStackTrace();
        }
        DbUtils.closeQuietly(conn);
        return list;
    }
    public Boolean writeFile(List<UserBean> list) {
        if (list.size()==0)
            return false;
        else {
            try {
                File file = new File("d:/test.txt");
                if (!file.exists())
                    file.createNewFile();
                FileOutputStream out = new FileOutputStream(file, true);
                for (int i = 0; i < list.size(); i++) {
                    StringBuffer sb = new StringBuffer();
                    SimpleDateFormat df = new SimpleDateFormat(
                            "yyyy-MM-dd HH:mm:ss:SSS");
                    sb.append(df.format(new Date()) + " t"
                            + list.get(i).getUserid()+ " t"+this.getNum());
                    sb.append(System.getProperty("line.separator"));
                    out.write(sb.toString().getBytes("utf-8"));
                }
                out.close();
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return true;
            }
        }
    }
    public static void main(String[] args) {
        new Thread(new Status(1)).start();
        new Thread(new Status(2)).start();
    }
    public Status(int num)
    {
        this.num=num;
    }

}

可是到最后,我不能在txt里得到1000条数据,总是缺少一些条目,但是数据库里却更新了……

如果我把存储过程改为

create procedure sp_getuserid
as
Begin TransAction
declare @userid int
declare @errno int
set @errno=0
select top 1 @userid=userid from user_status where status=0 order by newid()
set @errno=@errno+@@error
update user_status set status=1 where status=0 and userid =@userid
set @errno=@errno+@@error
select userid from user_status where userid=@userid
set @errno=@errno+@@error
If @errno>0
Begin
rollback TransAction
end
Else
Begin
Commit TransAction
End

这样运行又会报死锁错误……
好吧,多线程的问题和存储过程不怎么会啊,求指教啊!!

解决方案

我们在这样的情况是这样的
一:在表中新增一个job字段,这个job取序列号;
二:每次执行存储过程时先获取一个序列,并且写在要操作数据的那个表中;
三:做完步骤二的更新后用这个job查询出这个序列的数据进行业务;
四:做完业务后,将job的数据更新为空.

另外有个重置的行程,更新job在处理时有挂死或者超时的情况,比如你的job不为空,但是status一直还是0.过了一个小时还是这样,就必须重置了
这样每个job处理的数据全都是自己的数据.希望给你帮助

解决方案二:

主要是存储过程写得不好,没有做事务控制,可以考虑这样:
1、存错过程:
在存储过程中使用游标,Select ... For Update,这样游标操作当前行时,可以锁定;然后利用游标来更新字段即可,最后也是返回游标的userid;记得用完了要关闭游标;

2、单句执行:
UPDATE user_status SET status=1
OUTPUT INSERTED.userid
WHERE userid = (
Select top 1 userid from user_status where status=0
)
要用PrepareStatement执行,注册好返回参数,具体请咨询Google。

时间: 2024-05-21 06:31:07

java-多线程编程中,2个线程同时调用一个存储过程…………的相关文章

详解Java多线程编程中CountDownLatch阻塞线程的方法_java

直译过来就是倒计数(CountDown)门闩(Latch).倒计数不用说,门闩的意思顾名思义就是阻止前进.在这里就是指 CountDownLatch.await() 方法在倒计数为0之前会阻塞当前线程. CountDownLatch是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待. CountDownLatch 的作用和 Thread.join() 方法类似,可用于一组线程和另外一组线程的协作.例如,主线程在做一项工作之前需要一系列的准备工作,只有这些准备工

Java多线程编程中synchronized线程同步的教程_java

0.关于线程同步 (1)为什么需要同步多线程?线程的同步是指让多个运行的线程在一起良好地协作,达到让多线程按要求合理地占用释放资源.我们采用Java中的同步代码块和同步方法达到这样的目的.比如这样的解决多线程无固定序执行的问题: public class TwoThreadTest { public static void main(String[] args) { Thread th1= new MyThread1(); Thread th2= new MyThread2(); th1.sta

详解Java多线程编程中线程的启动、中断或终止操作_java

线程启动: 1.start() 和 run()的区别说明start() : 它的作用是启动一个新线程,新线程会执行相应的run()方法.start()不能被重复调用. run() : run()就和普通的成员方法一样,可以被重复调用.单独调用run()的话,会在当前线程中执行run(),而并不会启动新线程! 下面以代码来进行说明. class MyThread extends Thread{ public void run(){ ... } }; MyThread mythread = new

详解Java多线程编程中的线程同步方法_java

1.多线程的同步: 1.1.同步机制:在多线程中,可能有多个线程试图访问一个有限的资源,必须预防这种情况的发生.所以引入了同步机制:在线程使用一个资源时为其加锁,这样其他的线程便不能访问那个资源了,直到解锁后才可以访问. 1.2.共享成员变量的例子:成员变量与局部变量: 成员变量: 如果一个变量是成员变量,那么多个线程对同一个对象的成员变量进行操作,这多个线程是共享一个成员变量的. 局部变量: 如果一个变量是局部变量,那么多个线程对同一个对象进行操作,每个线程都会有一个该局部变量的拷贝.他们之间

详解Java多线程编程中LockSupport类的线程阻塞用法_java

LockSupport是用来创建锁和其他同步类的基本线程阻塞原语. LockSupport中的park() 和 unpark() 的作用分别是阻塞线程和解除阻塞线程,而且park()和unpark()不会遇到"Thread.suspend 和 Thread.resume所可能引发的死锁"问题. 因为park() 和 unpark()有许可的存在:调用 park() 的线程和另一个试图将其 unpark() 的线程之间的竞争将保持活性. 基本用法LockSupport 很类似于二元信号量

Java多线程编程中使用Condition类操作锁的方法详解_java

Condition的作用是对锁进行更精确的控制.Condition中的await()方法相当于Object的wait()方法,Condition中的signal()方法相当于Object的notify()方法,Condition中的signalAll()相当于Object的notifyAll()方法.不同的是,Object中的wait(),notify(),notifyAll()方法是和"同步锁"(synchronized关键字)捆绑使用的:而Condition是需要与"互斥

Java多线程编程中synchronized关键字的基础用法讲解_java

多线程编程中,最关键.最关心的问题应该就是同步问题,这是一个难点,也是核心. 从jdk最早的版本的synchronized.volatile,到jdk 1.5中提供的java.util.concurrent.locks包中的Lock接口(实现有ReadLock,WriteLock,ReentrantLock),多线程的实现也是一步步走向成熟化.   同步,它是通过什么机制来控制的呢?第一反应就是锁,这个在学习操作系统与数据库的时候,应该都已经接触到了.在Java的多线程程序中,当多个程序竞争同一

浅谈Java多线程编程中Boolean常量的同步问题_java

在JAVA中通过synchronized语句可以实现多线程并发.使用同步代码块,JVM保证同一时间只有一个线程可以拥有某一对象的锁.锁机制实现了多个线程安全地对临界资源进行访问.   同步代码写法如下:   代码1: Object obj = new Object(); ... synchronized(obj) { //TODO: 访问临界资源 } JAVA的多线程总是充满陷阱,如果我们用Boolean作为被同步的对象,可能会出现以下两种情况:   一. 以为对一个对象加锁,实际同步的是不同对

Java多线程编程中易混淆的3个关键字总结_java

概述 最近在看<ThinKing In Java>,看到多线程章节时觉得有一些概念比较容易混淆有必要总结一下,虽然都不是新的东西,不过还是蛮重要,很基本的,在开发或阅读源码中经常会遇到,在这里就简单的做个总结. 1.volatile volatile主要是用来在多线程中同步变量. 在一般情况下,为了提升性能,每个线程在运行时都会将主内存中的变量保存一份在自己的内存中作为变量副本,但是这样就很容易出现多个线程中保存的副本变量不一致,或与主内存的中的变量值不一致的情况. 而当一个变量被volati