天天看點

Hibernate 踩坑日記

## 環境

Spring4 + hibernate5 + jpa

坑一

描述

打算使用es, 是以給hibernate 配置了攔截器, 如下

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="persistenceUnit"/>
        <property name="persistenceUnitManager" ref="persistenceUnitManager"/>
        <property name="dataSource" ref="dataSource" />
        <property name="jpaVendorAdapter">
            <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="database" value="MYSQL"/>
            </bean>
        </property>
        <property name="jpaDialect">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
        </property>
        <property name="jpaPropertyMap">
            <map>
                <entry key="hibernate.ejb.interceptor.session_scoped">
                    <value>per.posse.tool.interceptor.HibernateSessionInterceptor</value>
                </entry>
            </map>
        </property>
    </bean>
           

HibernateSessionInterceptor 實作了 org.hibernate.Interceptor 接口

問題

RETRIEVE, CREATE, CREATE, 全無問題, 但是UPDATE 操作毫無反應, 資料不更新, 也不報錯, 也不列印update的sql.

原因及解決

HibernateSessionInterceptor 具體實作還沒寫, 編譯器預設生成Interceptor接口的實作方法, 有個方法叫findDirty(), 編譯器預設實作空方法是

@Override
    public int[] findDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState,
            String[] propertyNames, Type[] types) {
        return new int[];
    }
           

檢視描述

Called from flush(). The return value determines whether the entity is updated
  • an array of property indices - the entity is dirty
  • an empty array - the entity is not dirtinte

也就是hibernate 在執行 flush() 操作的時候, 會調用這個方法, 傳回值決定實體是否被update傳回值有值, 實體被改寫, 需要更新持久化上下文, 傳回值是空數組, hibernate不認為實體被改動, 不執行更新操作,傳回null, 則由hibernate 預設的dirty-checking 機制判斷是否需要更新, 它有自己的一套DirtyCheckEventListener, DirtyCheckEvent機制.

是以編譯器給我預設傳回new int[0], hibernate 認為實體不需要更新, 是以就沒有執行update, 是以把傳回先改成null ,再做update操作, 列印sql, 資料庫更新.

OK.