一次奇怪的assertOpen Issue 解决
2015-12-02 15:00
423 查看
好久没写Blog,最近事多,人忙。现在有空闲下来说说自己在最近一次jpa问题解决时候的实例。
给出出问题的代码的简单实现如下:
系统使用了IBM Websphere cluster distributed map做为集群的缓存,get函数简单的先从cache拿,拿不到再通过jpa从数据库load数据,由于数据比较复杂,使用了fetchplan来获取需要序列化的部分属性,由于使用了fetchplan,所以不再需要使用transaction来load数据了。
最近我为系统添加了一个新的scheduled task, 每分钟执行一次,在测试中发现每天总能出现2,3次openjpa assertOPEN issue,而且每个节点都会出。每次报错都是在cache.put(id,t)这一行,试图序列化T对象出错,报错的trace stack可能是任何一个操作websphere cache的地方(系统中使用了多个websphere的cache)。打开openjpa的runtime trace level日志,可以看出系统每次实际出错都是在我新加的scheduled的任务执行时,之所以看起来每次错误日志地方不一样是因为cache.put操作的实现可能是在另外一个线程中执行(Websphere daemon batch operation thread)。。。所以任何一个操作websphere cache的get/set都有可能导致报错。
现在说说具体报错原因,之前get方法不在事物中,openjpa实现会在get方法调用loadForCache的时候按照fetchplan要求取出所有需要的数据,而我新加的方法讲get放进事物里,那么问题就出现了,由于openjpa的优化,fetchplan的获取可能不在是即时的(t = service.loadForCache(ID);),而cache.put(id,t)操作的实现可能要在websphere的后台线程里面做处理。。。很明显后台线程处理的时候很可能数据还没有load完,assertOpen异常就出现了。
这个教训告诉我,一定要多去了解你要是用的第三方代码,在事务处理的时候千万要小心不要有代码是提交事务相关信息去其他线程去处理的。。。
要解决这个问题有2个办法,第一个,在loadForCache方法上加上@transactional(propagation=Propagation.REQUIRES_NEW),还有一个就是手动编写transaction相关代码,只把需要的代码放入事务
给出出问题的代码的简单实现如下:
CacheService @Autowired private DistributedMap<ID,T> cache; @Autowired private PersistenceService service; public void get(ID id){ T t = cache.get(id); if(t != null){ return t; } else { t = service.loadForCache(ID); cache.put(id,t); return t; } } Persistent Layer public class PersistenceService { public T loadForCache(ID id){ Query query = createQuery("select t from T where t.id=?"); query.setFetchPlan("detail"); ... } ... } @Entity @FetchGroups({ @FetchGroup(name="detail", attributes={ @FetchAttribute(name="refs") }), ... }) public class T { private ID id; private Map<ID, A> refs = new HashMap<ID,A>(); ... ... } Scheduled task: @Autowired private CacheService cache; @Transactional public void dailyProcess(){ T t = cache.get(id); ...... }
系统使用了IBM Websphere cluster distributed map做为集群的缓存,get函数简单的先从cache拿,拿不到再通过jpa从数据库load数据,由于数据比较复杂,使用了fetchplan来获取需要序列化的部分属性,由于使用了fetchplan,所以不再需要使用transaction来load数据了。
最近我为系统添加了一个新的scheduled task, 每分钟执行一次,在测试中发现每天总能出现2,3次openjpa assertOPEN issue,而且每个节点都会出。每次报错都是在cache.put(id,t)这一行,试图序列化T对象出错,报错的trace stack可能是任何一个操作websphere cache的地方(系统中使用了多个websphere的cache)。打开openjpa的runtime trace level日志,可以看出系统每次实际出错都是在我新加的scheduled的任务执行时,之所以看起来每次错误日志地方不一样是因为cache.put操作的实现可能是在另外一个线程中执行(Websphere daemon batch operation thread)。。。所以任何一个操作websphere cache的get/set都有可能导致报错。
现在说说具体报错原因,之前get方法不在事物中,openjpa实现会在get方法调用loadForCache的时候按照fetchplan要求取出所有需要的数据,而我新加的方法讲get放进事物里,那么问题就出现了,由于openjpa的优化,fetchplan的获取可能不在是即时的(t = service.loadForCache(ID);),而cache.put(id,t)操作的实现可能要在websphere的后台线程里面做处理。。。很明显后台线程处理的时候很可能数据还没有load完,assertOpen异常就出现了。
这个教训告诉我,一定要多去了解你要是用的第三方代码,在事务处理的时候千万要小心不要有代码是提交事务相关信息去其他线程去处理的。。。
要解决这个问题有2个办法,第一个,在loadForCache方法上加上@transactional(propagation=Propagation.REQUIRES_NEW),还有一个就是手动编写transaction相关代码,只把需要的代码放入事务
@Autowired private PlatformTransactionManager txManager; public void dailyProcess(){ T t = cache.get(id); TransactionDefinition def = new DefaultTransactionDefinition(); //def.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRED); //def.setIsolationLevel(DefaultTransactionDefinition.ISOLATION_READ_COMMITTED); TransactionStatus txStatus = txManager.getTransaction(def); boolean result = false; try { result = service.process(t); txManager.commit(txStatus); } catch (Exception e) { result = false; txManager.rollback(txStatus); LOGGER.error("Transfer Error!",e); } return result; }
相关文章推荐
- ios 快速集成环信EaseUI
- vs2010 编译mosquitto win32版本
- Errors running builder 'xx' on project_java
- pt-query-digest查询日志分析工具
- 利用UIImageJPEGRepresentation与UIGraphicsBeginImageContext进行图片压缩的简单比较
- SAP OBYC自动记账的实例说明 +VALUE STRING
- IFeatureClass.Search(IQuery Filter,bool Recycling)第二个参数说明
- Identity Build-编译自动加1
- UISwitch控件的常用属性
- android URI 和 UIL 图片加载问题
- UITextView使用总结
- iOS 一 UIButton用法详解
- UItableView分割线根据文本内容显示
- opencv+Kinect2.0调用Visual Gesture Builder制作的动作
- hue下oozie调度sqoop
- 修改UINavigationController返回按钮颜色
- UICollectionView实现Beginupdates
- UIColor
- Confluence5.8中文PPT、宏乱码解决方法
- oVirt Quick Start Guide