论坛首页 入门技术论坛

老生常谈的session的问题

浏览 10626 次
该帖已经被评为新手帖
作者 正文
   发表时间:2007-02-09  

目前的结构采用的是Struts+spring+hibernate,目前遇到一个问题,Riskdutyfactor表与riskDuty是多对多的关系,中间表为factorRiskDuty

配置文件如下:

RISKDUTY表:

xml 代码
  1. <hibernate-mapping>  
  2.     <class name="com.sleb.po.Riskduty" table="RISKDUTY" schema="XFLIU">  
  3.         <id name="riskdutyid" type="integer">  
  4.             <column name="RISKDUTYID" />  
  5.             <generator class="sequence" >  
  6.             <param name="sequence">S_RISKDUTY</param>  
  7.             </generator>  
  8.         </id>  
  9. .....   
  10.         <set name="riskdutyrisks" inverse="true">  
  11.             <key>  
  12.                 <column name="RISKDUTYID" />  
  13.             </key>  
  14.             <one-to-many class="com.sleb.po.Riskdutyrisk" />  
  15.         </set>  
  16.         <!-- 设计责任和责任要素的多对多的关联,手动修改过,中间表名称为FACTORRISKDUTY-->  
  17.         <set name="riskdutyfactors" table="FACTORRISKDUTY" cascade="save-update">  
  18.             <key>  
  19.                 <column name="RISKDUTYID" />  
  20.             </key>  
  21.             <many-to-many class="com.sleb.po.Riskdutyfactor" column="RISKDUTYFACTORID" />  
  22.         </set>  
  23.     </class>  
  24. </hibernate-mapping>  


------------------------

riskdutyfactor表映射文件: ----------先对以上进行解释,有一个界面是用来增加RISKDUTYFACTOR表中的数据的,另一个界面用来增加RISKDUTY数据的,在增加RISKDUTY的时候,需要使用RISKDUTYFACTOR表中的数据,由于是多对多的关系,因此增加FACTORRISKDUTY中间表.由以上可以知道riskduty增加的时候,再对中间表进行更新,因此设置RISKDUTY配置文件中的cascade="save-update"> 来维护关系,我想这个是正确的,因为我能正确的增加数据.RiskDutyService程序如下:
  

  1. // 保存一个责任要素   
  2. public boolean saveRiskduty(String dutyName, String dutyType,   
  3.   String[] baseChecked, String[] complexChecked) {     
  4.  riskDuty.setDutyname(dutyName);   
  5.  riskDuty.setDutytype(dutyType);   
  6.  if (baseChecked != null) {   
  7.   for (int i = 0; i < baseChecked.length; i++) {   
  8.    log.info(this.getRiskDutyFactorByPk(new Integer(baseChecked[i])).getFactorname());   
  9.    //首先根据页面上请求的ID,取得RiskDutyFactor对象,后与RiskDuty关联   
  10.    riskDuty.getRiskdutyfactors().add(this.getRiskDutyFactorByPk(new Integer(baseChecked[i])));       
  11.   }   
  12.  }   
  13.  if (complexChecked != null) {   
  14.   for (int i = 0; i < complexChecked.length; i++) {   
  15.    log.info(this.getRiskDutyFactorByPk(new Integer(complexChecked[i])).getFactorname());   
  16. /    首先根据页面上请求的ID,取得RiskDutyFactor对象,后与RiskDuty关联   
  17.    riskDuty.getRiskdutyfactors().add(this.getRiskDutyFactorByPk(new Integer(complexChecked[i])));   
  18.   }   
  19.  }   
  20.  log.info("begin save complexCheck riskDuty");   
  21.  this.getRiskDutyDAO().save(riskDuty);   
  22.   
  23.  bl=true;   
  24.  //this.getRiskDutyFactorDAO().getCurrentSession().clear();   
  25.     
  26.  return bl;   
  27. }   

第一次增加riskduty是没有任何问题的,但是第2次的时候,报如下错误:org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [com.sleb.po.Riskdutyfactor#1]

----------我知道出现的问题是在this.getRiskDutyFactorByPk(new Integer(baseChecked[i])));    但是在网上找了很对解决办法,都没有实现,比较纳闷,所以写在自己的BLOG中,请看看怎么修改.

