ColdFusion-预订系统-预订消失

时间:2018-07-06 16:04:06

标签: ms-access coldfusion append

下面的代码是一个简单的预订系统,他们可以预订/注册。真的没有。我遇到的问题是,如果有多个用户在同一时间范围内注册,则ListAppend不会因每个发言而锁定。因此,两者都会签约。但是,如果同时烟雾消失,则可能无法注册用户。

我确定这是一个ListAppend问题,因此他们同时访问了该网站,但附加内容会更新并错过某人。

Kinda喜欢那种现场拍卖,您认为自己是赢家,但最终却不是。

有没有简单的解决方法?使用ColdFusion 2016,MS Access。

      <cfset signedup = #add.signedup# + 1>

      <cfset temp = ValueList(add.userssigned)>

      <cfset temp2 = ListAppend(Temp, "#session.demshinuser_id#", ",")>

      <cfquery name=Update DATASOURCE="#ds#">
      update shindates
      set 
      signedup = #signedup#,
      userssigned = '#temp2#'
      where shinid = '#shinid#'
      </cfquery>

1 个答案:

答案 0 :(得分:3)

问题-比赛条件

问题在于您当前的代码受比赛条件的影响。当多个线程尝试同时读取并写入共享资源时,只有其中一个可以获胜。 当“约翰”和“鲍勃”尝试在同一时间进行注册时,会发生以下情况:

  1. 约翰去报名了。查询报告到目前为止,只有一个用户注册:“ Jane ”。
  2. 与此同时,Bob去注册了。由于John的线程尚未完成,该查询再次报告只有一个用户注册:“ Jane ”。

  3. John的主题更新了该记录,并将其添加到已注册用户的原始列表“ Jane,John ”中。 John's Update

  4. 然后Bob的线程更新了记录,并将其附加到原始列表中:“ Jane,Bob
    Bob's Update

鲍勃的话题获胜,并清除了约翰的话题中的更改。

锁定资源-一次只能有一个线程可以读取和/或修改资源-是解决此问题的唯一可靠方法。

数据库结构

就个人而言,建议您重新设计表格以避免存储列表。除了加剧这种类型的问题之外,数据库根本不是为列表设计的。当数据存储在单独的行中时,它们效果最佳。在可能的情况下,存储列表会导致许多其他问题,例如数据完整性问题和不合格的查询性能。最好创建一个单独的表来将注册存储为单独的记录。

说您的应用程序记录了学生的入学情况,您将有3张表:

  • CREATE TABLE Course (courseId int identity, courseName varchar(100), ....)
  • CREATE TABLE Student (studentId int identity, userName varchar(100), ....)
  • CREATE TABLE Enrollment (courseId int, studentId int)

在添加新记录之前,请检查“注册”表以查看用户是否已经注册,如果已注册,则拒绝该记录。我不使用Access,但是类似这种结构的东西会起作用。用cfqueryparam替换@variables。

    SELECT COUNT(*) AS EnrollmentsFound
    FROM   Enrollment 
    WHERE  courseId = @courseId
    AND    studentId = @studentId 

要确定一门课程是否已满,请执行COUNT(*)。如果计数小于最大容量,则允许插入。否则,拒绝它。使用SQL Server,您可以执行以下操作-进行适当的lock或可序列化的事务。。如果没有其中之一,它仍然会受到竞争条件的影响。当然,机会的窗口比您当前的代码要小,但它仍然存在。

if ((select count(*) from Enrollment where courseId = @courseId) < @maxCapacity) 
begin
    insert into Enrollment (courseId, studentId )
    values (@courseId, @studentId)
end

不幸的是,MS Access可能不支持“如果存在...”,锁定提示或事务。因此,考虑升级到SQL Server或MySQL,这两种方法都提供了更强大的选项。如果您绝对不能升级,则以上内容可能会被重写为两个单独的查询和一个cfif / cfelse。 但是,您仍然必须应用某种锁定方式来避免出现竞争状况。锁定资源-一次只能有一个线程可以读取或修改资源-是解决问题的唯一可靠方法

尽管我讨厌这么说,但是由于MS Access不支持事务AFAIK,因此您可以尝试使用专有的“命名” CFLOCK而不是可序列化的事务。可以,但是坦率地说,它不能替代真实的数据库事务。再次重申,如果可能的话,最好将其升级到更可靠的数据库,从而为IMO提供适当的事务支持。

<!--- Exclusive lock to prevent race conditions / Access ONLY --->
<cflock name="Student_Enrollment_Add" type="exclusive" timeout="5000">

   <cfquery name="getEnrollments" ...>
      SELECT COUNT(*) AS EnrollmentsFound
      FROM   Enrollment 
      WHERE  courseId = <cfqueryparam value="#form.courseId#" cfsqltype="cf_sql_integer">
   </cfquery>

   <cfif getEnrollments.EnrollmentsFound lt maxCapacity>
       <cfquery ...>
          INSERT INTO Enrollment ( .... )
          VALUES ( .... )
       </cfquery>
   </cfif>

</cflock>