AJAX请求并发问题
2012-03-19 21:46
169 查看
最近在开发中遇到一个棘手的问题,在FireFox浏览器中连续展开AJAX树(XTREE+XLoadTree)的多个节点会导致Hibernate抛org.hibernate.exception.GenericJDBCException:can't load entry(…)异常(我们的系统用Ajax树控制数据节点,数据持久层采用Hibernate),但是在IE浏览器下进行同样的操作则不会抛任何异常。
通过异常日志和代码分析发现,在这个异常后面隐藏着Hibernate Session的线程安全问题。当去掉引起该异常的代码时,线程安全的异常警告便会被显示出来。也就是说这个异常只是表象,其实真正导致系统异常的原因是Hibernate Session线程安全。当然,这个不能怪Hibernate,确实是我们的代码在存在并发时重写HibernateSession导致冲突的可能。修正代码后问题得以解决。但令人费解的是,为什么在FireFox会导致Hibernate抛异常,在IE下却完全正常呢?
两种浏览器都是发送Ajax请求到服务器,结果却大相径庭。虽说是服务器端的响应导致了该异常,但不难发现,只有当两个请求同时进行时才可能引起上述的Hibernate的线程安全问题,那么我们就必须假设这样的情况,当使用Firefox浏览器进行AJAX请求时同时发送两个甚至多个相同session id的请求线程到服务器,而IE仅发送一个。
在网上找到一个非常有意思的测试,最终得出这样的结论:IE每次执行一个请求,Firefox一次执行两个请求。这一测试通过验证,结果属实。
三个文件,一个客户端(其中包含 prototype.js 文件):
client.html
[html] view
plaincopy
<scripttypescripttype="text/javascript"src="prototype.js">script>
<script type="text/javascript"src="func.js">script>
<a href="javascript:ajax_get('A')">Click A </a>
<hr />
<a href="javascript:ajax_get('B')">Click B </a>
<hr />
<a href="javascript:ajax_get('C')">Click C </a>
<hr />
<div id="result">Result:<br/>div>
一个 JS:
func.js
[javascript] view
plaincopy
vari = 0;
function ajax_get(action){
i++;
var rand_num = Math.random();
var myajax=newAjax.Request("server.php?action=" + action + "&order=" + i +"&rand=" + rand_num,{method:'get',onComplete:show_result});
$('result').innerHTML += get_date() + " , " + action + i + " : client post.
\n";
}
function show_result(response){
var r_text = response.responseText;
$('result').innerHTML += r_text;
}
function get_date(){
var date = newDate();
return date.getMinutes() + "m" + date.getSeconds();
}
一个服务器端,PHP 文件:
server.php
[php] view
plaincopy
//session_start();
$action=$_GET['action'];
$order=$_GET['order'];
echo date("i\ms").",".$action.$order.": server is start.
\n";
switch($action){
case 'A':
sleep(5);
break;
case 'B':
sleep(2);
break;
case 'C':
break;
}
echo date("i\ms").",".$action.$order.": server is end.
\n";
第一段代码是点 A,B,C 三个链接,分别发送不同的 action 的请求到服务器端。
第二段代码是接收到请求后,A 是等 5 秒后结束,B 是等 2 秒,C 是马上结束,用来模拟 PHP 执行代码的时间。
测试环境:IE6,FireFox,Opera,Windows XP,Apache 2,PHP 5.2.0
测试方法 1:
分别点 A,B,C,慢点点,等前一个回来后再点下一个:
结果:
IE6,FireFox 以及 Opera 结果都类似:
42m52 , A1 : client post.
42m52 , A1 : server is start.
42m57 , A1 : server is end.
42m57 , B1 : client post.
42m57 , B1 : server is start.
42m59 , B1 : server is end.
43m01 , C1 : client post.
43m01 , C1 : server is start.
43m01 , C1 : server is end.
结论:没啥惊讶的,点一个返回一个嘛。
测试方法 2:
分别点 A,C,快点点,不能前一个回来就点后面的,模拟并发:
结果和上面一样,恩,处理两个并发木问题。
测试方法 3:
分别点 A,B,C,快点点,不能前一个回来就点后面的,模拟并发:
结果:
IE6 和 Opera 结果类似:
51m30 , A1 : client post.
51m30 , B2 : client post.
51m30 , C3 : client post.
51m30 , C3 : server is start.
51m30 , C3 : server is end.
51m30 , B2 : server is start.
51m32 , B2 : server is end.
51m30 , A1 : server is start.
51m35 , A1 : server is end.
FireFox:
52m20 , A1 : client post.
52m20 , B2 : client post.
52m20 , C3 : client post.
52m20 , B2 : server is start.
52m22 , B2 : server is end.
52m22 , C3 : server is start.
52m22 , C3 : server is end.
52m20 , A1 : server is start.
52m25 , A1 : server is end.
结论:嘎嘎,有意思了吧,IE6 和 Opera 似乎不受影响,但 FireFox 的结果确是 C 要等 B 执行执行完毕后才开始(看时间,A 和 B 在服务器端都是 52m20 秒开始的,而 C 确是在 B 结束后的时间 5m22 开始执行的),这样可以排除服务器端 PHP 的影响,因为 IE,FireFox 以及 Opera 并没有改变服务器端什么,而返回的结果是不同的,所以 PHP 端顺序执行代码的结论应该是不成立的。
测试方法 4:
分别点 A,A,A,A,C 快点点,不能前一个回来就点后面的,模拟并发:
结果:
IE6:
56m06 , A1 : client post.
56m06 , A2 : client post.
56m06 , A3 : client post.
56m07 , A4 : client post.
56m07 , B5 : client post.
56m07 , B5 : server is start.
56m09 , B5 : server is end.
56m06 , A1 : server is start.
56m11 , A1 : server is end.
56m06 , A2 : server is start.
56m11 , A2 : server is end.
56m06 , A3 : server is start.
56m11 , A3 : server is end.
56m07 , A4 : server is start.
56m12 , A4 : server is end.
FireFox:
56m33 , A1 : client post.
56m33 , A2 : client post.
56m33 , A3 : client post.
56m34 , A4 : client post.
56m34 , B5 : client post.
56m33 , A1 : server is start.
56m38 , A1 : server is end.
56m33 , A2 : server is start.
56m38 , A2 : server is end.
56m38 , A3 : server is start.
56m43 , A3 : server is end.
56m38 , A4 : server is start.
56m43 , A4 : server is end.
56m43 , B5 : server is start.
56m45 , B5 : server is end.
Opera:
57m18 , A1 : client post.
57m19 , A2 : client post.
57m19 , A3 : client post.
57m19 , A4 : client post.
57m20 , B5 : client post.
57m18 , A1 : server is start.
57m23 , A1 : server is end.
57m19 , A2 : server is start.
57m24 , A2 : server is end.
57m19 , A3 : server is start.
57m24 , A3 : server is end.
57m19 , A4 : server is start.
57m24 , A4 : server is end.
57m23 , B5 : server is start.
57m25 , B5 : server is end.
结论:
从上面可以看出,IE6 似乎还是不受影响,而 FireFox 同时发送请求,但执行却是要两个两个执行, Opera 是四个四个执行。所以得到结论是 IE 可以同时发送无数个请求,FireFox 同时发送 2 个,Opera 是 4 个。
从网上查了一下,貌似是和浏览器的进程并发数有关。
更有趣的一个测试:
把上面的 PHP 文件的第 2 行的 session_start 的注释去掉,每次请求都打开一次 session,然后进行上面的测试。
测试方法 2:
IE6,FireFox 以及 Opera 结果类似:
15m03 , A1 : client post.
15m03 , C2 : client post.
15m08 , C2 : server is start.
15m08 , C2 : server is end.
15m03 , A1 : server is start.
15m08 , A1 : server is end.
结论:
貌似 session_start 也占了一个进程,A 和 C 同时发出去,但 C 要等 A 执行完后才开始执行。
测试方法 3:
分别点 A,B,C,快点点,不能前一个回来就点后面的,模拟并发:
IE6 和 FireFox 结果类似:
01m59 , A1 : client post.
01m59 , B2 : client post.
01m59 , C3 : client post.
01m59 , A1 : server is start.
02m04 , A1 : server is end.
02m04 , B2 : server is start.
02m06 , B2 : server is end.
02m06 , C3 : server is start.
02m06 , C3 : server is end.
Opera:
05m07 , A1 : client post.
05m08 , B2 : client post.
05m08 , C3 : client post.
05m07 , A1 : server is start.
05m12 , A1 : server is end.
05m14 , C3 : server is start.
05m14 , C3 : server is end.
05m12 , B2 : server is start.
05m14 , B2 : server is end.
结论:
从上面感觉 session 也占了浏览器的一个进程。从网上找了一下,说是 session 是发送一个 session ID 放到客户端,但我感觉既然是这么发送,应该不可能老占着一个进程啊。
结论是这样的:服务器端同一session_id执行是阻塞的,也就是如果session_id相同,同一时间只能执行一个页面,准确的说是“session_start()”以下的部分。其实将server.php中session_start()的位置换下就知道了。
如果想在用到session的时候达到最初的效果,在合适的地方用session_write_close()保存并关闭session即可。我也是根据楼主的文章才了解到上述这些的,谢谢楼主的分享。
通过异常日志和代码分析发现,在这个异常后面隐藏着Hibernate Session的线程安全问题。当去掉引起该异常的代码时,线程安全的异常警告便会被显示出来。也就是说这个异常只是表象,其实真正导致系统异常的原因是Hibernate Session线程安全。当然,这个不能怪Hibernate,确实是我们的代码在存在并发时重写HibernateSession导致冲突的可能。修正代码后问题得以解决。但令人费解的是,为什么在FireFox会导致Hibernate抛异常,在IE下却完全正常呢?
两种浏览器都是发送Ajax请求到服务器,结果却大相径庭。虽说是服务器端的响应导致了该异常,但不难发现,只有当两个请求同时进行时才可能引起上述的Hibernate的线程安全问题,那么我们就必须假设这样的情况,当使用Firefox浏览器进行AJAX请求时同时发送两个甚至多个相同session id的请求线程到服务器,而IE仅发送一个。
在网上找到一个非常有意思的测试,最终得出这样的结论:IE每次执行一个请求,Firefox一次执行两个请求。这一测试通过验证,结果属实。
三个文件,一个客户端(其中包含 prototype.js 文件):
client.html
[html] view
plaincopy
<scripttypescripttype="text/javascript"src="prototype.js">script>
<script type="text/javascript"src="func.js">script>
<a href="javascript:ajax_get('A')">Click A </a>
<hr />
<a href="javascript:ajax_get('B')">Click B </a>
<hr />
<a href="javascript:ajax_get('C')">Click C </a>
<hr />
<div id="result">Result:<br/>div>
一个 JS:
func.js
[javascript] view
plaincopy
vari = 0;
function ajax_get(action){
i++;
var rand_num = Math.random();
var myajax=newAjax.Request("server.php?action=" + action + "&order=" + i +"&rand=" + rand_num,{method:'get',onComplete:show_result});
$('result').innerHTML += get_date() + " , " + action + i + " : client post.
\n";
}
function show_result(response){
var r_text = response.responseText;
$('result').innerHTML += r_text;
}
function get_date(){
var date = newDate();
return date.getMinutes() + "m" + date.getSeconds();
}
一个服务器端,PHP 文件:
server.php
[php] view
plaincopy
//session_start();
$action=$_GET['action'];
$order=$_GET['order'];
echo date("i\ms").",".$action.$order.": server is start.
\n";
switch($action){
case 'A':
sleep(5);
break;
case 'B':
sleep(2);
break;
case 'C':
break;
}
echo date("i\ms").",".$action.$order.": server is end.
\n";
第一段代码是点 A,B,C 三个链接,分别发送不同的 action 的请求到服务器端。
第二段代码是接收到请求后,A 是等 5 秒后结束,B 是等 2 秒,C 是马上结束,用来模拟 PHP 执行代码的时间。
测试环境:IE6,FireFox,Opera,Windows XP,Apache 2,PHP 5.2.0
测试方法 1:
分别点 A,B,C,慢点点,等前一个回来后再点下一个:
结果:
IE6,FireFox 以及 Opera 结果都类似:
42m52 , A1 : client post.
42m52 , A1 : server is start.
42m57 , A1 : server is end.
42m57 , B1 : client post.
42m57 , B1 : server is start.
42m59 , B1 : server is end.
43m01 , C1 : client post.
43m01 , C1 : server is start.
43m01 , C1 : server is end.
结论:没啥惊讶的,点一个返回一个嘛。
测试方法 2:
分别点 A,C,快点点,不能前一个回来就点后面的,模拟并发:
结果和上面一样,恩,处理两个并发木问题。
测试方法 3:
分别点 A,B,C,快点点,不能前一个回来就点后面的,模拟并发:
结果:
IE6 和 Opera 结果类似:
51m30 , A1 : client post.
51m30 , B2 : client post.
51m30 , C3 : client post.
51m30 , C3 : server is start.
51m30 , C3 : server is end.
51m30 , B2 : server is start.
51m32 , B2 : server is end.
51m30 , A1 : server is start.
51m35 , A1 : server is end.
FireFox:
52m20 , A1 : client post.
52m20 , B2 : client post.
52m20 , C3 : client post.
52m20 , B2 : server is start.
52m22 , B2 : server is end.
52m22 , C3 : server is start.
52m22 , C3 : server is end.
52m20 , A1 : server is start.
52m25 , A1 : server is end.
结论:嘎嘎,有意思了吧,IE6 和 Opera 似乎不受影响,但 FireFox 的结果确是 C 要等 B 执行执行完毕后才开始(看时间,A 和 B 在服务器端都是 52m20 秒开始的,而 C 确是在 B 结束后的时间 5m22 开始执行的),这样可以排除服务器端 PHP 的影响,因为 IE,FireFox 以及 Opera 并没有改变服务器端什么,而返回的结果是不同的,所以 PHP 端顺序执行代码的结论应该是不成立的。
测试方法 4:
分别点 A,A,A,A,C 快点点,不能前一个回来就点后面的,模拟并发:
结果:
IE6:
56m06 , A1 : client post.
56m06 , A2 : client post.
56m06 , A3 : client post.
56m07 , A4 : client post.
56m07 , B5 : client post.
56m07 , B5 : server is start.
56m09 , B5 : server is end.
56m06 , A1 : server is start.
56m11 , A1 : server is end.
56m06 , A2 : server is start.
56m11 , A2 : server is end.
56m06 , A3 : server is start.
56m11 , A3 : server is end.
56m07 , A4 : server is start.
56m12 , A4 : server is end.
FireFox:
56m33 , A1 : client post.
56m33 , A2 : client post.
56m33 , A3 : client post.
56m34 , A4 : client post.
56m34 , B5 : client post.
56m33 , A1 : server is start.
56m38 , A1 : server is end.
56m33 , A2 : server is start.
56m38 , A2 : server is end.
56m38 , A3 : server is start.
56m43 , A3 : server is end.
56m38 , A4 : server is start.
56m43 , A4 : server is end.
56m43 , B5 : server is start.
56m45 , B5 : server is end.
Opera:
57m18 , A1 : client post.
57m19 , A2 : client post.
57m19 , A3 : client post.
57m19 , A4 : client post.
57m20 , B5 : client post.
57m18 , A1 : server is start.
57m23 , A1 : server is end.
57m19 , A2 : server is start.
57m24 , A2 : server is end.
57m19 , A3 : server is start.
57m24 , A3 : server is end.
57m19 , A4 : server is start.
57m24 , A4 : server is end.
57m23 , B5 : server is start.
57m25 , B5 : server is end.
结论:
从上面可以看出,IE6 似乎还是不受影响,而 FireFox 同时发送请求,但执行却是要两个两个执行, Opera 是四个四个执行。所以得到结论是 IE 可以同时发送无数个请求,FireFox 同时发送 2 个,Opera 是 4 个。
从网上查了一下,貌似是和浏览器的进程并发数有关。
更有趣的一个测试:
把上面的 PHP 文件的第 2 行的 session_start 的注释去掉,每次请求都打开一次 session,然后进行上面的测试。
测试方法 2:
IE6,FireFox 以及 Opera 结果类似:
15m03 , A1 : client post.
15m03 , C2 : client post.
15m08 , C2 : server is start.
15m08 , C2 : server is end.
15m03 , A1 : server is start.
15m08 , A1 : server is end.
结论:
貌似 session_start 也占了一个进程,A 和 C 同时发出去,但 C 要等 A 执行完后才开始执行。
测试方法 3:
分别点 A,B,C,快点点,不能前一个回来就点后面的,模拟并发:
IE6 和 FireFox 结果类似:
01m59 , A1 : client post.
01m59 , B2 : client post.
01m59 , C3 : client post.
01m59 , A1 : server is start.
02m04 , A1 : server is end.
02m04 , B2 : server is start.
02m06 , B2 : server is end.
02m06 , C3 : server is start.
02m06 , C3 : server is end.
Opera:
05m07 , A1 : client post.
05m08 , B2 : client post.
05m08 , C3 : client post.
05m07 , A1 : server is start.
05m12 , A1 : server is end.
05m14 , C3 : server is start.
05m14 , C3 : server is end.
05m12 , B2 : server is start.
05m14 , B2 : server is end.
结论:
从上面感觉 session 也占了浏览器的一个进程。从网上找了一下,说是 session 是发送一个 session ID 放到客户端,但我感觉既然是这么发送,应该不可能老占着一个进程啊。
结论是这样的:服务器端同一session_id执行是阻塞的,也就是如果session_id相同,同一时间只能执行一个页面,准确的说是“session_start()”以下的部分。其实将server.php中session_start()的位置换下就知道了。
如果想在用到session的时候达到最初的效果,在合适的地方用session_write_close()保存并关闭session即可。我也是根据楼主的文章才了解到上述这些的,谢谢楼主的分享。
相关文章推荐
- AJAX请求并发问题
- AJAX请求并发问题
- springMVC3和springMVC4解决ajax跨域请求的问题
- 如何解决Ajax请求结果的缓存问题说明
- ajax请求到参数太大获取参数失败问题
- 如何解决Ajax请求结果的缓存问题说明
- ajax请求返回设js变量值问题
- node响应ajax请求:解决COR问题
- 使用jsonp解决ajax请求json跨域问题
- 如何解决Ajax请求结果的缓存问题说明
- 关于ajax跨域请求问题解决
- 在ie中关于ajax请求获得数据缓存问题的解决办法
- 关于ajax post请求跨域问题的解决心得
- 过滤器实现登录拦截需要注意的问题(AJAX请求的处理)
- 完美解决ajax跨域请求的问题
- Web Service (014---webservice使用Jquery、Ajax请求WebService所遇到的跨域问题)
- 解决ajax禁止跨源请求的问题
- 单独将ajax请求放入js文件中URL问题
- Android 客户端请求 Tomcat 并发问题
- jq的ajax请求同步与异步的问题