Hibernate是一个ORM持久化框架,也是主流的ORM框架之一。使用它,程序员能够利用OOP思想操作数据库数据。但是新手刚开始学习Hibernate的时候,由于对于Hibernate的工作原理和机制理解不透彻,在使用过程中,将会遇到许多问题和掉入许多深坑(好几天出不来,比如楼主我,唉~~~~),大大的降低了工作效率。最近使用Hibernte做个人项目时,又掉进了深坑,为了避免更多小白入坑难以自拔,就有了楼楼这篇漏作。
在使用Hibernate的时候,使用框架的接口方法,能够简化开发代码,楼楼在做个人项目时为了省点时间撸,就想尝试使用Hibernate的接口方法,像什么save()、delete()、update()、saveorUpdate()的,不过确实很方便。在使用过程中就遇到问题,就行update()更新无效,数据更新不完全等等。
一、 使用Update更新数据无效。
在调用update方法更新数据时,更新操作无效,也不抛出任何异常。楼楼复习了hibernate知识和查阅了相关资料,并经过了自身测试,找到了问题所在。
在使用Hibernate与spring集成时,将Hibernate事务交给spring管理。配置文件如:
<!-- 定义事务 -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 配置详细的事务定义 -->
<tx:attributes>
<!-- 所有以查询数据库的方法是read-only的 -->
<tx:method name="get*" propagation="REQUIRED" read-only="true" />
<tx:method name="find*" propagation="REQUIRED" read-only="true" />
<tx:method name="list*" propagation="REQUIRED" read-only="true" />
<!-- 其他方法使用默认的事务设置 -->
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="del*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut expression="execution(* com.hal.bms..*.services..*.*Services.*(..))"
id="allpoint" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="allpoint" />
</aop:config>
在配置文件中,配置了事务管理的,其他方法调用不存在任何问题,但是update方法却出了问题。也就是说并不是spring事务管理的事。
情况一:
测试代码:
public void updateSelf(User user){
System.out.println("进入本方法!");
getSession().update(user);
getSession().flush();
}
注意图片中的第四条数据,待会就是测试这条了。
然后将用户的地址改为“中国北京”,看看测试结果。
测试成功。说明更新无效是由于只更新了缓存中的数据,如果不调用flush,则数据库并不会更新。
能成功的前提是因为在web.xml配置了OSIV
<!-- Hibeinate OSIV 配置 -->
<filter>
<filter-name>OpenSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
<init-param>
<param-name>FlushMode</param-name>
<param-value>AUTO</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>OpenSessionInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
情况二:
就是情况一下面要说的FlushMode属性,该属性有五中状态(这个网上一查就知道了),分别是:
1、NEVEL:被MANUAL取代了
2 MANUAL:
如果FlushMode是MANUAL或NEVEL,在操作过程中hibernate会将事务设置为readonly,所以在增加、删除或修改操作过程中会出现如下错误
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;
解决办法:配置事务,spring会读取事务中的各种配置来覆盖hibernate的session中的FlushMode;
3 AUTO
设置成auto之后,当程序进行查询、提交事务或者调用session.flush()的时候,都会使缓存和数据库进行同步,也就是刷新数据库
4 COMMIT
提交事务或者session.flush()时,刷新数据库;查询不刷新
5 ALWAYS:
每次进行查询、提交事务、session.flush()的时候都会刷数据库
ALWAYS和AUTO的区别:当hibernate缓存中的对象被改动之后,会被标记为脏数据(即与数据库不同步了)。当 session设置为FlushMode.AUTO时,hibernate在进行查询的时候会判断缓存中的数据是否为脏数据,是则刷数据库,不是则不刷,而always是直接刷新,不进行任何判断。很显然auto比always要高效得多。
所以如果没有配置OSIV,就需要自己手动设置FlushMode属性:session.setFlushMode(FlushMode.xxx)。
情况三:就是事务并没有管理update的类或方法,这时就需要自己手动添加事务管理。在方法上添加事务注解属性@Transactional。然后参考情况一二。
以上属个人对于Hibernate的理解,如有偏差,还望指正。