码迷,mamicode.com
首页 > Web开发 > 详细

web系统常见并发问题

时间:2016-05-03 22:14:48      阅读:256      评论:0      收藏:0      [点我收藏+]

标签:

说说考试系统中的一些并发问题吧,这几天着重解决了一下题目这边的并发问题。

其实并发问题不外乎就是:

1.当插入一道试题时,结果这个题目所属的课程被删除掉了;

2.当删除一个课程时,先查时这个课程下的试题没有被使用可以被删除,结果在将将要执行删除语句之前,有一道试题被使用了;

对于第一个问题,其实用外键就可以解决。但是公司似乎有规定,不能够使用外键。主要原因还是外键对于数据库性能的损耗比较严重,特别是当数据量较大时。

其实外键对于我们这个考试系统也是不好使的,因为系统中的删除都是逻辑删除,只是将is_delete置为1而已。外键不好使怎么办?mysql似乎写了check约束也不执行,怎么办?

我开始采用的是触发器的方法。当插入一道试题时,就在course中检查这个courseId的有效性。但这个解决方法并不好,因为即使在触发器中发现该courseId已经无效也不能够中断插入语句,我所做是将插入的新的试题的is_delete字段置为1.也就是说插入的是一道无效试题。

insert触发器
CREATE TRIGGER CheckCourse_BeforeInsert BEFORE INSERT ON question
        FOR EACH ROW
             BEGIN
                if EXISTS(SELECT course.id FROM course WHERE course.id = New.course_id AND course.is_delete = 1) Then
                    SET New.is_delete = 1;
                END IF;
             END;

今天上午经过和DBA吕哥进行沟通,它建议我将select和insert做成一个事务,即先查课程有没有效,有效再继续插入。但是select是不锁表的,所以这里的select是select **** for update。它能够将查询的这个课程id这一行锁住。保证在整个事务内,这一行是不会被修改的。

select for update
SELECT course.is_delete AS isDelete FROM course WHERE course.id = #{courseId} FOR UPDATE;

对于第二个问题,一般就采用乐观锁的思想。我的具体实现是,在执行之前先查询有多少条将要被删除掉,然后执行删除语句,返回实际删除的行数,当发现不一致时,抛出runtimeException进行回滚。

其实这些并发问题可以说是任何一个web系统都会遇到的问题。最好的解决方案,应该是版本号机制。

版本号机制就是为数据库的每一条记录打上版本,每次修改了该记录,版本号加一,每次查询的结果都携带一个版本号。以第二个例子为例,先查询出所有要删除的题目的id,并且携带上版本号,当删除时发现版本不一致时,就表示该条记录被修改过了,进行处理,如抛出异常回滚等。在本次考试系统的数据库中,每一张表都有一个updateTime字段,就可以用来作为版本号。

PS:Spring中的用@Trancational注解标记的方法互相嵌套调用时与是否是同一个线程,同一个类没有关系。只要是Trancational方法,它就会根据propagation属性的值去决定是创建一个新的事务还是加入已存在的事务中。

web系统常见并发问题

标签:

原文地址:http://www.cnblogs.com/userrain/p/5456572.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!