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




























>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>Subject.hbm.xml<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<









































































































































由于对外键的重复映射,给以后的开发带来了一点小小的麻烦。为了保持原来程序的完整,对象之间的关联的建立,还是用原来的 baseCode, itemCode这两个String类型的属性。而关联的对象的属性 base,item仅仅在查询时有用。所以我把 base,和 item的映射属性update和insert都设为false,否则hibernate在初始化时会报错。如下:



















在开发的过程中,我使用了Spring的HibernateTemplate。我们的Service对象的所有方法都使用了Spring的申明式事务。


































一切基本上没有什么问题。当我在做一个修改功能时问题出现了。最早完成的查询功能,查询结果用一个列表返回。后来为了使其可以删除和更新记录,所以在显示结果的表格里又新增了一列用来放删除和修改按钮。当记录被更新后,重新返回到这个列表中。所以我的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。





























这样才把这个问题给解决了。