//section 1 *************************************************************************
假设你有一组信息需要展示给客户,因此在应用的主界面有一个链入列表页面的超级链接。用户点击链接,浏览器将转向一个包含“dataTable”定义的页面。现在分为两种情况讨论:
第一种情况:dataTable的preserveDataModel属性设置为“true”,表格中的数据将被请求两次。
1、第一次是在RENDER阶段。HtmlTableTag doEndTag()方法执行完后,由HtmlTableRenderer 请求数据。
2、第二次还是在RENDER阶段。但是这次是由于执行了ViewTag doAfterBody()方法。它导致顺次调用UIViewRoot processSaveState()方法,和HtmlDataTable saveState()方法。更确切的说,由于我们将preserveDataModel属性设置为“true”,当调用saveState()方法保存dataTable状态时,会请求一次数据。这次请求的数据将保存在session(web.xml配置了server state方式)中或客户端(web.xml配置了client state方式,gzipping and base 64编码)
第二种情况:dataTable的preserveDataModel属性设置为“false”,表格中的数据将仅仅请求一次。(因为不需要序列化数据)
1、发生在RENDER阶段。HtmlTableTag doEndTag()方法执行完后,由HtmlTableRenderer 请求数据。
假设你有一组信息需要展示给客户,因此在应用的主界面有一个链入列表页面的超级链接。用户点击链接,浏览器将转向一个包含“dataTable”定义的页面。现在分为两种情况讨论:
第一种情况:dataTable的preserveDataModel属性设置为“true”,表格中的数据将被请求两次。
1、第一次是在RENDER阶段。HtmlTableTag doEndTag()方法执行完后,由HtmlTableRenderer 请求数据。
2、第二次还是在RENDER阶段。但是这次是由于执行了ViewTag doAfterBody()方法。它导致顺次调用UIViewRoot processSaveState()方法,和HtmlDataTable saveState()方法。更确切的说,由于我们将preserveDataModel属性设置为“true”,当调用saveState()方法保存dataTable状态时,会请求一次数据。这次请求的数据将保存在session(web.xml配置了server state方式)中或客户端(web.xml配置了client state方式,gzipping and base 64编码)
第二种情况:dataTable的preserveDataModel属性设置为“false”,表格中的数据将仅仅请求一次。(因为不需要序列化数据)
1、发生在RENDER阶段。HtmlTableTag doEndTag()方法执行完后,由HtmlTableRenderer 请求数据。
// section 2 ****************************************************************************
现在假定刚才包含dataTable的页面已经呈现完毕,用户点击了任何一个commandLink。那么接下来发生的事情,同样分两种情况:
第一种情况:dataTable的preserveDataModel属性设置为“true”,应用请求值和更新模型阶段都不会请求数据。因为数据将直接从先前的序列化数据中获得。
第二种情况:dataTable的preserveDataModel属性设置为“false”。
1、应用请求值阶段将请求数据。
2、更新模型阶段将请求数据。
通过以上分析,现在我们假设preserveDataModel属性设置为“false”,点击commandLink后,应用请求值阶段请求一次数据(DM1),然后更新模型阶段再次请求一次数据(DM2),DM1和DM2可能并不相同。但是由于JSF的DataModel在实现时,假定了DM在一个生命周期中不会发生变化,因此导致在实际开发中存在严重的“过期数据”问题。具体页面表现就是error 500错误。
但是如果我们将preserveDataModel属性设置为“true”,用来更新模型的数据就是在客户端先前看到的数据。这样就可以保证在生命周期内,程序不会发生异常行为。但是如果两次请求/响应之间,后台数据发生变化,这种仅仅将preserveDataModel属性设置为“true”,也不能防止程序取到过期数据。
现在假定刚才包含dataTable的页面已经呈现完毕,用户点击了任何一个commandLink。那么接下来发生的事情,同样分两种情况:
第一种情况:dataTable的preserveDataModel属性设置为“true”,应用请求值和更新模型阶段都不会请求数据。因为数据将直接从先前的序列化数据中获得。
第二种情况:dataTable的preserveDataModel属性设置为“false”。
1、应用请求值阶段将请求数据。
2、更新模型阶段将请求数据。
通过以上分析,现在我们假设preserveDataModel属性设置为“false”,点击commandLink后,应用请求值阶段请求一次数据(DM1),然后更新模型阶段再次请求一次数据(DM2),DM1和DM2可能并不相同。但是由于JSF的DataModel在实现时,假定了DM在一个生命周期中不会发生变化,因此导致在实际开发中存在严重的“过期数据”问题。具体页面表现就是error 500错误。
但是如果我们将preserveDataModel属性设置为“true”,用来更新模型的数据就是在客户端先前看到的数据。这样就可以保证在生命周期内,程序不会发生异常行为。但是如果两次请求/响应之间,后台数据发生变化,这种仅仅将preserveDataModel属性设置为“true”,也不能防止程序取到过期数据。
// section 3 ****************************************************************************
为了最终消除“过期数据”的问题,就必须,无论“浏览”,“编辑”,“删除”,“批量删除”等操作,都通过向backing bean中传递DB中的PRIMARY KEY,它一般是一个UUID,也是业务对象中的IID。
这样每次在backing bean中对数据进行操作针对一个具有唯一标识的数据,可以事先get一下本条数据,从数据库中恢复最新的版本。另外,即使这条数据被其他用户删除了,不存在,也可以给客户一个提示。
参考资料: