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

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);

时间: 2024-10-02 14:40:35

利用行级锁判断多任务并发完成的相关文章

MySQL学习笔记(五):MySQL表级锁和行级锁

一:概述 相对其他数据库而言,MySQL的锁机制比较简单,其最显著的特点是不同的存储引擎支持不同的锁机制.比如,MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking):InnoDB存储引擎既支持行级锁( row-level locking),也支持表级锁,但默认情况下是采用行级锁. MySQL主要的两种锁的特性可大致归纳如下:? 表级锁: 开销小,加锁快:不会出现死锁(因为MyISAM会一次性获得SQL所需的全部锁):锁定粒度大,发生锁冲突的概率最高,并发度最

MySQL行级锁、表级锁、页级锁详细介绍

原文链接:http://www.jb51.net/article/50047.htm 页级:引擎 BDB.表级:引擎 MyISAM , 理解为锁住整个表,可以同时读,写不行行级:引擎 INNODB , 单独的一行记录加锁 表级,直接锁定整张表,在你锁定期间,其它进程无法对该表进行写操作.如果你是写锁,则其它进程则读也不允许行级,,仅对指定的记录进行加锁,这样其它进程还是可以对同一个表中的其它记录进行操作.页级,表级锁速度快,但冲突多,行级冲突少,但速度慢.所以取了折衷的页级,一次锁定相邻的一组记

MySQL行级锁,表级锁,页级锁详解

页级:引擎 BDB. 表级:引擎 MyISAM , 理解为锁住整个表,可以同时读,写不行 行级:引擎 INNODB , 单独的一行记录加锁 表级,直接锁定整张表,在你锁定期间,其它进程无法对该表进行写操作.如果你是写锁,则其它进程则读也不允许 行级,,仅对指定的记录进行加锁,这样其它进程还是可以对同一个表中的其它记录进行操作. 页级,表级锁速度快,但冲突多,行级冲突少,但速度慢.所以取了折衷的页级,一次锁定相邻的一组记录. MySQL 5.1支持对MyISAM和MEMORY表进行表级锁定,对BD

Mysql事务及行级锁的理解

在最近的开发中,碰到一个需求签到,每个用户每天只能签到一次,那么怎么去判断某个用户当天是否签到呢?因为当属表设计的时候,每个用户签到一次,即向表中插入一条记录,根据记录的数量和时间来判断用户当天是否签到. 这样的话就会有一个问题,如果是在网速过慢的情况下,用户多次点击签到按钮,那么变会发送多次请求,可能会导致一天多次签到,重复提交的问题,那么很自然的想到用事务.这次用的是spring + mybtais的框架,一开始设计的代码大致如下: public boolean signIn(SignInH

【转】MySQL中的行级锁,表级锁,页级锁

在计算机科学中,锁是在执行多线程时用于强行限制资源访问的同步机制,即用于在并发控制中保证对互斥要求的满足. 在数据库的锁机制中介绍过,在DBMS中,可以按照锁的粒度把数据库锁分为行级锁(INNODB引擎).表级锁(MYISAM引擎)和页级锁(BDB引擎 ). 行级锁 行级锁是Mysql中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁.行级锁能大大减少数据库操作的冲突.其加锁粒度最小,但加锁的开销也最大.行级锁分为共享锁 和 排他锁. 特点 开销大,加锁慢:会出现死锁:锁定粒度最小,发生锁冲

[数据库事务与锁]详解五: MySQL中的行级锁,表级锁,页级锁

注明: 本文转载自http://www.hollischuang.com/archives/914 在计算机科学中,锁是在执行多线程时用于强行限制资源访问的同步机制,即用于在并发控制中保证对互斥要求的满足. 在数据库的锁机制中介绍过,在DBMS中,可以按照锁的粒度把数据库锁分为行级锁(INNODB引擎).表级锁(MYISAM引擎)和页级锁(BDB引擎 ). 行级锁 行级锁是Mysql中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁.行级锁能大大减少数据库操作的冲突.其加锁粒度最小,但加锁的

Mysql事务及行级锁

事务隔离级别 数据库事务隔离级别,只是针对一个事务能不能读取其它事务的中间结果. Read Uncommitted (读取未提交内容) 在该隔离级别,所有事务都可以看到其他未提交事务的执行结果.本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少.读取未提交的数据,也被称之为脏读( Dirty Read ). Read Committed (读取提交内容) 这是大多数数据库系统的默认隔离级别(但不是 MySQL 默认的).它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变.这

Mysql 的表级锁和行级锁

表级锁 MySQL表级锁分为读锁和写锁. 读锁 用法:LOCK TABLE table_name [ AS alias_name ] READ 释放锁使用UNLOCK tables.可以为表使用别名,如果一旦使用别名在使用的时候也必须采用别名.成功申请读锁的前提是当前没有线程对该表使用写锁,否则该语句会被阻塞.申请读锁成功后,其他线程也可以对该表进行读操作,但不允许有线程对其进行写操作,就算是当前线程也不允许.当锁住了A表之后,就只能对A表进行读操作,对其他表进行读操作会出现错误(tablena

SQL Server 中 ROWLOCK 行级锁

一.ROWLOCK的使用 1.ROWLOCK行级锁确保,在用户取得被更新的行,到该行进行更新,这段时间内不被其它用户所修改.因而行级锁即可保证数据的一致性,又能提高数据操作的并发性. 2.ROWLOCK告诉SQL Server只使用行级锁,ROWLOCK语法可以使用在SELECT,UPDATE和DELETE语句中. 3.例如select语句中 A 连接中执行 SET TRANSACTION ISOLATION LEVEL REPEATABLE READ begin tran select * f