多线程操作数据库时为了防止数据的增删改的混乱该在数据库层还是程序层面上进行同步? [问题点数:60分,结帖人jiao_zg] 不显示删除回复 显示所有回复 显示星级回复 显示得分回复 只显示楼主 收藏 jiao_zg 水上冰石 结帖率:96.15% 多线程 假设两张表中各有一个字段,是由约束关系的,比如一张表是已经卖出的票的数目,另一张表是还剩余的票的数目。为了操作两张表时保证数据的原子性,应该在数据库层设置还是在程序层做设置?两种方式各有什么优缺点? 更多0 分享到: 发表于: 2014-11-28 17:04:20 楼主 对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理 回复次数:15 csdn官网 官方推荐 Beginning.Spring-Spring入门经典 中文高清完整版pdf 带详细书签 Spring MVC学习指南 Spring实战Spring in Action中文第4版pdf高清完整版(详细书签 无水印 图像增强 文字版+扫描版) 网络围棋 树形结构的数据库 网络信息过滤 Rich Explorer 3.1.1 SpringMVC简介及第一个HelloWorld 进入IT企业必读的324个Java面试题 高清 PDF MulThreadSQLiteTest多线程操作数据库 qq_24018231 周某某_1112 用售票系统来举例 不错 这种问题说明你操作数据层是面向对象的 这样在多线程下会出现剩余票数不一致 这是由于你取数据对象后 还没进行数据操作 其他线程就对数据该条数据操作了 导致你现在纠结的问题 解决方法大致分为两种: 1、利用存储过程,对售票逻辑编写存储过程来保证数据操作的唯一性 2、利用纯SQL语句对售票逻辑进行处理 如: update ticket set restTicket=(restTicket-1) where......... 上面任何一种方法都适用,不过存储过程编写需要一定的基本功,建议使用第二种,简单明了又能有效解决问题 回复于: 2014-11-29 09:54:25 #1 得分:10 对我有用[2] 丢个板砖[0] 引用 | 举报 | 管理 ldh911 MiceRice 基本上是数据库层面为主;程序层面的话因为涉及到要如何解决集群问题,所以比较麻烦。 但如果是12306之类的这种压力规模系统,直接把所有事物管控下推数据库可能将数据库变为瓶颈,所以需要特殊设计。 回复于: 2014-11-29 11:56:05 #2 得分:10 对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理 atgso atgso 两个字:事务 多几个字:不管你在哪个层面,都要对数据库进行事务处理 锁数据是基本的。 回复于: 2014-12-10 23:59:34 #3 得分:10 对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理 atgso atgso 两个字:事务 多几个字:不管你在哪个层面,都要对数据库进行事务处理 锁数据是基本的。 回复于: 2014-12-10 23:59:42 #4 得分:0 对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理 atgso atgso 两个字:事务 多几个字:不管你在哪个层面,都要对数据库进行事务处理 锁数据是基本的。 回复于: 2014-12-10 23:59:48 #5 得分:0 对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理 hqshaozhu 少主无翼 在数据库层面的话就需要通过加锁来控制原子性,事务是无法控制的,因为事务具有隔离性。 举例,现剩余数量是1,有一个线程去读取剩余数据,并进行出票操作,由于这个线程还未提交事务,这时有另一个线程来读取剩余数量,读取到的还是1,所以也进行出票操作,这样就出错了。 如果在应用层面控制的话解决方法可以使用队列,或者加锁并发操作 回复于: 2014-12-16 19:32:10 #6 得分:10 对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理 guixiang155cm _Nick_ 数据层做悲观锁效率太差,且承载资源有限。 1.简单方案:使用cache实例做同步锁 2.复杂方案:使用zookeeper的分布式锁实现(尽量使用锁分段) 假如操作这2张表库存的方法是 abc(int lessStock) getLock(); abc(1); returnLock(); 回复于: 2015-04-01 15:55:06 #7 得分:10 对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理 Javainging Java_er 数据库事务,怎可能会在程序中控制呢 回复于: 2015-05-23 19:20:23 #8 得分:5 对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理 jdmake jdmake 引用 5 楼 atgso 的回复: 两个字:事务 多几个字:不管你在哪个层面,都要对数据库进行事务处理 锁数据是基本的。 事务 提交 回滚 回复于: 2015-06-20 00:53:50 #9 得分:0 对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理 sp1234 以专业开发人员为伍 更多勋章 数据库事务是一种层次,而且这也是需要应用程序显式声明两个sql操作在同一个事务中的。(不知道在应用程序中事务的,就不提了)。 但是能够在内存操作中考虑到需要“原子”操作的,(假设能够用在大系统中的话)是另外一个层次。因为内存操作毕竟会比数据库操作快100倍速度的! 将很关键、很简单的原则操作放在多步业务流程的“最开头”,然后后边的操作就可以尽量异步处理(并且也尽量不加锁)了。而如果你把“修改库存票数”这个操作放在多步业务流程的最后,那么你就会写出一个冗长、严重阻塞整体性能的程序。 回复于: 2015-06-20 01:49:09 #10 得分:0 对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理 sp1234 以专业开发人员为伍 更多勋章 将很关键、很简单的原则操作放在多步业务流程的“最开头” -> 将很关键、很简单的原子操作放在多步业务流程的“最开头” 如果你说“程序层做设置”,它不是还是得修改数据库嘛! 正因为此,有些人很懒,觉得既然一切最终都要记录到数据库,那么干脆就用存储过程写业务逻辑程序就得了。而人家用程序显式地声明事务(将两条update语句封装在一个事务的begin/commit之间),就被他看作是非要辨出个是非曲直的多大事儿出来。 实际上如果不考虑效率,那么程序员随便折腾程序。谁跟老板是亲戚,谁说的就是对的。但是考虑性能需求,用较少的成本产生足以打败竞争对手的高性能、高并发处理能力的需求,这就能分出哪种设计才是更加值得鼓励的了! 回复于: 2015-06-20 01:55:57 #11 得分:0 对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理 sp1234 以专业开发人员为伍 更多勋章 引用 6 楼 hqshaozhu 的回复: 举例,现剩余数量是1,有一个线程去读取剩余数据,并进行出票操作,由于这个线程还未提交事务,这时有另一个线程来读取剩余数量,读取到的还是1,所以也进行出票操作,这样就出错了。 这个事务描述是错误的!一般默认的隔离级别,通常是可以避免幻象读问题的。(更何况还可以自定义更严格级别) 当一个事务读取剩余数量1、而并没有结束出票操作时,另外一个线程启动的事务就不能读取到剩余数量(也就是不能读取到1)。所以这里所谓的“出错”不成立! 回复于: 2015-06-20 02:02:49 #12 得分:0 对我有用[0] 丢个板砖[1] 引用 | 举报 | 管理 sbwwkmyd showjim 在数据库层还是程序层,一般情况下取决于你当前框架的支持。 如果没有任何支持,数据库事务是最佳选择,虽然可能存在性能问题。 如果有成熟的缓存架构支持,那么程序层面的处理优势是绝对毋庸置疑的。 回复于: 2015-06-23 11:43:21 #13 得分:5 对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理 uuuiiiooo099 uuuiiiooo099 引用 12 楼 sp1234 的回复: Quote: 引用 6 楼 hqshaozhu 的回复: 举例,现剩余数量是1,有一个线程去读取剩余数据,并进行出票操作,由于这个线程还未提交事务,这时有另一个线程来读取剩余数量,读取到的还是1,所以也进行出票操作,这样就出错了。 这个事务描述是错误的!一般默认的隔离级别,通常是可以避免幻象读问题的。(更何况还可以自定义更严格级别) 当一个事务读取剩余数量1、而并没有结束出票操作时,另外一个线程启动的事务就不能读取到剩余数量(也就是不能读取到1)。所以这里所谓的“出错”不成立! 是吗? 回复于: 2017-06-05 14:42:29 #14 得分:0 对我有用[0] 丢个板砖[0] 引用 | 举报 | 管理 lin182508 lin182508 事物+乐观离线锁,,更新剩余数量时,验证一下,剩余数量大于1时才能更新,,更新失败,页面可提示,票已卖完,,足够友好 建议楼主查看 企业应用架构模式 第十六章离线并发模式