论坛首页 Java版 Spring

spring下hibernate多数据库解决方案,以及跨库事务的尝试(二)

浏览 947 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
最后更新时间:2007-05-17 关键字: spring 多数据库 事务 hibernate

假设,我配置了两个sessionFatory ,一个是mitSessionFactory,一个是testSessionFactory,如下:

xml 代码
  1. <hibernatesupport>
  2. <item id="mit" bean="mitSessionFactory"/>
  3. <item id="test" bean="testSessionFactory"/>
  4. hibernatesupport>

这个我自己系统配置的一部分,系统会解析他,从而知晓究竟存在多少个sessionFactory,item's XmlNode中的id可以理解会托管客户的客户单位

编号,当然,这个配置完全可以忽略,直接从ApplicationContext中一样可以获取到这样的信息

在客户登陆的时候,系统要记录下该客户所属托管单位,然后通过上面的id找到bean's name ,最后获取这个sessionFactory,托管单位信息一般

都是个编号而已跟己方系统的托管用户管理相结合,一般是保存这个编号在session里面,也可以象asp.net一样,记录在安全凭证里,还不知道JAVA方面有没有类似实现,个人认为asp.net这个方法很值得采用,虽然MS号称安全系数+++++这个观点值得怀疑

首先建立一个类,HibernateSupport ,存放当前请求线程所需sessionFactory


