(转)Hibernate之one-to-many XML 篇
Hibernate的ORM关系,
下面将通过简单的事例来了解Hibernate ont-to-many/many-to-one双向配置、inverse、cascade的常用配置:
一、首现创建简单的数据库Table:user<用户>以及book<图书> 这里假设user与book的关系是一对多,创建代码如下:
MySql下:
(1)创建user Table:
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`uid` int(11) NOT NULL auto_increment,
`uname` varchar(255) NOT NULL,
PRIMARY KEY (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=latin1;
(2)创建book Table:
DROP TABLE IF EXISTS `book`;
CREATE TABLE `book` (
`bid` int(11) NOT NULL auto_increment,
`bname` varchar(20) NOT NULL,
`buid` int(11) NOT NULL,
PRIMARY KEY (`bid`),
KEY `FK_USER` (`buid`),
CONSTRAINT `FK_USER` FOREIGN KEY (`buid`) REFERENCES `user` (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=38 DEFAULT CHARSET=latin1;
二、编写相印的Entity Class,这里用的是XML配置方法,有关Annotation将在以后的文章中发表,
(1)User Entity:
public class User implements java.io.Serializable {
// Fields
private Integer uid;
private String uname;
private Set books = new HashSet(0); //one-to-many关系,作为one的一方使用Set来存储many方的数据表示
// Constructors
public User() {
}
get....
set...方法
}
(2)Book Entity:
public class Book implements java.io.Serializable {
// Fields
private Integer bid;
private User user; //one一方的实体对象<数据库关系是通过外键来关联,即:book表中有user 表的ID外键>
private String bname;
// Constructors
public Book() {
}
get....
set...方法
}
三、有关ORM隐射文件:
(1)User.hbm.xml:
(2)Book.hbm.xml:
好,至此上面的配置已经完成,下面是测试代码:
一、测试级联添加:
public static void ontToManyAdd_User() {
//获取Session/并打开事务
SessionFactory factory = HibernateSessionFactory.getSessionFactory();
Session session = factory.openSession();
Transaction st = session.beginTransaction();
try {
//创建User对象
User user = new User();
user.setUname("A");
//创建Book对象,并存储至Set集合中
Set book_set = new HashSet();
Book book1 = new Book();
book1.setBname("Java");
Book book2 = new Book();
book2.setBname("C++");
Book book3 = new Book();
book3.setBname("Net");
book_set.add(book1);
book_set.add(book2);
book_set.add(book3);
//设置Book对象中的User对象属性 注意:一定要设置该属性如果不设定,将不能级联添加Book
book1.setUser(user);
book2.setUser(user);
book3.setUser(user);
user.setBooks(book_set);
session.save(user);
st.commit();
System.out.println("添加成功!");
} catch (Exception e) {
System.out.println(e.getMessage());
st.rollback();
} finally {
session.close();
}
}
上面的代码测试结果如下:
Hibernate: insert into hibernate_db.user (uname) values (?)
Hibernate: insert into hibernate_db.book (buid, bname) values (?, ?)
Hibernate: insert into hibernate_db.book (buid, bname) values (?, ?)
Hibernate: insert into hibernate_db.book (buid, bname) values (?, ?)
添加成功!
在上面的代码以及配置中需要注意的有一下几点:
<1>、
book1.setUser(user);
book2.setUser(user);
book3.setUser(user);
设置book对象中的User对象属性,因为数据库中book表中的uid字段为not null所以此时需要为Book Entity中的User 对象设置属性,如果不设置则会出现一下错误:
Hibernate: insert into hibernate_db.user (uname) values (?)
Hibernate: insert into hibernate_db.book (buid, bname) values (?, ?)
could not insert: [com.model.Book]
提示不能insert Book对象中。
<2>、
User.hbm.xml中的 cascade的配置,这个属性可以简单的理解为:"级联操作的类型" ,这里 的cascade="all" 意思是:不管当前操作User对象是增删改还是查 都将对User中的books这个集合进行级联操作,当然还可以设为其他的属性值,如:save-update、、、、cascade的使用场合:当操作其中一个或者一些元素,但是又需要级联到操作到另外一个元素时就需要为此配置。比方说这里的User对象:当添加一个User时需要级联添加N个Book那么就需要为User中的Book集合对象books设定cascade属性,当然在Book中也是设定cascade属性去级联操作User对象。
二、
测试级联查询:
public static void ontToManySelect() {
SessionFactory factory = HibernateSessionFactory.getSessionFactory();
Session session = factory.openSession();
try {
//获取User对象
User user = (User) session.get(User.class, 27);
System.out.println("User_Name:" + user.getUname());
//session.close(); //代码1
if (user != null) {
//获取User对象中的books集合数据
Iterator iter = user.getBooks().iterator();
while (iter.hasNext()) {
Book b = iter.next();
System.out.println("\t Book_Name:" + b.getBname());
}
}
} catch (Exception e) {
System.out.println(e.getMessage());
} finally {
session.close();
}
}
在上面的级联查询代码中有一个细节需要我们注意的:
User.hbm.xml 中 Set 里面的lazy属性配置,其含义是懒加载,作用可以简单的理解为:“当加载一个或者一些元素的时候 是否也相印的加载这个元素中相关联的其他元素”,在Hibernate默认的配置中lazy的属性值是true,即:不主动去加载其相关的元素,这样有个好处,那就是在我们需要的时候才去查询,怎么才算是需要的时候呢?比方说上面的:Iterator iter = user.getBooks().iterator();这里当我们使用到User对象中相关联元素的时候,Hibernate才会发出Sql语句去查询。但是这样也会遇到一个问题:那就是 当在用到相关对象之前 (如:注释中的代码1),Hibernate的Session如果关闭了那么就不能再获取到该对象了。这个时候如果再在视图层或者后台中读取其相关的属性时就会出现:
Session was already closed 错误
所以在使用中还得看各自的需求来配置lazy。
上面已经简述完了one-to-many以及many-to-one的双向关系,其实还是有许多的东西需要我们实际操作中才会遇到以及学习到。