insert/update操作失败原因及解决方法

本文探讨了ASP+SQLServer环境下并发插入数据时出现的数据丢失问题。分析了因用户输入错误导致的数据插入失败,并提出了解决方案,包括字段长度调整、特殊字符处理等。
    很奇怪,asp+sql server人数在300人左右的时候,插入数据的操作有数据丢失的情况。

    查了半天,数据库相关表的编号列是primary key,有identity属性,每次自动加一。代码里面显示编号是通过select max(clNum)拿出来的。这样的话,在插入数据成功之后,还需要select一把。
     这里就有个漏洞,如果同时做插入动作的用户很多,对单个用户来说,插入数据之后,可能有很多其他用户也插入数据成功。这时再去取最大编号的话,就不能保证这个号码是这个用户插入的数据。
     到sql server的book online里查了查,sql server提供了取得插入记录后identity值的功能,
   
  • IDENT_CURRENT 返回为任何会话和任何作用域中的特定表最后生成的标识值。

  • @@IDENTITY 返回为当前会话的所有作用域中的任何表最后生成的标识值。

  • SCOPE_IDENTITY 返回为当前会话和当前作用域中的任何表最后生成的标识值。

    sql server7只提供了@@IDENTITY一种,而且没有区分会话和作用域,感觉是后两种的一个合集。
    引入以上概念,修改的代码,可以运行通过。只是有另外一个疑问,如果只是号码错,insert的动作应该成功,数据也应该能查到。但是,实际上用户输入的数据在数据库里没法找到。这个问题先挂着,继续观察。

================================================    

     隔了快一年,以上的问题算是有了个结果。经过sql profiler的监测,以及用户的反馈,经过分析发现,插入数据失败主要的原因还是由于用户输入的数据有问题造成的。这个有问题有不少种情况,例如,数据库里定义的是数字整型字段,而用户输入字母; 例如,定义的字段长度是varchar(100),用户输入超长的字符串; 前一种情况,只要在页面的逻辑上控制输入内容的类型就可以了。

     后一种情况比较有特点,因为用户有时会输入特殊字符,例如单引号,双引号,尖括号等等,这些字符输入后如果要正常显示在页面上,必须要用htmlencode转换一下才可以。正是这个htmlencode出了问题,一个双引号被转换之后,一个字符变成了6个字符(&quote;)。这样如果字符串正好100个字符长度,而里面又有2,3个双引号或是其他特殊字符的话,操作数据库肯定是会失败的。

     所以弄清楚了问题所在,解决起来也就容易了。首先是扩大数据库所定义字段的长度到200,但页面上还是限制长度100。但如果用户输入100个双引号,还不够用呢。不过这个是比较极端的情况,为了节省资源,暂时定义成200的长度。 其次,在连续的数据库操作之后(指update, insert,不包括select)加上检查,如果遇到错误,将提示用户有错误,但操作不回滚。

     这里要做个说明,原本想采用transaction模式来处理操作数据库所遇到的错误。但是,写好代码之后发现,使用transaction模式的性能有很大的问题。可能是操作数据库的步骤多,相关记录被锁住,直到操作结束。这样导致,其他用户无法同时查看相关记录。我用一台机器开两个IE窗口,模拟修改和查看操作时,修改记录就导致查看要等待很久。要是300个用户同时用,那要出大问题了。另外,象这样操作失败的情况不应该作为处理逻辑的一部分,错误只要出现就应改被及时纠正,而不是用一个单独的逻辑去专门处理。所以,只是检查是否有错误,而不回滚操作。

     另外,做个备忘。要在asp页面里实现事务模式有两种,一种是靠页面的事务,一种是数据库自身的事务。页面事务,遇到失败时,把所有操作,不仅仅是数据库事务都回滚。有时会和数据库的事务冲突,而不能正常使用。 数据库事务,只是针对数据库本身的操作,不牵涉页面上其他的逻辑。

     贴两个例子:

     sql server transaction:

Dim   connas   New   ADODB.Connection  
  ...  
   
  Sub   Date_syori()    
  On   Error   GoTo   Err_syori       
          conn.BeginTrans  
          ...  
   
          conn.execute("sql1")  
          ...  
           
          conn.execute("sql2")       
          conn.CommitTrans       
          Set   conn   =   Nothing       
          Exit   Sub       
  Err_syori:       
          conn   .RollbackTrans           
          Set   conn   =   Nothing      
          Exit   Sub       
  End   Sub  

     asp transaction:

<%@ TRANSACTION=Required%>
<%
Option Explicit
On Error Resume Next
Dim oConn, oRS