this.getRiskDutyFactorByPk(new Integer(baseChecked[i])));   对它也进行说明,我们是在riskDutyService中增加了

 //根据责任要素主键,取得一个责任要素对象,该方法避免了service调用service是的事务调用事务的问题
 public Riskdutyfactor getRiskDutyFactorByPk(Integer id) {
   return (Riskdutyfactor)this.getRiskDutyFactorDAO().getByPk(Riskdutyfactor.class,id);
 }

方法直接调用RiskDutyFactorDAO中的方法,这样做的目的是避免了使用riskDutyService调用riskDutyFactorService.因此spring 中的配置文件修改为:
 <!---->
 请教高手!

xml 代码

<bean id="riskDutyService" parent="proxyTemplate"></bean>

  1. <!--riskDuty service -->  
  2.     <bean id="riskDutyService" parent="proxyTemplate">  
  3.         <property name="target">  
  4.             <bean class="com.sleb.service.riskDuty.spring.RiskDutyServiceImpl">  
  5.                 <property name="riskDutyDAO">  
  6.                     <ref local="riskDutyDAO" />  
  7.                 </property>  
  8.                 <property name="riskDutyFactorDAO">  
  9.                     <ref local="riskDutyFactorDAO" />  
  10.                 </property>  
  11.             </bean>  
  12.         </property>  
  13.     </bean>  
  14.     <bean id="riskDutyDAO" class="com.sleb.dao.riskDuty.RiskDutyDAOImpl">  
  15.         <property name="sessionFactory">  
  16.             <ref bean="sessionFactory" />  
  17.         </property>  
  18.     </bean>  

 

xml 代码
  1. <hibernate-mapping>  
  2.     <class name="com.sleb.po.Riskdutyfactor" table="RISKDUTYFACTOR" schema="XFLIU">  
  3.         <id name="riskdutyfactorid" type="integer">  
  4.             <column name="RISKDUTYFACTORID" />  
  5.             <generator class="sequence" >  
  6.             <param name="sequence">S_RISKDUTYFACTOR</param>  
  7.             </generator>  
  8.         </id>  
  9.         <property name="factorname" type="string">  
  10.             <column name="FACTORNAME" length="20" />  
  11.         </property>  
  12.         <property name="factorunit" type="string">  
  13.             <column name="FACTORUNIT" length="120" />  
  14.         </property>  
  15.         <property name="value" type="string">  
  16.             <column name="VALUE" length="120" />  
  17.         </property>  
  18.         <property name="sign" type="string">  
  19.             <column name="SIGN" length="1" />  
  20.         </property>  
  21.         <property name="language" type="string">  
  22.             <column name="LANGUAGE" length="1" />  
  23.         </property>  
  24.         <!-- 设计责任要素和责任的多对多的关联,手动修改过,中间表名称为FACTORRISKDUTY-->  
  25.         <set name="riskduties" table="FACTORRISKDUTY"  inverse="true" cascade="none">  
  26.             <key>  
  27.                 <column name="RISKDUTYFACTORID" />  
  28.             </key>  
  29.             <many-to-many class="com.sleb.po.Riskduty" column="RISKDUTYID" />  
  30.         </set>  
  31.     </class>  
  32. </hibernate-mapping>  


<hibernate-mapping></hibernate-mapping>

java 代码
   发表时间:2007-02-09  
da大家能看到吗?我怎么看不到啊!奇怪!
0 请登录后投票
   发表时间:2007-02-09  
liutjedu 写道
da大家能看到吗?我怎么看不到啊!奇怪!


发表代码请用code包含。BBCODE模式下,用Code包含, RichEdit模式下用代码输入窗口输入代码。
0 请登录后投票
   发表时间:2007-02-09  
谢谢springArt.
0 请登录后投票
   发表时间:2007-02-09  
关于 NonUniqueObjectException ,请看:

http://www.hibernate.org/116.html#A8

这个异常估计是每一个Hibernate使用者都曾经遇到过的……

