题库管理模块

本文探讨了在Hibernate中处理原有设计与新需求冲突时遇到的问题。通过调整映射文件并利用Spring的HibernateTemplate,成功解决了同一session下关联对象更新不生效的难题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        题库实际是一个资料库,里面分门别类的存放着一些主题和内容。主题通常是一个问句,所以被称为题库。这个系统主要是对数据的创建,删除,修改,和查询。我主要做的是查询,修改和删除。
       在业务对象的设计上有一个有趣的问题。在我之前,业务对象已经设计好了,而且hibernate的映射文件也已经完成了。最初的设计者把这些表的所有字段,包括外键全部用property映射了。这样做就是放弃了hibernate的对象关联的功能。当我开始工作后,新的需求要求对一些关联数据进行访问,为了让其它已有的程序能够正常工作,我在hibernate映射文件里添加了many-to-one的映射,并且在类中添加了引用。已有的部分没有任何改动。代码和映射文件如下:

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Subject.java<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
public class Subject {
    
private String id;

    
private String baseCode;  //外键

    
private String itemCode;   //外键
    
    
private SubjectBaseCode base;   //引用
    
    
private SubjectItemCode item;     //引用
    
    
private String subDate;

    
private String aboutUser;

    
private String aboutProduct;
    
    
private Blob subjectTitle;

    
private Blob subjectContent;
    
    
private String createUser;
    
    
private Timestamp createTime;

       
//其它略
}



>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Subject.hbm.xml<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"
>

<hibernate-mapping
>
    
<class
        
name="com.xxxx.model.question.Subject"
        table
="mis_tb1031_subject"
    
>

        
<id
            
name="id"
            column
="ID"
            type
="java.lang.String"
            length
="32"
            unsaved-value
="null"
        
>
            
<generator class="uuid.hex">
              
<!--  
                  To add non XDoclet generator parameters, create a file named 
                  hibernate-generator-params-Subject.xml 
                  containing the additional parameters and place it in your merge dir. 
              
--> 
            
</generator>
        
</id>

        
<property
            
name="createTime"
            type
="java.sql.Timestamp"
            update
="true"
            insert
="true"
            column
="CRT_TIME"
        
/>

        
<property
            
name="createUser"
            type
="java.lang.String"
            update
="true"
            insert
="true"
            column
="CRT_USER"
            length
="5"
        
/>

        
<property
            
name="aboutProduct"
            type
="java.lang.String"
            update
="true"
            insert
="true"
            column
="ABOUT_PRODUCT"
            length
="500"
        
/>

        
<property
            
name="aboutUser"
            type
="java.lang.String"
            update
="true"
            insert
="true"
            column
="ABOUT_USER"
            length
="500"
        
/>

        
<property
            
name="baseCode"
            type
="java.lang.String"
            update
="true"
            insert
="true"
            column
="BASE_CODE"
            length
="32"
        
/>

        
<property
            
name="itemCode"
            type
="java.lang.String"
            update
="true"
            insert
="true"
            column
="ITEM_CODE"
            length
="32"
        
/>

        
<property
            
name="subDate"
            type
="java.lang.String"
            update
="true"
            insert
="true"
            column
="SUB_DATE"
            length
="10"
        
/>

        
<property
            
name="subjectContent"
            type
="java.sql.Blob"
            update
="true"
            insert
="true"
            column
="SUBJECT_CONTENT"
        
/>

        
<property
            
name="subjectTitle"
            type
="java.sql.Blob"
            update
="true"
            insert
="true"
            column
="SUBJECT_TITLE"
        
/>

        
<many-to-one
            
name="item"
            class
="com.xxxx.model.question.SubjectItemCode"
            cascade
="none"
            outer-join
="true"
            update
="false"    
            insert
="false"
            column
="ITEM_CODE"
        
/>

        
<many-to-one
            
name="base"
            class
="com.xxxx.model.question.SubjectBaseCode"
            cascade
="none"
            outer-join
="true"
            update
="false"
            insert
="false"
            column
="BASE_CODE"
        
/>

        
<!--
            To add non XDoclet property mappings, create a file named
                hibernate-properties-Subject.xml
            containing the additional properties and place it in your merge dir.
        
-->

    
</class>

</hibernate-mapping>

        由于对外键的重复映射,给以后的开发带来了一点小小的麻烦。为了保持原来程序的完整,对象之间的关联的建立,还是用原来的baseCode,itemCode这两个String类型的属性。而关联的对象的属性base,item仅仅在查询时有用。所以我把base,和item的映射属性update和insert都设为false,否则hibernate在初始化时会报错。如下:
        <many-to-one
            
