HIBERNATE学习笔记(转)
Hibernate 学习笔记
一 hibernate配置
1.下载所需包
下载hibernate2.13, hibernate-extension2.13,Middlegen(已装了jdk和ant)
2.创建数据库(例子:student;course,stu_cou)
Student(id,name)
Course(id,name)
Stu_cou(stu_id,cou_id)(分别是student表和course表的外健)
3.使用MiddleGen(见附录)
二 hibernate映射关系(many-to-many)
1. 分析inverse参数(student.hbm.xml course.hbm.xml)
inverse该参数用来负责映射之间的关系,设置为false的一方可以对他们的关系进行维护
设置inverse = false的实体,表示在映射中是它是主动关系,由它来维户关系中的数据
设置inverse = true 的实体,表示在映射中是它是被动关系,它不维护关系中的数据
1) inverse=false的情况
a) 添加记录的情况
student.hbm.xml是主动方,由它来决定stu_cou表中的记录,故inverse=false
当向stu_cou中写入记录时候,
/*
* 测试目的:在stu_cou中添加一组对应关系(student,course)
* 测试结果:当执行完该段代码后
* 如stu_cou中没有(student,course)时,自动加入(student,course)
* 如stu_cou中存在(student,course)时,什么都不作,不会存在主健冲突
Student student=(Student)session.load(Student.class,student2.getId())
Course course=(Course)session.load(Course.class,course2.getId());
student.getCourses().add(course);
session.save(student);
执行完后,hibenrate成功显示
Hibernate: select course0_.id as id0_, course0_.name as name0_ from course course0_ where course0_.id=?
Hibernate: select student0_.id as id0_, student0_.name as name0_ from student student0_ where student0_.id=?
Hibernate: select courses0_.cid as cid__, courses0_.sid as sid__ from stu_cou courses0_ where courses0_.sid=?
Hibernate: insert into stu_cou (sid, cid) values (?, ?)
b) 删除记录的情况
Student student=(Student)session.load(Student.class,student2.getId())
Course course=(Course)session.load(Course.class,course2.getId());
student.getCourses().让remove(course);
session.save(student);
代码执行完后,可以成功执行,hibernate显示:
Hibernate: select course0_.id as id0_, course0_.name as name0_ from course course0_ where course0_.id=?
Hibernate: select student0_.id as id0_, student0_.name as name0_ from student student0_ where student0_.id=?
Hibernate: select courses0_.cid as cid__, courses0_.sid as sid__ from stu_cou courses0_ where courses0_.sid=?
Hibernate: delete from stu_cou where sid=?
2) inverse=true的情况
student.hbm.xml是被动方,设置它的inverse=true
a) 添加记录情况
* 测试目的:在stu_cou中添加一组对应关系(student,course)
* 测试结果:当执行完该段代码后
* 如stu_cou中没有(student,course)时,自动加入(student,course)
* 如stu_cou中存在(student,course)时,什么都不作,不会存在主健冲突
Student tudent=(Student)session.load(Student.class,student2.getId());
Course course=(Course)session.load(Course.class,course2.getId());
student.getCourses().add(course);
session.save(student);
代码执行完后,hibernate显示,没有插入记录
Hibernate: select course0_.id as id0_, course0_.name as name0_ from course course0_ where course0_.id=?
Hibernate: select student0_.id as id0_, student0_.name as name0_ from student student0_ where student0_.id=?
Hibernate: select courses0_.cid as cid__, courses0_.sid as sid__ from stu_cou courses0_ where courses0_.sid=?
b) 删除记录情况
当向stu_cou中删除记录时候,
Student student=(Student)session.load(Student.class,student2.getId())
Course course= (Course)session.load(Course.class,course2.getId());
student.getCourses().remove(course);
session.save(student);
执行完,hibernate显示如下,证明没有删除记录
Hibernate: select course0_.id as id0_, course0_.name as name0_ from course course0_ where course0_.id=?
Hibernate: select student0_.id as id0_, student0_.name as name0_ from student student0_ where student0_.id=?
Hibernate: select courses0_.cid as cid__, courses0_.sid as sid__ from stu_cou courses0_ where courses0_.sid=?
Hibernate: select course0_.id as id0_, course0_.name as name0_ from course course0_ where course0_.id=?
Hibernate: select course0_.id as id0_, course0_.name as name0_ from course course0_ where course0_.id=?
2. 分析cascade参数(student.hbm.xml course.hbm.xml)
只有设置了inverse=false才可以操纵stu_cou的数据
当inverse=true的时候,下列情况1中b)提示错误
原因: stu_cou中存在外健约束,你无法直接删除student表中的数据
1) cascade=save-update的情况
a)添加记录情况
Set set=new HashSet();
set.add(course1);
set.add(course2);
set.add(course3);
student3.setCourses(set);
session.save(student3);
执行后hibernate提示:
Hibernate: insert into student (name) values (?)
Hibernate: insert into course (name) values (?)
Hibernate: insert into course (name) values (?)
Hibernate: insert into course (name) values (?)
Hibernate: insert into stu_cou (sid, cid) values (?, ?)
可见,插入了student,course,和stu_cou三个表
b)删除记录情况
Student student=(Student)session.load(Student.class,new Integer(22));
session.delete(student);
成功执行后,hibernate提示:
Hibernate: select student0_.id as id0_, student0_.name as name0_ from student student0_ where student0_.id=?
Hibernate: delete from stu_cou where sid=?
Hibernate: delete from student where
2) cascade=all的情况
a) 添加记录情况
Set set=new HashSet();
set.add(course1);
set.add(course2);
set.add(course3);
student3.setCourses(set);
session.save(student3);
执行后hibernate提示:成功添加级联关系
Hibernate: insert into student (name) values (?)
Hibernate: insert into course (name) values (?)
Hibernate: insert into course (name) values (?)
Hibernate: insert into course (name) values (?)
Hibernate: insert into stu_cou (sid, cid) values (?, ?)
b) 删除记录情况
Student student=(Student)session.load(Student.class,new Integer(22));
session.delete(student);
测试结果(所有和student(22)相关的记录均被删除)
删除student表中的student(22)记录
删除stu_cou表中的student(22)的记录
删除course表中的student(22)对应的course的记录
2) cascade=none情况
a) 添加记录情况
Set set=new HashSet();
set.add(course1);
set.add(course2);
set.add(course3);
student3.setCourses(set);
session.save(student3);
失败,因为没有级联关系,所以course记录添加不进去,造成外健失败
b) 删除记录情况
Student student=(Student)session.load(Student.class,new Integer(22));
session.delete(student);
正常,删除了student表中的记录student(22),同时删除了stu_cou中对应的student(22)的记录
附录
1.MiddleGen的使用
1环境变量设置
%Hibernate_Home%/lib/*.jar到%MiddleGen%/lib下
%Hibernate_Home%/hibernate2.jar到%MiddleGen%/lib下
%Hibernate-Extension_Home%/tools/lib/*.jar到%MiddleGen%/lib下
%Hibernate-Extension_Home%/tools/hibernate-tools.jar到%MiddleGen%/lib下
2 MiddleGen的配置
配置目标数据库参数
进入MiddleGen 目录下的\config\database 子目录,根据我们实际采用的数据库打开对应的配置文件。如这里我用的是mysql数据库,对应的就是mysql.xml文件。
<property
name="database.script.file" value="${src.dir}/sql/${name}-mysql.sql"/>
<property
name="database.driver.file" value="${lib.dir}/mysql.jar"/>
<property
name="database.driver.classpath" value="${database.driver.file}"/>
<property
name="database.driver" value="org.gjt.mm.mysql.Driver"/>
<property
name="database.url" value="jdbc:mysql://localhost/sample"/>
<property
name="database.userid" value="user"/>
<property
name="database.password" value="mypass"/>
<property
name="database.schema" value=""/>
<property
name="database.catalog" value=""/>
<property
name="jboss.datasource.mapping" value="mySQL"/>
其中下划线标准的部分是我们进行配置的内容,分别是数据url以及数据库用
户名和密码。
1) 修改Build.xml
修改MiddleGen 根目录下的build.xml 文件,此文件是Middlegen-Hibernate 的Ant构建配置。Middlegen-Hibernate将根据build.xml文件中的具体参数生成数据库表映射文件。可配置的项目包括:
a) 目标数据库配置文件地址
查找关键字 ”!ENTITY”,得到:
<!DOCTYPE project [
<!ENTITY database SYSTEM
"file:./config/database/hsqldb.xml">
]>
默认情况下,MiddleGen 采用的是hsqldb.xml,
将其修改为我们所用的数据库配置文件(mysql.xml):
<!DOCTYPE project [
<!ENTITY database SYSTEM
"file:./config/database/mysql.xml">
]>
b) Application name
查找:
<property value="airline"/>
“aireline”是MiddleGen原始配置中默认的 Application Name,将其修改为我们
所希望的名称,如“HibernateSample”:
<property value="HibernateSample"/>
c) 输出目录
查找关键字“name="build.gen-src.dir"”,得到:
<property
value="${build.dir}/gen-src"/>
修改value="${build.dir}/gen-src"使其指向我们所期望的输出目录,
这里我们修改为:<property
value="C:\sample"/>
d) 对应代码的Package name
查找关键字“destination”,得到:
<hibernate
destination="${build.gen-src.dir}"
package="${name}.hibernate"
genXDocletTags="false"
genIntergratedCompositeKeys="false"
javaTypeMapper=
"middlegen.plugins.hibernate.HibernateJavaTypeMapper"
/>
可以看到,hibernate 节点package 属性的默认设置实际上是由前面的
Application Name (${name})和“.hibernate”组合而成,根据我们的需要,
这里还有一个属性genXDocletTags,如果设置为true,则生成的代码将包含
xdoclet tag,这为以后在开发过程中借助xdoclet进行映射调整提供了帮助。注意,如果使用的数据库为SQLServer,需要将build.xml部分删除(参见夏?^的文档),否则Middlegen会报出找不到表的错误。
至此为止,MiddleGen 已经配置完毕,在MiddleGen 根目录下运行ant,就将出现
MiddleGen的界面:
2 *.xml到.java
在得到.xml后,使用ant hbm2java 即可得到相应的java文件
总结:
我第一次运行成功,但是后来则出现如下类似错误,检查发现在MiddleGen的lib目录下存在多个类似的jar包
(velocity.jar,velocity1-0.8.jar),删除旧的jar包后,问题解决
[middlegen] java.lang.IncompatibleClassChangeError
[middlegen] at [middlegen] at org.apache.velocity.Template.process(Template.java:136)
2.(评论)关于Many-to-Many需要注意的问题
比如group/user,user/role,group/role,都是多对多的关系。
所以有必要搞搞清楚。以group/user为例
(1)group.getUsers() & user.getGroups()双向映射。在这里,考虑到user.setGroups()是不会放出来的。所以在user端加入inverse=true,就是说,让Group端来维护两者的关系表。
(2)于是,添加的时候,要把user加入到group的user set中,保存,才有意义!
(3)如果要删除group_user的关系,而不是group/user本身,那么,需要在group端设定casade=save-update。否则,group.getUsers().remove(user)不会起作用!
(4)由于有了FK保护,你是无法单独删除User的。同时,由于你指定了inverse=true,所以无法光光的设置user.getGroups().clear就能够搞定一切。你必须首先在每个Group.getUsers中删除这个user,才能最后删除。所以,UserManagerImpl代码可能看起来像这样:
public void delUser(User user) {
if (user == null) {
logger.info("Got a null user object!");
return;
}
Session session = null;
Transaction trans = null;
boolean bSuccess = false;
try {
String username = new String(user.getName());
session = PLUtils.getSession();
trans = session.beginTransaction();
session.update(user);
Set groups = ((UserEntity)user).getGroups();
for(Iterator i = groups.iterator();i.hasNext();){
GroupEntity g = (GroupEntity)i.next();
session.update(g);
g.getUsers().remove(user);
session.update(g);
}
// ((UserEntity)user).getGroups().clear();
session.delete(user);
bSuccess = true;
logger.debug("User " + username + " deleted ok!");
}
catch (ObjectNotFoundException onfe) {
logger.info("user not found!", onfe);
}
catch (Exception e) {
logger.error("failed!", e);
}
finally {
try {
if (bSuccess)
trans.commit();
else
trans.rollback();
session.close();
}
catch (Exception ex) {
}
}
}