这样的帖子建议放到新手区。
0 请登录后投票
   发表时间:2007-02-09  
if (baseChecked != null) {    
  for (int i = 0; i < baseChecked.length; i++) {    
   log.info(this.getRiskDutyFactorByPk(new Integer(baseChecked[i])).getFactorname());    
   //首先根据页面上请求的ID,取得RiskDutyFactor对象,后与RiskDuty关联    
   riskDuty.getRiskdutyfactors().add(this.getRiskDutyFactorByPk(new Integer(baseChecked[i])));        
  }    
 }    

我在网络上搜到过,但是能不能帮我详细的看下我的代码,应该将你说的meger()方法放在那里?谢谢!
0 请登录后投票
   发表时间:2007-02-09  
	public boolean saveRiskduty(String dutyName, String dutyType,
			String[] baseChecked, String[] complexChecked) {		
		riskDuty.setDutyname(dutyName);
		riskDuty.setDutytype(dutyType);
		
		if (baseChecked != null) {
			for (int i = 0; i < baseChecked.length; i++) {
				log.info(this.getRiskDutyFactorByPk(new Integer(baseChecked[i])).getFactorname());
				//首先根据页面上请求的ID,取得RiskDutyFactor对象,后与RiskDuty关联
				this.getRiskDutyFactorDAO().getCurrentSession().merge(this.getRiskDutyFactorByPk(new Integer(baseChecked[i])));
				riskDuty.getRiskdutyfactors().add(this.getRiskDutyFactorByPk(new Integer(baseChecked[i])));				
			}
		}
		if (complexChecked != null) {
			for (int i = 0; i < complexChecked.length; i++) {
				log.info(this.getRiskDutyFactorByPk(new Integer(complexChecked[i])).getFactorname());
				//首先根据页面上请求的ID,取得RiskDutyFactor对象,后与RiskDuty关联
				this.getRiskDutyFactorDAO().getCurrentSession().merge(this.getRiskDutyFactorByPk(new Integer(complexChecked[i])));
				riskDuty.getRiskdutyfactors().add(this.getRiskDutyFactorByPk(new Integer(complexChecked[i])));
			}
		}
		log.info("begin save complexCheck riskDuty");
		this.getRiskDutyDAO().save(riskDuty);

		bl=true;
		//this.getRiskDutyFactorDAO().getCurrentSession().clear();
		
		return bl;
	}


程序增加了两行,但是还是不对,不知道merge怎么用.
0 请登录后投票
   发表时间:2007-02-09  
这个代码的可阅读性需要加强啊!

我觉得你这里出现问题的原因并不在于是否采用merge()方法来持久化PO……

况且你对merge()的用法也是不对的,它的正确用法请参考API文档。

Session.merge() API doc:
http://www.hibernate.org/hib_docs/v3/api/org/hibernate/Session.html#merge(java.lang.Object)
0 请登录后投票
   发表时间:2007-02-09  
很可能的一点是,你的这两个数组里面存在重复相同的值:String[] baseChecked, String[] complexChecked。这进而导致你的DAO层试图将同样Class类型并且含有同样标识符(identifier)的Riskdutyfactor对象关联到它的Session中去,就直接引发了NonUniqueObjectException。

另外,根据你的这段代码所体现的逻辑关系,建议将这个Set集合也设置inverse="true"。
        <set name="riskdutyfactors" table="FACTORRISKDUTY" cascade="save-update">   
            <key>   
                <column name="RISKDUTYID" />   
            </key>   
            <many-to-many class="com.sleb.po.Riskdutyfactor" column="RISKDUTYFACTORID" />   
        </set>
0 请登录后投票
   发表时间:2007-02-09  
to Allen    :
我是多对多的,但是riskdutyfactor表已经有数据了,后再对riskduty进行操作,如果都修改为inverse="true",那没有对象来维护中间表了.
不知道我说的对不对.

你说的代码可读性不好,是因为我注释少,还是我说的不清楚呢?希望能说的直白点,呵呵,学习ING.

对于出错的问题,我知道是这两个String[] baseChecked, String[] complexChecked造成的,但是怎么修改呢?
0 请登录后投票
论坛首页 入门技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics