{"id":660,"date":"2012-01-22T16:43:14","date_gmt":"2012-01-22T15:43:14","guid":{"rendered":"http:\/\/doanduyhai.wordpress.com\/?p=660"},"modified":"2018-09-14T14:02:57","modified_gmt":"2018-09-14T14:02:57","slug":"jpahibernate-conversational-states-caveats","status":"publish","type":"post","link":"https:\/\/www.doanduyhai.com\/blog\/?p=660","title":{"rendered":"JPA\/Hibernate Conversational States Caveats"},"content":{"rendered":"<p>This article follow on from <a href=\"https:\/\/www.doanduyhai.com\/blog\/?p=278\" title=\"JPA\/Hibernate Global Conversation with Spring\u00a0AOP\" target=\"_blank\">JPA\/Hibernate Global Conversation<\/a> and <a href=\"https:\/\/www.doanduyhai.com\/blog\/?p=593\" title=\"JPA\/Hibernate Temporary Conversations with Spring\u00a0AOP\" target=\"_blank\">JPA\/Hibernate Tempoorary Conversations<\/a>.<\/p>\n<p>We discuss here about the commons issues encountered when using the conversational states design.<\/p>\n<p><!--more--><\/p>\n<h1>I Thread Safety<\/h1>\n<p>It is well known that the Entity Manager is <strong>not thread-safe<\/strong> by nature. Only the Entity Manager Factory is thread-safe. If more than one thread is using the same Entity Manager, you&#8217;ll run into big trouble. There is no point trying to synchronize the Entity Manager operations since it will be a arduous task and very error-prone.<\/p>\n<p>Situations where many threads try to access the same Entity Manager are quite common if you use a JPA conversational state (same Entity Manager for one user unit of work). <\/p>\n<p>If you have a rich client interface for your application with many AJAX interactions, concurrent AJAX requests from the client to the server are likely to occur. In this case, each new request will be served by a distinct HTTP thread (from a thread pool) on the server side and each of them will access the same Entity Manager in the current user session, thus the issue.<\/p>\n<p><a href=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/01\/em_thread_safety.png\"><img loading=\"lazy\" src=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/01\/em_thread_safety.png\" alt=\"\" title=\"EM_Thread_Safety\" width=\"602\" height=\"458\" class=\"aligncenter size-full wp-image-663\" srcset=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/01\/em_thread_safety.png 602w, https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/01\/em_thread_safety-300x228.png 300w\" sizes=\"(max-width: 602px) 100vw, 602px\" \/><\/a><\/p>\n<p>To solve such issues, many solutions exist:<\/p>\n<ol>\n<li>Queue your AJAX calls so only one AJAX request is being processed by the server at a time. The new AJAX request will be sent to the server only upon reception of the result of the previous one.\n<\/li>\n<p>&nbsp;<\/p>\n<li>Display a <strong>waiting popup<\/strong> upon each AJAX request to the server and remove it once the response is received. This waiting popup will prevent the user to perform any other action in between.\n<\/li>\n<p>&nbsp;<br \/>\n<a href=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/01\/waiting_popup.png\"><img loading=\"lazy\" src=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/01\/waiting_popup.png\" alt=\"\" title=\"Waiting_Popup\" width=\"332\" height=\"94\" class=\"aligncenter size-full wp-image-665\" srcset=\"https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/01\/waiting_popup.png 332w, https:\/\/www.doanduyhai.com\/blog\/wp-content\/uploads\/2012\/01\/waiting_popup-300x85.png 300w\" sizes=\"(max-width: 332px) 100vw, 332px\" \/><\/a><\/p>\n<li>Set up a <strong>token system<\/strong> with the Entity Manager being the token itself. In the code section responsible for retrieving the Entity Manager from the user HTTP Session, put a <strong>synchronized<\/strong> block to remove it completely from the session. Any subsequent request trying to access the conversational Entity Manager will get a null value if the current request has not finished processing and has not put the Entity Manager back into the session. In such case, re-direct the request to an error page<\/li>\n<pre class=\"brush: java; title: ; wrap-lines: false; notranslate\" title=\"\">\r\n\r\n\t\t\/\/ Try to get the Entity Manager from the HttpSession\r\n\t\tHttpSession httpSession = ((HttpServletRequest) request).getSession();\r\n\t\tsynchronized(httpSession)\r\n\t\t{\r\n\t\t\tcurrentEmHolder = (EntityManagerHolder) httpSession.getAttribute(this.entityManagerFactoryName);\r\n\t\t\thttpSession.setAttribute(this.entityManagerFactoryName,null);\r\n\t\t\t\r\n\t\t\tif(currentEmHolder == null)\r\n\t\t\t{\r\n\t\t\t\t\/\/Redirect to error page\r\n\t\t\t}\r\n\t\t}\r\n<\/pre>\n<\/ol>\n<h1>II Exception Handling<\/h1>\n<p>According to the litterature, <strong>any exception occuring in the Entity Manager should be considered unrecoverable<\/strong> be cause the latter is in an unknown state and should be closed down. Continuing working with a stale Entity Manager will lead to data corruption and inconsistencies.<\/p>\n<p>In the context of JPA conversational state, the same Entity Manager is used for an entire unit of work. This design makes the conversational Entity Manager very sensitive to runtime exceptions. In case of exception the conversational Entity Manager should be closed down as soon as possible but all the managed entities will become <strong>&#8220;detached&#8221;<\/strong> (the evil detached state we wanted to avoid with conversational states). <\/p>\n<p>If a new Entity Manager is created, the task of merging these entities fall to the applicative code. Needless to say that determining which entities need to be merged is a daunting task.<\/p>\n<p>A smarter solution is to detect any SQL\/JPA related exception, re-direct the request to an error page and <strong>re-initialize<\/strong> all bean references. In this case all <strong>&#8220;detached&#8221;<\/strong> entities will be de-referenced by the reinit process. The user will start a new conversation with a fresh new Entity Manager.<\/p>\n<ol>\n<li>For the <strong>global conversation<\/strong> design, the Servlet filter is the right place to set the exception detecting and fordwarding mecanism.<\/li>\n<pre class=\"brush: java; title: ; wrap-lines: false; notranslate\" title=\"\">\r\n\t\ttry\r\n\t\t{\r\n\t\t\tchain.doFilter(request, response);\r\n\t\t}\r\n\t\tcatch (PersistenceException jpaException)\r\n\t\t{\r\n\t\t\t\/\/ Re-direct to an error page\r\n\t\t\t\/\/ Re-init all view beans to de-reference detached entities\r\n\t\t}\r\n\t\tcatch (HibernateException hibException)\r\n\t\t{\r\n\t\t\t\/\/ Re-direct to an error page\r\n\t\t\t\/\/ Re-init all view beans to de-reference detached entities\r\n\t\t}\t\t\r\n\t\tcatch (DataAccessException daException) \/\/ Spring wrapped exceptions\r\n\t\t{\r\n\t\t\t\/\/ Re-direct to an error page\r\n\t\t\t\/\/ Re-init all view beans to de-reference detached entities\r\n\t\t}\r\n<\/pre>\n<li>For the <strong>temporary conversation<\/strong> design, since there is no central place to capture JPA exceptions, we should rely on Spring AOP to create an around aspect and advise all classes participating in temporary conversations.<\/li>\n<pre class=\"brush: java; title: ; wrap-lines: false; notranslate\" title=\"\">\r\n\t@Pointcut(&amp;quot;execution(public * *(..)) &amp;amp;&amp;amp; @annotation(test.springaop.TemporaryConversationBegin)&amp;quot;)\r\n\tpublic void temporaryConversationBegin()\r\n\t{}\r\n\r\n\t@Pointcut(&amp;quot;execution(public * *(..)) &amp;amp;&amp;amp; @annotation(test.springaop.TemporaryConversationEnd)&amp;quot;)\r\n\tpublic void temporaryConversationEnd()\r\n\t{}\r\n\r\n\t@Pointcut(&amp;quot;execution(public * *(..)) &amp;amp;&amp;amp; args(test.springaop.ConversationEnum,..)&amp;quot;)\r\n\tpublic void temporaryConversationUse()\r\n\t{}\r\n\r\n\t@Around(&amp;quot;temporaryConversationBegin() || temporaryConversationEnd() || temporaryConversationUse()&amp;quot;)\r\n\tpublic Object catchJPAException(ProceedingJoinPoint jp)\r\n\t{\r\n\t\tObject retValue = null;\r\n\t\ttry\r\n\t\t{\r\n\t\t\tretValue = jp.proceed();\r\n\t\t}\r\n\t\tcatch (PersistenceException jpaException)\r\n\t\t{\r\n\t\t\t\/\/ Re-direct to an error page\r\n\t\t\t\/\/ Re-init all view beans to de-reference detached entities\r\n\t\t}\r\n\t\tcatch (HibernateException hibException)\r\n\t\t{\r\n\t\t\t\/\/ Re-direct to an error page\r\n\t\t\t\/\/ Re-init all view beans to de-reference detached entities\r\n\t\t}\t\t\r\n\t\tcatch (DataAccessException daException) \/\/ Spring wrapped exceptions\r\n\t\t{\r\n\t\t\t\/\/ Re-direct to an error page\r\n\t\t\t\/\/ Re-init all view beans to de-reference detached entities\r\n\t\t}\r\n\t\treturn retValue;\r\n\t}\r\n<\/pre>\n<\/ol>\n<p>The exception handling is identical to the one for global conversation<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This article follow on from JPA\/Hibernate Global Conversation and JPA\/Hibernate Tempoorary Conversations. We discuss here about the commons issues encountered when using the conversational states design.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[24,7,16],"tags":[34,36,40],"_links":{"self":[{"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/660"}],"collection":[{"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=660"}],"version-history":[{"count":2,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/660\/revisions"}],"predecessor-version":[{"id":13538,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/660\/revisions\/13538"}],"wp:attachment":[{"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=660"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=660"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.doanduyhai.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=660"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}