name="item"
            class
="com.xxxx.model.question.SubjectItemCode"
            cascade
="none"
            outer-join
="true"
            update
="false"    
            insert
="false"
            column
="ITEM_CODE"
        
/>

        
<many-to-one
            
name="base"
            class
="com.xxxx.model.question.SubjectBaseCode"
            cascade
="none"
            outer-join
="true"
            update
="false"
            insert
="false"
            column
="BASE_CODE"
        
/>


       在开发的过程中,我使用了Spring的HibernateTemplate。我们的Service对象的所有方法都使用了Spring的申明式事务。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
    "http://www.springframework.org/dtd/spring-beans.dtd"
>

<beans>
    
    
<bean id="txProxyTemplate" abstract="true"
        class
="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        
<property name="transactionManager"><ref bean="transactionManager"/></property>
        
<property name="transactionAttributes">
            
<props>
                
<prop key="save*">PROPAGATION_REQUIRED</prop>
                
<prop key="remove*">PROPAGATION_REQUIRED</prop>
                
<prop key="update*">PROPAGATION_REQUIRED</prop>
                
<prop key="delete*">PROPAGATION_REQUIRED</prop>
                
<prop key="unlock*">PROPAGATION_REQUIRED</prop>
                
<prop key="persist*">PROPAGATION_NEVER</prop>
                
<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
            
</props>
        
</property>
    
</bean>

 
    
<bean id="questionService" parent="txProxyTemplate" >
        
<property name="target">
            
<bean class="com.xxxx.service.impl.QuestionServiceImpl">
                
<property name="questionDao">
                    
<ref bean="questionDao"/>
                
</property>
            
</bean>
        
</property>            
    
</bean>    
</beans>

       一切基本上没有什么问题。当我在做一个修改功能时问题出现了。最早完成的查询功能,查询结果用一个列表返回。后来为了使其可以删除和更新记录,所以在显示结果的表格里又新增了一列用来放删除和修改按钮。当记录被更新后,重新返回到这个列表中。所以我的action要完成两个功能,更新记录,再查询。也就是要调用2次service中的方法。一次更新,一次查询。但是问题出现了,当对象的外键属性的内容更新后,重新返回列表时,里面的内容并没有变化,但是重新查询后,结果却是正确的,而其它的字段都正常。
       于是我对程序进行跟踪,发现返回的结果中的
Subject 对象,并不是Subject类,而是hibernate的proxy类。而且里面的数据都是旧的数据。这使我白思不得其解,难道是事务没有提交。我一开始怀疑是事务的问题,可能更新的方法和查询的方法处于同一个事务中了。所以查询的时候事务还没提交,但是,我换了许多属性都不行。最后,我决定去看spring的HibernateTemplate的源码。这是我才发现HibernateTemplate有一个方法
setAlwaysUseNewSession,它可以决定是不是每次execute都使用一个新的session。
       这是,我才明白,造成这个问题的原因是2个service方法都用了同一个session。再加上由于hibernate映射的问题,导致更新的时候外键更新了,但
关联对象的引用没有更新,导致第2次查询时的关联对象是旧的。
       于是我在QuestionDaoHibernateImpl类的构造函数里
setAlwaysUseNewSession(true),但是却报错,应该是因为当QuestionDaoHibernateImpl被spring初始化时,它的HibernateTemplate还没初始化。
       最后无奈,我只好用spring的initinit-method。


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
    "http://www.springframework.org/dtd/spring-beans.dtd"
>
<beans>
    
<!-- Generic DAO - can be used when doing standard CRUD -->
    
<bean id="baseDao" class="com.xxxx.dao.hibernate.BaseDaoHibernateImpl">
        
<property name="sessionFactory">
            
<ref local="sessionFactory" />
        
</property>
    
</bean>
    
<bean id="questionDao" 
         class
="com.xxxx.dao.hibernate.QuestionDaoHibernateImpl" 
       parent
="baseDao" 
init-method
="setUseNewSessionTrue" />
</beans>

public class QuestionDaoHibernateImpl extends BaseDaoHibernateImpl implements QuestionDao{
    
    
/**
     * HibernateTemplate每次使用新的session.
     
*/

    
public void setUseNewSessionTrue(){
        getHibernateTemplate().setAlwaysUseNewSession(
true);
    }

    
      
//
}

      
        这样才把这个问题给解决了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值