博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
spring + hibernate 设置更新指定字段
阅读量:4231 次
发布时间:2019-05-26

本文共 6466 字,大约阅读时间需要 21 分钟。

spring + hibernate 设置更新指定字段
hibernate的update方式默认的是更新所有字段的,这导致一个很大的问题,当想更新部分字段时必须要把整个entity先load一遍,然后set相应的更新字段再保存
这一步load数据势必将数据库的操作增加一倍,而且基本上是多余的,最近看了下hibernate源码,发现hibernate有设置指定更新的方式,具体方式如下
org.hibernate.persister.entity.AbstractEntityPersister中定义了基类的更新方法 public void update( 			final Serializable id, 	        final Object[] fields, 	        final int[] dirtyFields, 	        final boolean hasDirtyCollection, 	        final Object[] oldFields, 	        final Object oldVersion, 	        final Object object, 	        final Object rowId, 	        final SessionImplementor session) throws HibernateException {
其中的一段代码:
if ( ( entityMetamodel.isDynamicUpdate() && dirtyFields != null ) ) {
// We need to generate the UPDATE SQL when dynamic-update="true" propsToUpdate = getPropertiesToUpdate( dirtyFields, hasDirtyCollection ); // don't need to check laziness (dirty checking algorithm handles that) updateStrings = new String[span]; for ( int j = 0; j < span; j++ ) {
updateStrings[j] = tableUpdateNeeded[j] ? generateUpdateString( propsToUpdate, j, oldFields, j == 0 && rowId != null ) : null; } } else if ( ! isModifiableEntity( entry ) ) {
// We need to generate UPDATE SQL when a non-modifiable entity (e.g., read-only or immutable) // needs: // - to have references to transient entities set to null before being deleted // - to have version incremented do to a "dirty" association // If dirtyFields == null, then that means that there are no dirty properties to // to be updated; an empty array for the dirty fields needs to be passed to // getPropertiesToUpdate() instead of null. propsToUpdate = getPropertiesToUpdate( ( dirtyFields == null ? ArrayHelper.EMPTY_INT_ARRAY : dirtyFields ), hasDirtyCollection ); // don't need to check laziness (dirty checking algorithm handles that) updateStrings = new String[span]; for ( int j = 0; j < span; j++ ) {
updateStrings[j] = tableUpdateNeeded[j] ? generateUpdateString( propsToUpdate, j, oldFields, j == 0 && rowId != null ) : null; } } else {
// For the case of dynamic-update="false", or no snapshot, we use the static SQL updateStrings = getUpdateStrings( rowId != null, hasUninitializedLazyProperties( object ) ); propsToUpdate = getPropertyUpdateability( object ); }
可以看到hibernate提供了3种的获得更新字段方式,默认情况下会进入最后的else中获得所有的字段,中间else if 的方式可以看到注解里的说明,应该是为read-only的对象准备,此处没有详细深入,而我们需要的是第一种方式
当对象的mapping文件配置了dynamic-update="true" 且dirtyFields存在时hibernate便会根据dirtyFields获得需要更新的字段
propsToUpdate = getPropertiesToUpdate( dirtyFields, hasDirtyCollection );
这里的dirtyFields便是entity对应的字段下标
一直向前追溯dirtyFields的来源可以在org.hibernate.event.internal.DefaultFlushEntityEventListener中找到protected void dirtyCheck(final FlushEntityEvent event) throws HibernateException函数
关键代码:
int[] dirtyProperties = session.getInterceptor().findDirty( 				entity, 				id, 				values, 				loadedState, 				persister.getPropertyNames(), 				persister.getPropertyTypes() 		);
hibernate在session中做了一个拦截器,可以在操作前做一些处理。
session由sessionFactory创建,而interceptor则由从Configuration注入
这样就很清楚了,我们要做的操作只要在Configuration中注入我们自定义的interceptor就行了
先写一个interceptor继承与emtpyInterceptor
package net.esj.basic.dao.hibernate.sessioninterceptor; import java.io.Serializable; import java.util.HashSet; import java.util.Set; import net.esj.basic.pojo.AbstractPojo; import net.esj.basic.pojo.UpdateType; import net.esj.basic.pojo.Updater; import net.esj.basic.utils.JavaProtoTypeHelper; import org.hibernate.EmptyInterceptor; import org.hibernate.type.Type; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @Component("dirtyFindInterceptor") @Scope("prototype") public class DirtyFindInterceptor extends EmptyInterceptor {
@Override public int[] findDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) {
if(entity instanceof AbstractPojo){
Updater updater = ((AbstractPojo)entity).getUpdater(); UpdateType type =((AbstractPojo)entity).getUpdateType(); if(type==UpdateType.AUTO){
type = checkUpdateType(entity, id, currentState, previousState, propertyNames, types); } switch(type){
case BY_DIFF: return findDirtyByDiff(entity, id, currentState, previousState, propertyNames, types); case BY_UPDATER: return findDirtyByUpdater(entity, id, currentState, previousState, propertyNames, types, ((AbstractPojo)entity)); case NONE: return super.findDirty(entity, id, currentState, previousState, propertyNames, types); } } return super.findDirty(entity, id, currentState, previousState, propertyNames, types); } protected UpdateType checkUpdateType(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types){
if(! (entity instanceof AbstractPojo)){
return UpdateType.NONE; } Updater updater = ((AbstractPojo)entity).getUpdater(); if(updater.hasProperty()){
return UpdateType.BY_UPDATER; } return UpdateType.NONE; } private int[] findDirtyByUpdater(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types,AbstractPojo pojo){
Updater updater = pojo.getUpdater(); Set
tmp = new HashSet
(); //int[] reval = new int[propertyNames.length]; for(int i=0;i
tmp = new HashSet
(); for(int i=0;i
这里我做了3种更新方式,一种为基本的全字段更新,一种为根据程序员自定义的字段更新,一种为核查原始数据和新数据是否相等,更新不相等的字段。
基于spring的配置,我们的hibernate的Configuration是由LocalSessionFactoryBean创建的。
具体配置为:
classpath*:/net/esj/test/pojo/
after_transaction
${hibernate.dialect}
${hibernate.show_sql}
${hibernate.format_sql}
具体的过程可以在spring的源码中找到,此处我们注入上面的dirtyFindInterceptor类。
测试:
true
public void testUpdate(){
Foo foo = new Foo(); foo.setId("402881973aa11bb7013aa11bb8340000"); foo.setName("asdas"); foo.notifyUpdater("name");//只更新name字段 baseDao.update(foo); }
hibernate打印的sql:
Hibernate: update test_foo set name=? where id=?
可以看到现在只更新了name字段

转载地址:http://jpsqi.baihongyu.com/

你可能感兴趣的文章
SharePoint 2007 User's Guide: Learning Microsoft's Collaboration and Productivity Platform
查看>>
Word 2007: Beyond the Manual
查看>>
An Introduction to Testing Web Applications with twill and Selenium
查看>>
Accelerated VB 2005
查看>>
Pro Access 2007
查看>>
Excel 2007: Beyond the Manual
查看>>
Windows Vista: Beyond the Manual
查看>>
DotNetNuke For Dummies
查看>>
PCI Compliance: Understand and Implement Effective PCI Data Security Standard Compliance
查看>>
Flash CS3 For Dummies
查看>>
Professional ASP.NET 2.0 AJAX
查看>>
Security+ Study Guide
查看>>
Programming Interviews Exposed: Secrets to Landing Your Next Job
查看>>
Linksys WRT54G Ultimate Hacking
查看>>
Professional Rootkits
查看>>
Financial Applications using Excel Add-in Development in C/C++
查看>>
Learning Joomla! Extension Development: Creating Modules, Components, and Plugins with PHP
查看>>
How to Cheat at IIS 7 Server Administration
查看>>
Simply JavaScript
查看>>
Expert SQL Server 2005 Integration Services
查看>>