Java多重提交处理分析

2016-02-19 15:36 3 1 收藏

给自己一点时间接受自己,爱自己,趁着下午茶的时间来学习图老师推荐的Java多重提交处理分析,过去的都会过去,迎接崭新的开始,释放更美好的自己。

【 tulaoshi.com - 编程语言 】

  现代网络站点(web site)的主要任务是显示动态内容。从某些角度看,就是指用户将输入信息发送给网络应用(web application)进行处理之后网络应用再将处理结果发送回用户。某些特别情况下,从用户角度看后端操作运行足够快并且一切正常。但是在有些时候,后端的处理往往会因为出现较多的时间消耗而引起延迟。这种延迟有可能过长而最终使用户认为是其自己的操作错误,他们也许会放弃当前的操作或重新提交请求。

  处理操作运行周期的事件过长并不是一个新问题。Java提供的健壮的线程机制能够建立起后台的任务分配。另外,随着EJB 2.0规范的出现,基于消息的EJB(简称MDB)能够被用来执行后台操作。不过请记住,这些机制是为了处理异步操作而设计的。从你启动了一个线程或后台处理,到某段时间之后你被通知或者是需要查看结果,整个过程完全是异步的。

  对于轻型的长时间运行的一般同步应用仍然会引起大量处理的问题你有何看法?想象一下,一个音乐爱好者登陆她喜欢的网站为一场刚开始售票的演出订票(我想起了最近Bruce Springsteen的演唱会)。在通常情况下,网站会很好的执行并且我们的音乐爱好者能够以她自己的方式买到票。可是,当负载很大时,服务器便会慢下来,使该用户的操作不能顺利进行(用户会以为自己的订购操作失败了),因此她会接二连三的点击"提交"按钮。不幸的是,每一次点击"提交"都把之前的订票操作中止了。

  有很多方法处理这种情况。最显而易见的方法是防止用户重复提交相同请求。另外也可以跟踪用户先前提交的请求并回复先前的提交动作。下图显示了一个简单的服务端小程序(servlet)的输出数据,该程序处理每一个收到的请求,为每一个请求分配一个票号。

  处理简单的提交任务

  图1:简单提交任务处理

  最主要和最有效解决多重提交问题的方法就是防止这种情况发生。下面列出的HTML程序ConcertTickets.html是一个简单的表单,用于获取由用户输入的音乐会名字并提交给服务端小程序(servlet)订票。当网站相应迅速时处理执行的很好。但是,如果网站处于性能很低的状态并且提交的任务处理不够快,用户认为失败后会重新提交。处理过程在表1下的图2中显示。

  表1:ConcertTickets.html

  

01: <html>
02: <head><title>Online Concert Tickets</title></head>
03:
04: <center><h1>Order Tickets</h1></center>
05:
06: <form name="Order" action="./SimpleOrder" method="GET">
07: <table border="2" width="50%" align="center" bgcolor="CCCCCC">
08: <tr><td align="right" width="40%">Concert: </td>
09: <td width="60%"><input type="text" name="Concert" value=""></td></tr>
10:
11: <tr><td colspan="2" align="center">
12: <input type="submit" name="btnSubmit"
13: value="Do Submit"></td></tr>
14: </table>
15: </form>
16: </body>
17: </html>

  图2:重复的任务提交

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com/bianchengyuyan/)

  防止多重提交

  最简单的解决多重提交问题的方法是防止这种情况发生。下面是我们表1中表单程序的一个修改,加入了少量的javascript脚本。内嵌的javascript脚本记录以前提交按钮被点击的次数。在用户再次提交时,将会弹出报警窗口并且表单不会再被提交。我们能够通过给提交按钮加入onClick事件属性来缩短普通提交处理过程的周期。每次提交按钮被点击时,onClick的代码就会执行。在我们这个例子中,会引起javascript脚本函数checksubmitcount()被调用。但仅仅调用一个函数并不会真正起到作用。如果我们只是加入onClick,每次提交按钮被点击时我们会收到弹出的警报,而任务提交也会立即发生。用户会被警告她操作错误,但是请求还是会被提交。这样做仅仅对用户端有了一定的改善。而在服务端结果是一样的:多重提交。

  表2:Concert2.html

  

