請問要實現類似火車售票機制的功能﹐即當在多個售票點同時售票時所售出的票數量不能超出實際售票數總量﹐也就是當同時售票時應如何去控制或鎖定記錄﹐而不致于扣數不會大于總數。

解决方案 »

  1.   

    首先,系统中应该有一个记录库存火车票数的表.
     
     一个会话需要修改此表时, 先加行锁:
     select  * from tablename where ... for update of tablename.colname
     然后执行update ...
     最后commit; oracle的锁定机制是写阻塞写,因此其他会话在执行update操作时必须等待其他会话
     解锁后才能实现。
     
      

  2.   

    1.1.1 程序描述
    在正常的情况下,不论是售异地票还是售本地票,在确定座位时或者确定票数时都应该首先对票务中心的票源进行锁定。在客运站代理不需要实现该功能,可以直接配置路由,调用票务中心的相关服务。
    函数定义UINT TicketLock (char * szDate;char * szNo;char * szDepot,UINT iTickets,char * szSeat;char * szLockSeat)。
    1.1.2 功能
    对指定的班次相应座位记录进行锁定,请求锁定多个座位,即必须全部同时成功锁定,否则返回错误;如果非指定座位,而是请求票数,由票务中心相关服务进行处理,由当前最小的座位开始锁定,直到锁定所需要的票数,否则返回错误。
    1.1.3 性能
    说明该程序的全部性能要求,包括精度、灵活性和时间特性等性能要求。
    1.1.4 输入项
    项目 类型 名称和定义 说明
    szDate char* szDate 可以为空,为空默认为当前日期。
    szDepot Char* szDepot 票源站编码。以便确定具体的记录。
    szNo char*  szNo 班次号。
    iTickets UINT iTickets 请求锁定的票数,如果是选定座位,票数为1。
    szSeat char* szSeat 需要锁定的座位号。如果座位号为空,则按由小到大的顺序锁定座位直到所需的票数。1.1.5 输出项
    项目 类型 名称和定义 说明
    szLockSeat char* szLockSeat 成功锁定的座位串。多个座位用‘,’号分隔。
    返回值 UINT 0:函数执行成功;1:座位不够;2:网络故障或代理服务器故障;3:在指定座位时,该座位已经被锁住4:输入参数错误;5:流水班,不需要锁定
    1.1.6 算法
    UINT TicketLock (char * szDate,char * szNo,char * szDepot,UINT iTickets,char * szSeat,char * szLockSeat)
    {
    struct ticklock* pstSendBuf;   //发送缓冲,同时也是接收缓冲
    long  lRcvLen;                //接收长度
    int iRet;                     //返回值/* 初始化,加入会话*/
    if (tpinit((TPINIT *) NULL) == -1) {
    /*错误处理*/;
    return 3;
    }
    /* Allocate VIEW32 buffers for the request and the reply */
    pstSendBuf=(struct Ticklock*) tpalloc("VIEW32";"ticklock ";sizeof(struct ticklock));
    if(pstSendBuf == (struct ticklock*) NULL)
    {
    /*处理错误*/;
    tpterm();
    return 2;
    }
    /*将参数的值赋给发送变量*/
    pstSendBuf ->szDate=szDate;
    pstSendBuf ->szNo=szNo;
    pstSendBuf ->szDepot=szDepot;
    pstSendBuf ->iTickets=iTickets;
    pstSendBuf ->szSeat=szSeat;
    /*调用代理的service,注意该名字和票务中心的一致*/
    //如果不在一个事务中
    if (tpgetlev()==0)tpbegin();
    iRet = tpcall("CTicketLock "; (char *) pstSendBuf; 0; (char **)& pstSendBuf; (long *)& rcvlen; 0);
    if(iRet == -1){
     /*错误处理*/
     tpfree((char *)pstSendBuf);
    //如果是在一个事务中
    if (tpgetlev()==1)tpabort();
    tpterm();
    return 3;
    }
    //处理接收
    szLockSeat= pstSendBuf ->szSeat;
    return pstSendBuf ->iErrNo;
    /* 释放内存*/
    tpfree((char *)(char *) RBSche);
    return(0);
    }
      

  3.   

    謝謝beckhambobo,不過我現在的系統為C/S結構不通過路由器﹐而且我用VB來開發的﹐看有什么辦法﹐ leecooper0918的方法如果行得通的話就可以﹐不過我不太熟采﹐可不可講詳細一點。
    比如我先選一個記錄集
      

  4.   

    比如我先要查詢一個記錄集:select*from crtContractClass where Item=ItemNo
    是先用select*from crtContractClass where Item=ItemNo for update of crtContractClass.AQTY 鎖定嗎﹖
    再用﹕select*from crtContractClass where Item=ItemNo 查詢嗎﹖
    因為我要在查詢的結果中選擇一項進行扣數﹐但此時并不立即update數據表﹐因為還要選擇其他項之后一起Update,這時其他用戶不能對這項扣數。能詳細介紹一下嗎﹖在我的crtContractClass保存了Item的余量。