Set oConn = Server.CreateObject("ADODB.Connection")
oConn.Open "Provider=SQLOleDB;server=servername;Initial Catalog=pubs;uid=sa;pwd="
if err.Number <> 0 Then
    Response.Write "<BR>Error Occurred Opening Connection...<BR>"
    Response.Write "<BR>Error Description:" & err.Description & "...<BR>"
ObjectContext.SetAbort
    Response.End
else
    Response.Write "Connection Opened Successfully...<BR>"
    ObjectContext.SetComplete
End If


oConn.Execute "Select * from Authors"
if err.Number <> 0 Then
    Response.Write "<BR>Error Occurred Executing Query...<BR>"
    Response.Write "<BR>Error Description:" & err.Description & "...<BR>"
    oConn.Close
    Set oConn = Nothing
ObjectContext.SetAbort
Response.End
else
    Response.Write "<BR>Query Completed Successfully...<BR>"
    ObjectContext.SetComplete
End If

oConn.Close
Response.Write "<BR>Connection Closed Successfully...<BR>"
set oConn = Nothing
Response.Write "<BR>Test Completed Successfully...<BR>"

Sub OnTransactionCommit()
Response.Write "<p><b>The Transaction just committed</b>."
Response.Write "This message came from the "
Response.Write "OnTransactionCommit() event handler."
End Sub

Sub OnTransactionAbort()
Response.Write "<p><b>The Transaction just aborted</b>."
Response.Write "This message came from the "
Response.Write "OnTransactionAbort() event handler."
End Sub

%>

### 关于GTM-free模式下的INSERT/UPDATE/DELETE/MERGE操作涉及多个远程查询的解决方案 在分布式数据库环境中,尤其是在GTM-free(Global Transaction Manager Free)模式下执行`INSERT`、`UPDATE`、`DELETE`或`MERGE`操作时,如果这些操作涉及到多个远程查询,则可能会遇到错误。这通常是因为缺乏全局事务协调机制来处理跨节点的数据一致性问题。 #### 错误原因分析 在GTM-free模式下,由于缺少集中式的事务管理器,分布式事务的一致性和隔离性难以保障。当一个SQL语句触发多个远程查询时,可能引发以下问题: - **数据不一致**:不同节点上的事务状态无法统一协调。 - **并发冲突**:多个节点之间的写入操作可能导致死锁或其他并发异常。 - **网络延迟**:远程调用增加了系统的复杂度和潜在失败风险。 这些问题的根本原因是,在GTM-free模式下,传统的两阶段提交协议(2PC)不再适用,因此需要采用其他替代方案来实现分布式事务管理[^5]。 #### 解决方案概述 针对此类问题,可以考虑以下几种方法: 1. **基于补偿的事务模型** 使用SAGA模式或其他补偿型事务框架,通过显式定义每个子事务的成功路径及其对应的回滚逻辑,确保整体流程能够恢复到一致状态。这种方法适用于长时间运行的工作流场景,并且允许一定程度的手动干预[^6]。 2. **引入轻量级事务管理组件** 虽然处于GTM-free环境,但仍可部署专门设计用于简化分布式事务处理的小规模中间件服务作为补充支持工具。例如Apache Flink CDC或者Debezium等技术栈可以帮助捕获变更事件并传播至目标端点完成最终更新动作[^7]。 3. **优化应用层代码结构** 修改应用程序的设计思路,减少单条命令跨越多表或多库的操作频率;尽量把复杂的业务逻辑拆解成更细粒度的任务单元分别独立执行后再汇总结果集返回给客户端展示界面查看[^8]。 4. **增强底层存储引擎能力** 如果条件允许的话,升级现有关系型数据库管理系统版本号以便利用最新特性比如原生JSON字段类型支持等功能从而降低对外部依赖程度进而间接改善性能表现指标数值水平达到预期标准范围之内[^9]。 以下是Python伪代码示例演示如何手动控制事务边界以及实施必要的清理措施以防止单步失败影响后续步骤继续正常运转下去: ```python try: # Step A: Begin transaction on Node X node_x_conn.begin_transaction() # Perform some operations... result_a = perform_operation_on_node_x() if not validate_result(result_a): raise Exception("Validation failed at step A") # Step B: Begin transaction on Node Y based off results from A node_y_conn.begin_transaction() # Use outcome of previous operation here. process_data_in_node_y(result_a) except Exception as e: print(f"Error occurred: {e}") try: # Rollback all changes made so far across involved nodes. rollback_changes(node_x_conn) rollback_changes(node_y_conn) except Exception as rb_e: print(f"Rollback also encountered issues: {rb_e}") finally: close_connections([node_x_conn, node_y_conn]) ``` 以上脚本片段仅作示意用途,请根据实际项目需求调整具体实现细节部分。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值