利用行级锁判断多任务并发完成

5台设备分布式处理30项任务,在30项任务全部处理完成时发送邮件通知,需要在最后一个任务完成时触发邮件发送动作,实现方式:

1、程序中实现,在程序中synchronized变量表示剩余任务数;

2、编写触发器?兼容多数据库比较麻烦;

3、利用数据库在程序中判断,行级锁保证数据准确性;

1)每次更新已完成任务数后查询剩余的任务数,为0时表示任务完成,每个任务需要查询一次;

2)利用update语句执行成功时返回更新记录数,特意让最后一次更新记录数为0(不成功),以下为模拟代码:

/** 处理每个任务,finished为true表示最后一个任务 */
public static int doTask(boolean finished) 
{
    int result = 0;// 执行update语句更新数据库总记录数

    Connection conn = null;
    PreparedStatement stmt = null;
    try {
        conn = DriverManager.getConnection(
                "jdbc:oracle:thin:@192.168.100.2:1521:orcl",
                "h2do", "h2do");
        
        if(!finished){
            //
            // TODO:处理其他数据
            // 先提交,减少更新完成任务数的锁定时间
            conn.commit();
        }

        /* 条件finished=total-1时表示最后一个任务,<total-1时才能更新成功,最后一个任务更新失败 */
        stmt = conn.prepareStatement(
                "update t_progress set finished = finished + 1 where id = ? and finished < total - ?");
        stmt.setInt(1, 1);
        stmt.setInt(2, finished ? 0 : 1);

        result = stmt.executeUpdate();
        /*
         * 也可在这里select total-finished from t_progress where id = 1
         * 根据未完成数判断是否所有任务均已完成
         */
        conn.commit();

    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        try {if (null != stmt)stmt.close();} catch (Exception e) {}
        try {if (null != conn)conn.close();} catch (Exception e) {}
    }

    return result;
}

public static void main(String[] args) throws Throwable
{
    oracle.jdbc.driver.OracleDriver.class.newInstance();

    /*模拟30个任务并发处理*/
    for (int i = 0; i < 30; i++) 
    {
        new Thread(new Runnable() {
            @Override
            public void run() {
                int result = doTask(false);
                if (0 == result) {
                    result = doTask(true);
                    if(1 == result){
                        System.out.println("发送所有任务完成邮件。。。");
                    }else{
                        //TODO:记录日志;
                    }
                }
            }
        }).start();
    }
    
}

附:

create table t_progress

(

  id       integer not null,

  total    integer not null,

  finished integer default 0 not null,

  constraint pk_t_progress primary key (id)

);

insert into t_progress (ID, TOTAL, FINISHED) values (1, 30, 0);


你可能感兴趣的:(并发任务)