java 代码
  1. public class HibernateSupport {
  2. public static final String HIBERNATE_SESSIONIDKEY = "com.mit.hibernatesupport.factory.id";
  3. private static final Logger logger = Logger.getLogger(HibernateSupport.class);
  4. private static ApplicationContext applicationContext ;
  5. private static boolean singleSession=true;
  6. private static Map factorybeanset;
  7. private static ThreadLocal switchhistory;//ÔÚÇл»²»Í¬sessionFactoryµÄʱºòÓõ½
  8. private static ThreadLocal idset;//¼Ç¼µ±Ç°Ä¬ÈϵÄÍйÜÓû§id,ÔÚʵ¼ÊʹÓÃÖУ¬Õâ¸öÊÇ¿ÉÒÔÈ¡ÏûµôµÄ
  9. private static ThreadLocal curfactory;//µ±Ç°ÕýÔÚʹÓõÄsessionFactory
  10. private static ThreadLocal trace;//Ò»¸ösessionFactory¼¯ºÏ,ÓÃÀ´¼Ç¼Õâ´ÎÏ̵߳÷ÓÃÁËÄÇЩsessionFactory
  11. static
  12. {
  13. idset = new ThreadLocal();
  14. curfactory = new ThreadLocal();
  15. trace = new ThreadLocal();
  16. switchhistory = new ThreadLocal();
  17. }
  18. /**
  19. * set current sessionfactory for the Request
  20. * @param ServletContext
  21. * @param the factory's id defined in courser.xml
  22. */
  23. public static synchronized void setCurrent(ServletContext context,Object id)
  24. {
  25. if (idset.get()==null)
  26. {
  27. idset.set(id);
  28. if (factorybeanset.containsKey(id))
  29. {
  30. if (applicationContext==null)
  31. {
  32. applicationContext =
  33. WebApplicationContextUtils
  34. .getWebApplicationContext(context);
  35. }
  36. curfactory.set((SessionFactory)applicationContext
  37. .getBean((String)factorybeanset.get(id)));
  38. putTrace(idset.get(),(SessionFactory)curfactory.get());
  39. }
  40. }
  41. }
  42. /**
  43. * put the sessionfactory to tracemap
  44. * @see COPenSessionInViewFilter release sessionfactory in tracemap
  45. * @param the factory's id defined in courser.xml
  46. * @param hibernate's sessionfactory
  47. */
  48. private static void putTrace(Object id ,SessionFactory factory)
  49. {
  50. Map tracemap = null;
  51. if (trace.get()==null)
  52. {
  53. tracemap = new HashMap();
  54. trace.set(tracemap);
  55. }
  56. else
  57. {
  58. tracemap = (Map)trace.get();
  59. }
  60. if (!tracemap.containsKey(id))
  61. {
  62. tracemap.put(id, factory);
  63. }
  64. }
  65. /**
  66. * switch current sessionfactory
  67. * @param the factory's id defined in courser.xml
  68. */
  69. public static synchronized void swtichFactory(Object id)
  70. {
  71. if (!idset.get().equals(id) )
  72. {
  73. if (factorybeanset.containsKey(id))
  74. {
  75. SessionFactory oldfactory = (SessionFactory)curfactory.get();
  76. SessionFactory newfactory = (SessionFactory)applicationContext
  77. .getBean((String)factorybeanset.get(id));
  78. curfactory.set(newfactory);
  79. pushHistory(oldfactory);
  80. putTrace(id,newfactory);
  81. bindSessionFactory(newfactory);
  82. }
  83. }
  84. }
  85. /**
  86. * restore sessionfactory from queue of switchhistory
  87. */
  88. public static synchronized void restoreFactory()
  89. {
  90. SessionFactory factory = popHistory();
  91. if (factory!=null)
  92. {
  93. curfactory.set(factory);
  94. }
  95. }
  96. /**
  97. * push old sessionfactory to swithhistory after swtichFactory
  98. * @param hibernate's sessionfactory
  99. */
  100. private static void pushHistory(SessionFactory sessionfactory)
  101. {
  102. LinkedList list = null;
  103. if (switchhistory.get()==null)
  104. {
  105. list = new LinkedList();
  106. switchhistory.set(list);
  107. }
  108. else
  109. {
  110. list = (LinkedList)switchhistory.get();
  111. }
  112. list.add(0,sessionfactory);
  113. }
  114. /**
  115. * pop sessionfactory in queue
  116. */
  117. private static SessionFactory popHistory()
  118. {
  119. if (switchhistory.get()!=null)
  120. {
  121. LinkedList list = (LinkedList)switchhistory.get();
  122. if (list.size()>0)
  123. {
  124. SessionFactory factory = (SessionFactory)list.getFirst();
  125. list.removeFirst();
  126. return factory;
  127. }
  128. }
  129. return null;
  130. }
  131. public static Map getTraceMap()
  132. {
  133. if (trace.get()!=null)
  134. {
  135. return (Map)trace.get();
  136. }
  137. return null;
  138. }
  139. public static SessionFactory getCurrentFactory()
  140. {
  141. return (SessionFactory)curfactory.get();
  142. }
  143. public static synchronized void release()
  144. {
  145. idset.set(null);
  146. curfactory.set(null);
  147. switchhistory.set(null);
  148. trace.set(null);
  149. }
  150. /**
  151. * °ó¶¨sessionFactoryµ½springµÄ×ÊÔ´¹ÜÀí
  152. * @param hibernate's sessionfactory
  153. */
  154. private static synchronized boolean bindSessionFactory(SessionFactory sessionFactory)
  155. {
  156. boolean participate=false;;
  157. if (singleSession) {
  158. // single session mode
  159. if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
  160. // Do not modify the Session: just set the participate flag.
  161. participate = true;
  162. }
  163. else {
  164. logger.debug("Opening single Hibernate Session in OpenSessionInViewFilter");
  165. Session session = getSession(sessionFactory);
  166. if (!TransactionSynchronizationManager.hasResource(sessionFactory))
  167. {
  168. TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
  169. }
  170. }
  171. }
  172. else {
  173. // deferred close mode
  174. if (SessionFactoryUtils.isDeferredCloseActive(sessionFactory)) {
  175. // Do not modify deferred close: just set the participate flag.
  176. participate = true;
  177. }
  178. else {
  179. SessionFactoryUtils.initDeferredClose(sessionFactory);
  180. }
  181. }
  182. return participate;
  183. }
  184. //see SessionFactoryUtils
  185. private static Session getSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {
  186. Session session = SessionFactoryUtils.getSession(sessionFactory, true);
  187. FlushMode flushMode = FlushMode.COMMIT;
  188. if (flushMode != null) {
  189. session.setFlushMode(flushMode);
  190. }
  191. return session;
  192. }
  193. public static synchronized void initSessionFactory(Map res,Class loadclass)
  194. {
  195. factorybeanset =res;
  196. }
  197. public static void setSingleSession(boolean singleSession) {
  198. HibernateSupport.singleSession = singleSession;
  199. }
  200. }
  201. bindSessionFactory·½·¨ºÍgetSession¶¼ÊÇ´ÓspringÖ±½ÓCOPY¹ýÀ´µÄ¡£
  202. Õâ¸öÀàÆäËû·½·¨¿ÉÒÔ²»¹Ü£¬ÔÝʱ¹Ø×¢setCurrentÕâ¸ö·½·¨
  203. if (idset.get()==null)
  204. {
  205. idset.set(id);
  206. if (factorybeanset.containsKey(id)) //factorybeanset°üº¬µÄ¾ÍÊÇÎÒ×Ô¼ºÏµÍ³ÅäÖÃÖÐÄÇÒ»²¿·Ö,key¾ÍÊÇid£¬,value¾ÍÊÇsessionFactory ÔÚspring»·¾³ÖеÄbeanName
  207. {
  208. if (applicationContext==null)
  209. {
  210. applicationContext =
  211. WebApplicationContextUtils
  212. .getWebApplicationContext(context);
  213. }
  214. curfactory.set((SessionFactory)applicationContext
  215. .getBean((String)factorybeanset.get(id)));//ÉèÖõ±Ç°µÄsessionFactory
  216. putTrace(idset.get(),(SessionFactory)curfactory.get());//putµ½µ±Ç°Ï̵߳ÄÒ»¸ö¼Ç¼¼¯
  217. }
  218. }
  219. HibernateSupportFilterÊǸöservlet filter,Ëû»á»ñÈ¡µ±Ç°ÇëÇóµÄÍйÜÓû§±àºÅÈ»ºóµ÷ÓÃsetCurrent
  220. public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
  221. HttpSession session = ((HttpServletRequest)req).getSession();
  222. if (session.getAttribute(HibernateSupport.HIBERNATE_SESSIONIDKEY)!=null)//ÎҰѱàºÅ¼Ç¼ÔÚsessionÖУ¬»ñÈ¡Õâ¸ö±àºÅ
  223. {
  224. Object id = session.getAttribute(HibernateSupport.HIBERNATE_SESSIONIDKEY);
  225. if (log.isDebugEnabled())
  226. {
  227. log.debug("Set Current SessionFactory:"+id.toString());
  228. }
  229. HibernateSupport.setCurrent(config.getServletContext(),session.getAttribute(HibernateSupport.HIBERNATE_SESSIONIDKEY));//µ÷ÓÃsetCurrent
  230. }
  231. try
  232. {
  233. chain.doFilter(req, res);
  234. }
  235. catch (Exception ex)
  236. {
  237. ex.printStackTrace();
  238. }
  239. finally
  240. {
  241. HibernateSupport.release();
  242. }
  243. }