01: <html>
. . .<!?与表1 :ConcertTickets.html程序02~11相同 //-->
12: <input type="button" name="btnSubmit"
13: value="Do Submit"
14: onClick="checksubmitcount();"></td></tr>
15: </table>
16: </form>
17:
18: <script language="javascript">
19: <!--
20: var submitcount = 0;
21: function checksubmitcount()
22: {
23: submitcount++;
24: if (1 == submitcount )
25: {
26: document.Order.submit();
27: }
28: else
29: {
30: if ( 2 == submitcount)
31: alert("You have already submitted this form");
32: else
33: alert("You have submitted this form"
34: + submitcount.toString()
35: + " times already");
36: }
37: }
38: //-->
39: </script>
40: </body>
41: </html>

  我们能通过更进一步和更精细的改变我们网页的工作方式来解决问题。敏锐的读者可能会注意到对表单添加的改变。程序第12行定义的按钮类型原先为submit,现在改成了button。而网页界面是完全相同的。可是,与表单相关的默认动作(程序第6行,调用服务端小程序)不再是自动执行的了。我们现在能够通过程序控制表单向服务器端的提交,我们的问题也得到了解决,不是么?

  表2当然是一种改善,但我们还是需要一些其他方法。仍然有许多情况会导 致错误。如果用户按下了浏览器的后退键或者刷新了整个网页会怎么样?如果用户的浏览器关闭了javascript的功能或者浏览器不能处理会如何呢?我们还是可以处理这个问题的,但是为了取代防止多重提交,我们需要在后端通过表单处理的服务端小程序处理它们。

  为了理解如何解决多重提交问题,我们必须首先理解服务端小程序会话(sessions)机制。每个人都知道,HTTP协议的固有性质中并不对状态(客户端请求信息的历史记录)进行记录。为了处理状态,我们需要一些方法使浏览器能够将当前请求与其他大量请求联系起来。会话(session)程序提供给我们一个解决这个问题的方案。HttpServlet中的方法doGet()和doPost()使用了两个指定的参数:HttpServletRequest和HttpServletResponse。服务端小程序请求参数使我们能够访问会话(session)。会话为访问和存储状态提供了机制。

  什么才是会话(session)呢?会话(session)包括很多内容:

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com/bianchengyuyan/)

  状态集??由web服务器管理并且由特定用户所有请求所共享的详细表示描述。

  存储空间??通过HttpSession接口至少将HttpServlets所需状态数据和定义存储起来。

  在我们具体了解如何使用服务器端方案解决我们的问题之前,我们还需要了解服务端小程序会话(session)的生命周期。与EJB及其他服务端实体一样,会话在生存期中通过一个定义的状态集运行。下图显示了会话的生命周期。Servlet可在三种特定的状态中转换:不存在(does not exist),新建(new),非新建(not new/或使用中in-use)。

  图3:服务端小程序会话(session)生命周期

  [ 相关贴图 ]

  a) 会话在开始时处于不存在状态。会话从这一状态开始或者由于许多原因而返回到此状态。最主要的原因就是用户以前没有访问过这些状态或者是由于用户脱离(超时)站点或退出使会话被设置为无效。

  b) 当会话被建立时便会从不存在状态进入新建状态。新建与非新建状态的区分是非常重要的,因为HTTP协议不记录状态信息。根据servlet详细说明书描述,在客户端返回会话给服务端之前会话不能够进入非新建状态(即从预期会话转变为当前会话)。这样在客户端不知道或者还没有决定加入会话时会话处于新建状态。

  c) 当会话通过cookie或是重写URL()返回到服务器时,会话就变为使用中或非新建状态。

  d) 通过各种get与set方法继续使用会话会使其维持在使用中状态。

  e) 当会话由于长时间没有被使用而超时或显式的被设为无效则会发生图中所示的5以及6所标识的转移。不同应用服务器用不同方式处理超时。BEA公司的WebLogic使应用部署者能够通过与web应用一起打包的特殊部署描述脚本(weblogic.xml)设置会话超时的时限。

  现在我们了解了会话的生命周期,那么如何获得一个会话并有效的使用它呢?接口HttpServletRequest提供了两个关于会话的方法:

  public HttpSession getSession()返回一个新的会话或一个已存在的会话。

  如果提供一个有效的会话ID(可能是通过cookie)则返回一个存在的会话。返回新的会话可能会有许多原因:用户最初的会话(无法提供有效会话ID);会话超过有效时间(提供了会话ID);一个无效的会话(提供了会话ID);或者是明确指出会话无效(提供了会话ID)。

  public HttpSession getSession(boolean)可能返回新会话、存在的会话或者空。getSession(true)尽可能返回一个存在的会话。否则创建一个新会话。getSession(false) 尽可能返回一个存在的会话否则返回空。

  我们还是只解决了手边一半的问题。我们希望能够跳过会话新建状态并自动的转换到会话使用中状态。我们能够通过重定向浏览器到处理服务端小程序自动的实现这些。表3把服务端小程序会话逻辑和重定向用户端与有效会话到处理服务端小程序的能力结合在一起。

来源:https://www.tulaoshi.com/n/20160219/1609997.html

延伸阅读
用类名定义一个变量的时候,定义的应该只是一个引用,外面可以通过这个引用来访问这个类里面的属性和方法,那们类里面是够也应该有一个引用来访问自己的属性和方法纳?呵呵,JAVA提供了一个很好的东西,就是 this 对象,它可以在类里面来引用这个类的属性和方法。先来个简单的例子: 代码如下: public class ThisDemo {    &n...
当主流计算机应用软件开始迁移到客户/服务器体系结构时,程序员们开始寻找方法以简化使用类似技术并且在结构也类似的工程的开发。这就为现代软件开发框架打好了基础。 随着基于万维网的应用程序服务器的发展及其相关的应用软件的膨胀,支持这些技术的开发框架也随着蓬勃发展。当前,在企业开发领域中出现了许多特别适合于Java J2EE平台的软件开发...
Queue ------------ 1.ArrayDeque, (数组双端队列) 2.PriorityQueue, (优先级队列) 3.ConcurrentLinkedQueue, (基于链表的并发队列) 4.DelayQueue, (延期阻塞队列)(阻塞队列实现了BlockingQueue接口) 5.ArrayBlockingQueue, (基于数组的并发阻塞队列) 6.LinkedBlockingQueue, (基于链表的FIFO阻塞队列) 7.LinkedBlockin...
代码如下: public class TestCyclicBarrier {      private static final int THREAD_NUM = 5;      public static class WorkerThread implements Runnable{          CyclicBarrier barrier;          publ...
J2SE 1.5提供了另一种形式的for循环。借助这种形式的for循环,可以用更简单地方式来遍历数组和Collection等类型的对象。本文介绍使用这种循环的具体方式,说明如何自行定义能被这样遍历的类,并解释和这一机制的一些常见问题。 在Java程序中,要“逐一处理”――或者说,“遍历”――某一个数组或Collection中的元素的时候,一般会使用一个for...

经验教程

655

收藏

75
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部