- 浏览: 280183 次
- 性别:
- 来自: 西安
文章分类
最新评论
-
JQ_AK47:
谢谢你的ANT 五篇博文让我对Ant了解入门。
用Ant实现Java项目的自动构建和部署(4) -
lanluo:
这个源码,能给我一份吗?
自定义标签感想 -
mapeijie888:
google 翻译 用的不错
AMF使用简介 -
满分水:
如果有看到,讲解一下,谢谢!
IIs工作原理 -
满分水:
想了解一下IIS服务器是怎样与我们的web应用程序间交互的,终 ...
IIs工作原理
Write operations are not allowed in read-only mode (FlushMode.NEVER)
- 博客分类:
- 异常
使用Spring提供的Open Session In View而引起Write operations are not allowed in read-only mode (FlushMode.NEVER) 错误解决:
在没有使用Spring提供的Open Session In View情况下,因需要在service(or Dao)层里把session关闭,所以lazy loading 为true的话,要在应用层内把关系集合都初始化,如 company.getEmployees(),否则Hibernate抛session already closed Exception; Open Session In View提供了一种简便的方法,较好地解决了lazy loading问题.
它有两种配置方式OpenSessionInViewInterceptor和OpenSessionInViewFilter(具体参看SpringSide),功能相同,只是一个在web.xml配置,另一个在application.xml配置而已。
Open Session In View在request把session绑定到当前thread期间一直保持hibernate session在open状态,使session在request的整个期间都可以使用,如在View层里PO也可以lazy loading数据,如 ${ company.employees }。当View 层逻辑完成后,才会通过Filter的doFilter方法或Interceptor的postHandle方法自动关闭session。
OpenSessionInViewInterceptor配置
- <beans>
- <bean name="openSessionInViewInterceptor"
- class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
- <property name="sessionFactory">
- <ref bean="sessionFactory"/>
- </property>
- </bean>
- <bean id="urlMapping"
- class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
- <property name="interceptors">
- <list>
- <ref bean="openSessionInViewInterceptor"/>
- </list>
- </property>
- <property name="mappings">
- ...
- </property>
- </bean>
- ...
- </beans>
<beans> <bean name="openSessionInViewInterceptor" class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor"> <property name="sessionFactory"> <ref bean="sessionFactory"/> </property> </bean> <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="interceptors"> <list> <ref bean="openSessionInViewInterceptor"/> </list> </property> <property name="mappings"> ... </property> </bean> ... </beans>
OpenSessionInViewFilter配置
- <web-app>
- ...
- <filter>
- <filter-name>hibernateFilter</filter-name>
- <filter-class>
- org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
- </filter-class>
- <!-- singleSession默认为true,若设为false则等于没用OpenSessionInView -->
- <init-param>
- <param-name>singleSession</param-name>
- <param-value>true</param-value>
- </init-param>
- </filter>
- ...
- <filter-mapping>
- <filter-name>hibernateFilter</filter-name>
- <url-pattern>*.do</url-pattern>
- </filter-mapping>
- ..
- </web-app>
- 很多人在使用OpenSessionInView过程中提及一个错误:
- org.springframework.dao.InvalidDataAccessApiUsageException: Write operations
- are not allowed in read-only mode (FlushMode.NEVER) - turn your Session into
- FlushMode.AUTO or remove 'readOnly' marker from transaction definition
<web-app> ... <filter> <filter-name>hibernateFilter</filter-name> <filter-class> org.springframework.orm.hibernate3.support.OpenSessionInViewFilter </filter-class> <!-- singleSession默认为true,若设为false则等于没用OpenSessionInView --> <init-param> <param-name>singleSession</param-name> <param-value>true</param-value> </init-param> </filter> ... <filter-mapping> <filter-name>hibernateFilter</filter-name> <url-pattern>*.do</url-pattern> </filter-mapping> .. </web-app> 很多人在使用OpenSessionInView过程中提及一个错误: org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.NEVER) - turn your Session into FlushMode.AUTO or remove 'readOnly' marker from transaction definition
看看OpenSessionInViewFilter里的几个方法
- protected void doFilterInternal(HttpServletRequest request,
- HttpServletResponse response,FilterChain filterChain)
- throws ServletException, IOException {
- SessionFactory sessionFactory = lookupSessionFactory();
- logger.debug("Opening Hibernate Session in OpenSessionInViewFilter");
- Session session = getSession(sessionFactory);
- TransactionSynchronizationManager.bindResource(
- sessionFactory, new SessionHolder(session));
- try {
- filterChain.doFilter(request, response);
- }
- finally {
- TransactionSynchronizationManager.unbindResource(sessionFactory);
- logger.debug("Closing Hibernate Session in OpenSessionInViewFilter");
- closeSession(session, sessionFactory);
- }
- }
- protected Session getSession(SessionFactory sessionFactory)
- throws DataAccessResourceFailureException {
- Session session = SessionFactoryUtils.getSession(sessionFactory, true);
- session.setFlushMode(FlushMode.NEVER);
- return session;
- }
- protected void closeSession(Session session, SessionFactory sessionFactory)
- throws CleanupFailureDataAccessException {
- SessionFactoryUtils.closeSessionIfNecessary(session, sessionFactory);
- }
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,FilterChain filterChain) throws ServletException, IOException { SessionFactory sessionFactory = lookupSessionFactory(); logger.debug("Opening Hibernate Session in OpenSessionInViewFilter"); Session session = getSession(sessionFactory); TransactionSynchronizationManager.bindResource( sessionFactory, new SessionHolder(session)); try { filterChain.doFilter(request, response); } finally { TransactionSynchronizationManager.unbindResource(sessionFactory); logger.debug("Closing Hibernate Session in OpenSessionInViewFilter"); closeSession(session, sessionFactory); } } protected Session getSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException { Session session = SessionFactoryUtils.getSession(sessionFactory, true); session.setFlushMode(FlushMode.NEVER); return session; } protected void closeSession(Session session, SessionFactory sessionFactory) throws CleanupFailureDataAccessException { SessionFactoryUtils.closeSessionIfNecessary(session, sessionFactory); }
可以看到OpenSessionInViewFilter在getSession的时候,会把获取回来的session的flush mode 设为FlushMode.NEVER。然后把该sessionFactory绑定到 TransactionSynchronizationManager,使request的整个过程都使用同一个session,在请求过后再接除该 sessionFactory的绑定,最后closeSessionIfNecessary根据该 session是否已和transaction绑定来决定是否关闭session。在这个过程中,若HibernateTemplate 发现自当前session有不是readOnly的transaction,就会获取到FlushMode.AUTO Session,使方法拥有写权限。
- public static void closeSessionIfNecessary(Session session, SessionFactory sessionFactory)
- throws CleanupFailureDataAccessException {
- if (session == null ||
- TransactionSynchronizationManager.hasResource(sessionFactory)) {
- return;
- }
- logger.debug("Closing Hibernate session");
- try {
- session.close();
- }
- catch (JDBCException ex) {
- // SQLException underneath
- throw new CleanupFailureDataAccessException("Could not close Hibernate session", ex.getSQLException());
- }
- catch (HibernateException ex) {
- throw new CleanupFailureDataAccessException("Could not close Hibernate session", ex);
- }
- }
public static void closeSessionIfNecessary(Session session, SessionFactory sessionFactory) throws CleanupFailureDataAccessException { if (session == null || TransactionSynchronizationManager.hasResource(sessionFactory)) { return; } logger.debug("Closing Hibernate session"); try { session.close(); } catch (JDBCException ex) { // SQLException underneath throw new CleanupFailureDataAccessException("Could not close Hibernate session", ex.getSQLException()); } catch (HibernateException ex) { throw new CleanupFailureDataAccessException("Could not close Hibernate session", ex); } }
也即是,如果有不是readOnly的transaction就可以由Flush.NEVER转为Flush.AUTO,拥有 insert,update,delete操作权限,如果没有transaction,并且没有另外人为地设flush model的话,则doFilter的整个过程都是Flush.NEVER。所以受transaction保护的方法有写权限,没受保护的则没有。
采用spring的事务声明,使方法受transaction控制
- <bean id="baseTransaction"
- class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
- abstract="true">
- <property name="transactionManager" ref="transactionManager"/>
- <property name="proxyTargetClass" value="true"/>
- <property name="transactionAttributes">
- <props>
- <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
- <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
- <prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>
- <prop key="save*">PROPAGATION_REQUIRED</prop>
- <prop key="add*">PROPAGATION_REQUIRED</prop>
- <prop key="update*">PROPAGATION_REQUIRED</prop>
- <prop key="remove*">PROPAGATION_REQUIRED</prop>
- </props>
- </property>
- </bean>
- <bean id="userService" parent="baseTransaction">
- <property name="target">
- <bean class="com.phopesoft.security.service.impl.UserServiceImpl"/>
- </property>
- </bean>
<bean id="baseTransaction" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true"> <property name="transactionManager" ref="transactionManager"/> <property name="proxyTargetClass" value="true"/> <property name="transactionAttributes"> <props> <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop> <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop> <prop key="load*">PROPAGATION_REQUIRED,readOnly</prop> <prop key="save*">PROPAGATION_REQUIRED</prop> <prop key="add*">PROPAGATION_REQUIRED</prop> <prop key="update*">PROPAGATION_REQUIRED</prop> <prop key="remove*">PROPAGATION_REQUIRED</prop> </props> </property> </bean> <bean id="userService" parent="baseTransaction"> <property name="target"> <bean class="com.phopesoft.security.service.impl.UserServiceImpl"/> </property> </bean>
对于上例,则以save,add,update,remove开头的方法拥有可写的事务,如果当前有某个方法,如命名为importExcel(),则因没有transaction而没有写权限,这时若方法内有insert,update,delete操作的话,则需要手动设置flush model为Flush.AUTO,如
session.setFlushMode(FlushMode.AUTO);
session.save(user);
session.flush();
尽 管Open Session In View看起来还不错,其实副作用不少。看回上面OpenSessionInViewFilter的doFilterInternal方法代码,这个方法实际上是被父类的doFilter调用的,因此,我们可以大约了解的OpenSessionInViewFilter调用流程: request(请求)->open session并开始transaction->controller->View(Jsp)->结束transaction并 close session.
一切看起来很正确,尤其是在本地开发测试的时候没出现问题,但试想下如果流程中的某一步被阻塞的话,那在这期间connection就一直被占用而不释放。最有可能被阻塞的就是在写Jsp这步,一方面可能是页面内容大,response.write的时间长,另一方面可能是网速慢,服务器与用户间传输时间久。当大量这样的情况出现时,就有连接池连接不足,造成页面假死现象。
Open Session In View是个双刃剑,放在公网上内容多流量大的网站请慎用。
发表评论
-
could not initialize proxy - no session
2010-01-15 17:56 1529在<many-to-one>中这错误很常见,字 ... -
not a SELECTed expression
2009-11-20 11:48 1509异常信息:There is an incorrect ORDE ... -
java.lang.OutOfMemoryError: PermGen space及其解决方法
2009-11-03 17:08 925PermGen space的全称是Permanen ... -
关于eclipse中组件冲突问题
2009-10-24 11:34 1725我的Eclipse 3.3.2 + MyEclipse ... -
Document base D:\jakarta-tomcat-5.5.9\webapps\balancer does not exist or iis not
2009-08-17 19:06 1142在程序启动的时候出现了 Document base D:\j ... -
Java程序中的问题 short s1=1; s1+=1;为什么编译不出错
2009-07-28 14:30 1792short s1=1; 1例-> s1=s1+1; ... -
类型转换精度损失
2009-07-28 14:18 1251import java.util.*; cl ...
相关推荐
### 使用Spring引起的错误:Write operations are not allowed in read-only mode (FlushMode.NEVER) #### 问题背景 在使用Spring框架时,特别是在与Hibernate结合的情况下,可能会遇到“Write operations are not...
<param-name>cors.allowed.origins</param-name> <param-value>*</param-value> </init-param> <init-param> <param-name>cors.allowed.methods</param-name> <param-value>GET,POST,HEAD,OPTIONS</param-...
<param-name>cors.allowed.origins</param-name> <param-value>*</param-value> </init-param> <init-param> <param-name>cors.allowed.methods</param-name> <param-value>GET,POST,HEAD,OPTIONS,PUT,DELETE...
allowed.headers=Content-Type, Authorization, X-Requested-With allow.credentials=true exposed.headers=X-Total-Count, X-Custom-Header ``` 这里,`allowed.origins`指定了允许跨域的源,`allowed.methods...
String allowedOrigins = props.getProperty("cors.allowed.origins"); ``` 总结: Spring框架提供了多种解决跨域问题的方法,包括注解和过滤器。`cors-filter-1.7.jar`是一个非Spring的CORS过滤器,可以单独或与...
<param-name>cors.allowed.origins</param-name> <param-value>*</param-value> </init-param> <!-- 更多配置选项,如:允许的HTTP方法、允许的头部、是否允许证书等 --> <filter-mapping> <filter-name>...
Prerequisites: Java VM 1.8 Open a command shell/window, browse to where you ...Using the --help option will show the allowed command line arguments. 更多查看: https://github.com/WebGoat/WebGoat
**405 Method Not Allowed** - 请求行中指定的方法不被允许使用于请求相应的资源。 **406 Not Acceptable** - 服务器生成的响应没有满足客户端的MIME类型需求。 **407 Proxy Authentication Required** - 和401...
"allowed_methods": cloudfront.AllowedMethods.ALLOW_ALL, "cached_methods": cloudfront.CachedMethods.CACHE_GET_HEAD_OPTIONS, "default_ttl": core.Duration.minutes(5), }, ) ``` 在上面的例子中,我们...
4. **config.h.in** - 配置头文件模板,用于编译时生成`config.h`。 5. **Makefile.am** - Automake配置文件,用于构建过程。 6. **configure** - 自动配置脚本,帮助用户为特定环境设置编译选项。 7. **scripts** -...
2015-01-16: Version 8.039.01: Changed driver code to not use IP checksum hardware offload (caused various issues with networking in VMs) 2015-01-05: Version 8.039.00: Original version
在线封装和离线封装驱动 ... Description ...Adds the blacklisted ESXi 5.1 built-in ...Requires MaintMode Live Install Allowed Live Remove Allowed Stateless Ready Overlay Yes No No Yes No
Requires MaintMode Live Install Allowed Live Remove Allowed Stateless Ready Overlay Yes No No Yes No Additional links Related VMware Forum's post Package updated to include missing device IDs 1502...
xml/ns/javaee":deferred-syntax-allowed-as-literal, "http://java.sun.com/xml/ns/javaee":trim-directive-whitespaces, "http://java.sun.com/xml/ns/javaee":default-content-type, ...
NOTE: Windows executables in SDK are not signed so you may encounter security warnings on W8 and W10. On MacOS you may need to run SDK executables directly from console as they are not signed too.
- `cors.allowed.headers`:允许的请求头部,默认为Accept、Accept-Language、Content-Type、Last-Event-ID。 - `cors.exposed.headers`:服务器可以向浏览器暴露的响应头部。 - `cors.support.credentials`:是否...
Requires MaintMode Live Install Allowed Live Remove Allowed Stateless Ready Overlay Yes No No Yes No Additional links VMware Communities thread about running VMware ESXi inside Hyper-V Build ...
NOTE: sciter.dlls, sciter.exe and notes.exe Windows executables in SDK are digitally signed now. On MacOS you may need to run SDK executables directly from console as they are not signed too.
<param-name>cors.allowed.origins</param-name> <param-value>*</param-value> </init-param> <!-- 更多配置参数,例如允许的HTTP方法、头部、暴露头部等 --> <filter-mapping> <filter-name>CORS</filter-...
is_allowed = authorize(user, 'read', 'document_id') if is_allowed: # 执行受保护的操作 else: # 处理权限不足的情况 ``` 总的来说,VWS_Auth_Tools库为Python开发者提供了一套高效、安全的认证和授权解决...