这个类其他方法可以不管,暂时关注setCurrent这个方法


java 代码
  1. if (idset.get()==null)
  2. {
  3. idset.set(id);
  4. if (factorybeanset.containsKey(id)) //factorybeanset包含的就是我自己系统配置中那一部分,key就是id,,value就是sessionFactory 在spring环境中的beanName
  5. {
  6. if (applicationContext==null)
  7. {
  8. applicationContext =
  9. WebApplicationContextUtils
  10. .getWebApplicationContext(context);
  11. }
  12. curfactory.set((SessionFactory)applicationContext
  13. .getBean((String)factorybeanset.get(id)));//设置当前的sessionFactory
  14. putTrace(idset.get(),(SessionFactory)curfactory.get());//put到当前线程的一个记录集
  15. }
  16. }

HibernateSupportFilter是个servlet filter,他会获取当前请求的托管用户编号然后调用setCurrent

java 代码
  1. public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
  2. HttpSession session = ((HttpServletRequest)req).getSession();
  3. if (session.getAttribute(HibernateSupport.HIBERNATE_SESSIONIDKEY)!=null)//ÎҰѱàºÅ¼Ç¼ÔÚsessionÖУ¬»ñÈ¡Õâ¸ö±àºÅ
  4. {
  5. Object id = session.getAttribute(HibernateSupport.HIBERNATE_SESSIONIDKEY);
  6. if (log.isDebugEnabled())
  7. {
  8. log.debug("Set Current SessionFactory:"+id.toString());
  9. }
  10. HibernateSupport.setCurrent(config.getServletContext(),session.getAttribute(HibernateSupport.HIBERNATE_SESSIONIDKEY));//µ÷ÓÃsetCurrent
  11. }
  12. try
  13. {
  14. chain.doFilter(req, res);
  15. }
  16. catch (Exception ex)
  17. {
  18. ex.printStackTrace();
  19. }
  20. finally
  21. {
  22. HibernateSupport.release();
  23. }
  24. }

然后,就要修改spring关于hibernate的一些支持类了,当然,也可以选择重新写一套dao支持类,呵呵,不过,显然,在spring基础上做一些小修改代价更小

HibernateAccessor HibernateTemplate的基类)以及HibernateTransactionManager都是靠注入方式获取一个sessionFactory,显然,这套不适合了,修改之

   
论坛首页 Java版 Spring

跳转论坛:
JavaEye推荐