讨论一个并发线程导致的数据保存失败的问题

  环境:

前端采用异步提交的方式,将选择的多个附件分批发送到服务端

后端采用标准的SpringMVC架构来处理请求,采用声明式事务,控制在service层

现象:

后台保存附件信息到数据库的时候,总是报主键唯一性约束错误

分析:

前端采用的是异步提交,第一个附件正在保存的时候,第二个附件也进入了保存方法,而保存方法的逻辑是先生成主键,然后调用save方法保存数据,那么问题就来了,第一个附件进入保存方法,生成主键,在还没有执行save方法的时候,第二个附件进入了保存方法,也生成了主键,此时生成的主键将会覆盖第一个附件保存时生成的主键,然后无论是第一个附件先执行了save还是第二个附件先执行了save,都将会引发主键唯一性约束错误。

解决方法:

1、修改生成主键的方式,让主键生成也和当前事务产生关系,比如主键是从某张表中获取的,这样数据库会帮你加锁;

2、将整个保存附件信息到数据库的方法加上synchronized关键字,以保证线程安全。

时间: 2024-11-08 15:01:34

讨论一个并发线程导致的数据保存失败的问题的相关文章

asp.net并发请求导致的数据重复插入问题

前段时间工作中,有客户反应了系统中某类待办重复出现两次的情况.我核实了数据之后,分析认为是并发请求下导致的数据不一致性问题,并做了重现.其实这并不是一个需要频繁调用的功能,但是客户连续点击了两次,导致出现了并发问题.除了前端优化,这里重点探讨后台方面代码层面的处理,最终解决问题. 一.情景分析 Asp.net程序部署Web服务,是多主线程并发执行的,当多个用户请求进入同一个后台函数时,后进入的请求有可能会获取到非最新状态的数据. 结合我遇到的实际情况举个例子,假设后台函数Func1,先读取表Ta

time_zone导致的 数据插入失败问题

时区导致的一个数据插入失败的案例: 直接看我贴图,严格的sql_mode模式,时区和服务器时区一致(东八区) 创建一个带有timestamp格式的字段的表tt,往里插入一条记录.可以看到第一条记录插入失败.而从8点之后的插入都能成功. 修改时区为格林威治时区.再次执行插入操作: 可以看到插入成功了. 注意: 现在datetime格式也支持自动更新,且只占据5bytes长度(timestamp占据4bytes),但是datetime支持的时间范围更广泛.因此推荐使用datetime格式的字段类型.

解决办法:由于oracle版本不同导致导入数据时失败

在向一个数据库导入dmp文件时,出现了如下错误 经查询,是由于"导出的dmp文件与导入的数据库的版本不同造成的" 用notepad查看dmp文件的版本,看看是否和数据库版本一致 解决办法: 1.可以直接打开dmp文件,修改版本号 2.如果文件过大无法打开,可以用一个版本修改工具AlxcTools.exe来修改版本即可 工具界面如下 工具下载链接:https://pan.baidu.com/s/1miJWgSK      密码: avq8

启动时创建线程并传递数据

原文地址:https://msdn.microsoft.com/zh-cn/library/ts553s52(v=vs.110).aspx 将数据传递给线程和从线程检索数据 在 .NET Framework 2.0 版中,ParameterizedThreadStart 委托提供了一种简便方法,可以在调用 Thread.Start 方法重载时将包含数据的对象传递给线程. 有关代码示例,请参见 ParameterizedThreadStart. 使用 ParameterizedThreadStar

Disruptor——一种可替代有界队列完成并发线程间数据交换的高性能解决方案

本文翻译自LMAX关于Disruptor的论文,同时加上一些自己的理解和标注.Disruptor是一个高效的线程间交换数据的基础组件,它使用栅栏(barrier)+序号(Sequencing)机制协调生产者与消费者,从而避免使用锁和CAS,同时还组合使用预分配内存机制.缓存行机制(cache line).批处理效应(batch effect)来达到高吞吐量和低时延的目标.目前Disruptor版本已经迭代至3.0,本论文是基于Disruptor1.0写就,在新版本中,相对与1.0版本,其核心设计

Java并发工具类(四):线程间交换数据的Exchanger

简介 Exchanger(交换者)是一个用于线程间协作的工具类.Exchanger用于进行线程间的数据交换.它提供一个同步点,在这个同步点两个线程可以交换彼此的数据.这两个线程通过exchange方法交换数据, 如果第一个线程先执行exchange方法,它会一直等待第二个线程也执行exchange,当两个线程都到达同步点时,这两个线程就可以交换数据,将本线程生产出来的数据传递给对方. Exchanger的应用场景 1.Exchanger可以用于遗传算法,遗传算法里需要选出两个人作为交配对象,这时

Java并发工具类(四)线程间交换数据的Exchanger

简介 Exchanger(交换者)是一个用于线程间协作的工具类.Exchanger用于进行线程间的数据交换.它提供一个同步点,在这个同步点两个线程可以交换彼此的数据.这两个线程通过exchange方法交换数据, 如果第一个线程先执行exchange方法,它会一直等待第二个线程也执行exchange,当两个线程都到达同步点时,这两个线程就可以交换数据,将本线程生产出来的数据传递给对方. Exchanger的应用场景 1,Exchanger可以用于遗传算法,遗传算法里需要选出两个人作为交配对象,这时

演示stop暴力停止线程导致数据不一致的问题,但是有些有趣的发现 (2017-07-03 21:25)

如注释所言 /** * Created by weiwei22 on 17/7/3. * * 这里主要是为了演示stop导致的数据不一致的问题.stop会暴力的结束线程并释放锁,所以有可能在恰好写了一半数据的时候,就被stop并释放了锁. * 读线程此时获得锁就有可能读取到不一致的数据. * 但是发现几个有意思的现象: * 1.如果M<N,那么所有的Thread1线程实例都没有机会执行就被干掉了, * 因为新创建的Thread1的实例t1在执行到(1)处时,休息N毫秒,几乎同时主线程执行到(2)

线程间共享数据的一个例子

[申明:本文仅限于自我归纳总结和相互交流,有纰漏还望各位指出. 联系邮箱:[email protected]] 题目:输入一个整形数组,数组里有正数也有负数. 数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和. 求所有子数组的和的最大值.要求时间复杂度为O(n). 题目分析: 一.如果数组中全部为负数,则返回最大负数值即可 二.当既有正数也有负数的时候: (1)从左往右叠加,如果当前叠加值小于或者等于0,则放弃,叠加总和清0(加一个负数或者0是毫无意义的),从此位置继续重新叠加 (