学习Spring的事务还要源于我在开发中遇到的困难。我的网站Server端是基于S2SH的。问题是这样的:
在Service层我有一个service,部分代码如下:
@Service("userService") @Transactional public class UserServiceImpl implements UserService { private static String getUserByNameHQL = "from User as user where user.userName = ?"; private static String deleteByIDHQL = "delete from User as user where user.id=?"; private static String findLogonInfoHQL = "from LogonValidationInfo as info where info.userName=? and info.sessionid=?"; private static String deleteLogonInfoHQL = "delete from LogonValidationInfo as info where info.userName=? and info.sessionid=?"; private HibernateDaoSupport dao; public HibernateDaoSupport getDao() { return dao; } @Autowired public void setDao(HibernateDaoSupport dao) { this.dao = dao; } public User getUserByName(String userName ) { User user = null; List results = this.dao.getHibernateTemplate().find(getUserByNameHQL, userName); if (results != null && !results.isEmpty()) { user = (User) results.get(0); } return user; }
Dao的继承的Spring提供的HibernateDaoSupport,并通过Spring标注注入到UserService里,dao的代码如下
@Repository public class HibernateGenericDaoImpl extends HibernateDaoSupport{ @Autowired public void setSessionFactoryOverride(SessionFactory sessionFactory) { super.setSessionFactory(sessionFactory); } }
实体类User, Node存在一对多的双向关联关系,实体类比较通俗就不贴出来了,hbm文件如下,User对象通过自己的Set<TimelineNode>映射了一组Node类型。
<class name="User" table="user">
<id name="id" column="uid">
<generator class="increment" />
</id>
<property name="firstName" column="firstname"/>
<property name="lastName" column="lastname"/>
<property name="userPwd" column="password"/>
<property name="userName" column="username"/>
<set name="nodes" inverse="true" cascade="all" lazy="true"
table="timelinenode">
<key column="user_id" not-null="true"></key>
<one-to-many class="TimeLineNode"/>
</set>
</class>
<class name="TimeLineNode" table="timelinenode"> <id name="ID" column="id"> <generator class="increment" /> </id> <property name="startDate" type="date"> <column name="starttime" sql-type="datetime" /> </property> <property name="endDate" type="date"> <column name="endtime" sql-type="datetime" /> </property> <property name="headline" type="text" column="header"> </property> <property name="text" type="text" column="article"> <property name="isStartNode" column="titleSlide" /> <property name="tags" /> <property name="media" /> <property name="credit" /> <property name="caption" /> <property name="bgrImg" column="bgrimg" /> <many-to-one name="author" class="User" lazy="false" column="user_id" cascade="all"> </many-to-one> </class>
调用过程是UserAction->UserService->Dao
UserAction的入口方法:</property>public String login() {
............... User user = null; try { user = userService.getUserByName(uname); Set nodes=user.getNodes(); //lazy load ,sesseion closed exception will throw out here .................. }
红字的那一行,因为在hibernate映射文件里采用了lazy="true"的加载方法,user.getNodes()的时候会从新去数据库中得数据,可是这个时候user对象所处的session已经关闭掉了。会抛出一个异常
org.hibernate.LazyInitializationException: could not initialize proxy - no Session.
解决这个问题有如下几个方案:
一.设置第一个映射文件中lazy="false",采用非延迟加载,不过这样做挺扯淡,我本来就为了系统性能提升才采用的延迟加载策略,这么一改我不就白干了,所以果断否掉,这条也作为解决方案的其中一个的原因则是如果系统性能要求没那么高或者一次性加载的东西并不太占用内存,可以考虑采用这样的方式。
二.Spring提供的方案OpenSessionInView.
Spring提供了OpenSessionInViewInterceptor和OpenSessionInViewFilter这两种方式实现这个解决方案。
这两个主要都是在一个url请求到来的时候为程序打开一个hibernate session,然后请求结束的时候关闭这个session,我没有采用这种解决方案,因为
1.Open Session In View的解决方案存在性能上的争论。
2.我的lazy load发生在action层(这里要讲一下,其实执行lazy load的这段代码完全可以放到service层,只不过这个逻业务逻辑不是很复杂,加上本人手懒,就没有抽到service层里,如果要加入事务的话,最好还是要先抽一下这块代码),不应该讲其范围扩大到整个request范围,还要涉及到request的跳转问题(这个我也不是很确定,不过redirect的话该session应该是失效的,未经测试纯属猜测)。
三.采用hibernate的API手动解析目标代理。通过查阅Hibernate的API,发现了下面这个东东:
Hibernate的静态方法isInitialized
public static boolean isInitialized(Object proxy)
描述如下:
Check if the proxy or persistent collection is initialized.
proxy
- a persistable object, proxy, persistent collection or null
OK,在我这个例子里,参数proxy代表的即是user.getNodes();
修改了一下userService.getUserByName方法:
public User getUserByName(String userName ,boolean initChildren) { User user = null; List results = this.dao.getHibernateTemplate().find(getUserByNameHQL, userName); if (results != null && !results.isEmpty()) { user = (User) results.get(0); } if(user!=null && initChildren){ initializeObject(user.getNodes()); } return user; }
initializeObject方法如下:
public void initializeObject(Object proxy) { Hibernate.initialize(proxy); //To solve the lazy-load problem }
测试,搞定。这个困扰了我几天的问题终于解决了。
相关推荐
这是react-lazy-load-image-component NPM 包的演示。 它既不打算在现实生活中使用,也不是好的编程实践的一个例子,而是要给出一个如何使用包react-lazy-load-image-component及其道具的例子。 观看现场演示: : ...
react-lazy-load, 当子元素进入viewport时,响应它们呈现子元素 延迟加载 组件反应 延迟加载 很容易使用响应组件,它帮助你以可以预测的方式延迟加载内容。 速度快,工作在 IE8+,6KB 缩小,在默认情况下使用去抖...
ng2-image-lazy-load, Angular2图像迟缓加载程序库 当前未维护现在,你可以尝试使用这个伟大的延迟加载 库来实现。 上面的库唯一没有的是Web工作支持- 我希望在未来的某个时候循环,或者者为tjoskar提供辅助。 ng2-...
React惰性负载组件 React Lazy Load是易于使用的React组件,可帮助您以可预测的方式推迟加载内容。...import LazyLoad from 'react-lazy-load' ; const MyComponent = ( ) => ( Scroll to load images. < La
react-use-lazy-load-image使用为延迟加载的图像提供高性能解决方案,该图像不涉及滚动事件侦听器。 IntersectionObserver API仍然很新,因此较旧的浏览器可能不支持此功能,但是对于这些用例,可以使用一些不错的...
Angular-lazy-load-img.zip,发出,Angularjs于2016年发布,是Angularjs的重写版。它专注于良好的移动开发、模块化和改进的依赖注入。angular的设计目的是全面解决开发人员的web应用程序工作流。
react-lazy-load-images
前端项目-jquery-lazyload-any,jquery插件为图像、iframe或任何东西提供了lazyload函数。
懒加载-grunt-config lazy-load-grunt-config是一个Grunt库,允许您按任务分解Gruntfile配置。 它的灵感来自于正在安装npm install lazy-load-grunt-config特征每个任务都有其自己的配置文件。 示例:copy.js,...
Hibernate 的 lazyload 在FLEX中的解决方法例子 用的是gilead 因为LIB包太大上传很慢所以被我删掉了。
不必担心lazyload SEO问题,因为Google已经支持它。 我们只是。安装$ npm install hexo-lazyload-image --save用法首先从您的hexo项目的_config.yml添加配置。 lazyload : enable : true onlypost : false # ...
运行cd angular-lazy-load-demo 为开发服务器运行ng serve 。 导航到http://localhost:4200/ 学到更多 这些示例应该能够帮助您开始动态加载带有或不带有子级的延迟加载组件。 如果您想了解更多信息,请查看以下...
下面小编就为大家带来一篇浅谈spring中的default-lazy-init参数和lazy-init。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
搭建 Struts2+Spring+Hibernate 框架中的 Action 单元测试环境需要解决三个主要问题:如何测试 Action?如何解决 JPA 中的 Lazy 机制?如何做用户 Session 管理?通过使用 StrutsSpringTestCase 和 junit4.jar,可以...
前端项目-vanilla-lazyload,Lazyload是一个快速、轻量级和灵活的脚本,仅在图像即将进入可滚动区域的视区时才加载图像,并对渐进式JPEG图像格式提供了极好的支持。类型脚本模块定义可用。
React图像延迟加载组件一个简单...// Import these bad boys B-|import IronImage from 'react-image-lazy-load-component' ;import 'react-image-lazy-load-component/build/ironImage.css' ;// This is just an exam
前端开源库-markdown-it-lazy-headersMarkdown it Lazy Headers,Lazy ATX Headers插件用于Markdown it
前端开源库-lazy-dependable懒惰可靠,通过懒惰依赖解析实现可靠
适用于vanilla-lazyload的lazyload-vue Vue插件构建状态:功能可与v-lazy-src轻松使用接受选项Vue.use(LazyloadVue,options)适用于vanilla-lazyload的Multipl lazyload-vue Vue插件构建状态:功能可与v-lazy轻松...
一个组件实现lazyload图片当在视窗内(或附近)时才加载