Hibernate一对多单向配置详细说明实例教程,index.jsp页面显示:
Hibernate一对多关联,例如一个用户有多张银行卡(只考虑用户到银行卡的单向一对多关联)。由于是学习Hibernate原理,并没有使用工具自动生成代码等。
单向一对多关联只需要在”一方”进行配置即可,”多方”无需额外配置。
a.Java程序中所要做的一对多:
1
2
3
4
5
6
7
8
9
|
public class User{ ... private Set< Card > cards; ... } public class Card{ ... } |
b.Hibernate中所要做的一对多:
1
2
3
4
5
6
7
|
User.hbm.xml: ... < set name = "cards" inverse = "false" cascade = "all" > < key column = "userId" /> < one-to-many class = "wintys.hibernate.onetomany.Card" /> </ set > ... |
c.数据库中的一对多:
而对应的数据库中,只要相应在Card对应的物理表中添加外键userId(不为设为NOT NULL)即可。
详细的MyEclipse WebProject如下:
1、实体类:
用户类User.java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
package wintys.hibernate.onetomany; import java.util.Set; public class User { private String id; private String name; private Set< Card > cards; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void setCards(Set< Card > cards) { this.cards = cards; } public Set< Card > getCards() { return cards; } } |
银行卡类Card.java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
package wintys.hibernate.onetomany; public class Card { private String id; private float balance; public Card(){ } public Card(float balance){ this.balance = balance; } public String getId() { return id; } public void setId(String id) { this.id = id; } public float getBalance() { return balance; } public void setBalance(float balance) { this.balance = balance; } } |
2、数据库表:
数据库是MySQL 5.1.34-community。
用户表:
1
2
3
4
5
|
CREATE TABLE myuser( id VARCHAR(50) NOT NULL, name VARCHAR(100), PRIMARY KEY(id) ); |
银行卡表:
1
2
3
4
5
6
|
CREATE TABLE mycard( id VARCHAR(50) NOT NULL, balance FLOAT(7,2), userId VARCHAR(50), PRIMARY KEY(id) ); |
3、映射文件:
用户类映射文件/src/wintys/hibernate/onetomany/User.hbm.xml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<? xml version = "1.0" encoding = "UTF-8" ?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" <!-- Mapping file autogenerated by MyEclipse Persistence Tools --> < hibernate-mapping > < class name = "wintys.hibernate.onetomany.User" table = "myuser" catalog = "db" > < id name = "id" type = "string" > < column name = "id" not-null = "true" /> < generator class = "uuid.hex" /> </ id > < property name = "name" type = "java.lang.String" column = "name" /> < set name = "cards" inverse = "false" cascade = "all" > < key column = "userId" /> < one-to-many class = "wintys.hibernate.onetomany.Card" /> </ set > </ class > </ hibernate-mapping > |
银行卡映射文件/src/wintys/hibernate/onetomany/User.hbm.xml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<? xml version = "1.0" encoding = "UTF-8" ?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" <!-- Mapping file autogenerated by MyEclipse Persistence Tools --> < hibernate-mapping > < class name = "wintys.hibernate.onetomany.Card" table = "mycard" catalog = "db" > < id name = "id" type = "string" > < column name = "id" not-null = "true" /> < generator class = "uuid.hex" /> </ id > < property name = "balance" /> </ class > </ hibernate-mapping > |
Hibernate配置文件:/src/hibernate.cfg.xml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
<? xml version = '1.0' encoding = 'UTF-8' ?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" <!-- Generated by MyEclipse Hibernate Tools. --> < hibernate-configuration > < session-factory > < property name = "connection.username" >root</ property > < property name = "connection.url" > </ property > < property name = "dialect" > org.hibernate.dialect.MySQLDialect </ property > < property name = "myeclipse.connection.profile" >MySQLDriver</ property > < property name = "connection.password" >root</ property > < property name = "connection.driver_class" > com.mysql.jdbc.Driver </ property > < property name = "show_sql" >true</ property > < mapping resource = "wintys/hibernate/onetomany/User.hbm.xml" /> < mapping resource = "wintys/hibernate/onetomany/Card.hbm.xml" /> </ session-factory > </ hibernate-configuration > |
4、使用测试:
1
2
3
4
5
6
7
8
9
|
/src/wintys/hibernate/onetomany/HibernateDAO.java: package wintys.hibernate.onetomany; import java.util.List; public interface HibernateDAO { public void insert(); public List< User > selectAll(); } |
/src/wintys/hibernate/onetomany/HibernateDAOBean.java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
package wintys.hibernate.onetomany; import java.util.HashSet; import java.util.List; import java.util.Set; import org.hibernate.HibernateException; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.Transaction; public class HibernateDAOBean implements HibernateDAO { public void insert() throws HibernateException { Transaction tc = null; try{ Set< Card > cards = new HashSet< Card >(); Card c1,c2,c3; c1 = new Card(7641.96f); c2 = new Card(654.8f); c3 = new Card(3650f); cards.add(c1); cards.add(c2); cards.add(c3); User user = new User(); user.setName("Tom"); user.setCards(cards); Session session = HibernateUtil.getSession(); tc = session.beginTransaction(); /* 配置文件中的cascade="true"时,所以无需手动保存c1,c2,c3 session.save(c1); session.save(c2); session.save(c3); */ session.save(user); tc.commit(); }catch(HibernateException e){ try{ if(tc != null) tc.rollback(); }catch(Exception ex){ System.err.println(ex.getMessage()); } System.err.println(e.getMessage()); }finally{ HibernateUtil.closeSession(); } } @SuppressWarnings("unchecked") public List< User > selectAll() throws HibernateException { List< User > users = null; Transaction tc = null; try{ Session session = HibernateUtil.getSession(); tc = session.beginTransaction(); Query query = session.createQuery("from User"); users = query.list(); tc.commit(); }catch(HibernateException e){ try{ if(tc != null){ tc.rollback(); users = null; } }catch(Exception ex){ System.err.println(ex.getMessage()); } System.err.println(e.getMessage()); }finally{ //HibernateUtil.closeSession(); } return users; } } |
/src/wintys/hibernate/onetomany/HibernateUtil.java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
package wintys.hibernate.onetomany; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; /** * Hibernate Session管理 * @author Winty */ public class HibernateUtil { private static SessionFactory factory = null; private static ThreadLocal< Session > threadLocal; static { try{ factory = new Configuration() .configure() .buildSessionFactory(); }catch(HibernateException e){ System.err.println(e.getMessage()); } threadLocal = new ThreadLocal< Session >(); } private HibernateUtil(){ } public static Session getSession()throws HibernateException{ Session session = threadLocal.get(); if(session == null){ session = factory.openSession(); threadLocal.set(session); } return session; } public static void closeSession()throws HibernateException{ Session session = threadLocal.get(); if(session != null){ session.close(); } threadLocal.set(null); } } |
/index.jsp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%> <%@ page import="wintys.hibernate.onetomany.*"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> < html > < head > < title >My JSP 'index.jsp' starting page</ title > </ head > < body > <% List< User > users = null; HibernateDAO dao = new HibernateDAOBean(); dao.insert(); users = dao.selectAll(); Iterator< User > it = users.iterator(); while(it.hasNext()){ User user = it.next(); String id = user.getId(); String name = user.getName(); out.println("id:" + id + "< br />"); out.println("name:" + name + "< br />"); out.println("cards:< br />"); Set< Card > cards = user.getCards(); Iterator< Card > itc = cards.iterator(); while(itc.hasNext()){ Card card = itc.next(); String cardId = card.getId(); float balance = card.getBalance(); out.println(" cardId:" + cardId + "< br />"); out.println(" balance:" + balance + "< br />"); } out.println("< hr />"); } %> </ body > </ html > |
5、运行结果:
控制台显示:
1
2
3
4
5
6
7
8
9
|
...... Hibernate: insert into db.myuser (name, id) values (?, ?) Hibernate: insert into db.mycard (balance, id) values (?, ?) Hibernate: insert into db.mycard (balance, id) values (?, ?) Hibernate: insert into db.mycard (balance, id) values (?, ?) Hibernate: update db.mycard set userId=? where id=? Hibernate: update db.mycard set userId=? where id=? Hibernate: update db.mycard set userId=? where id=? ...... |
id:402881e421d4d0be0121d4d20e140005
name:Tom
cards:
cardId:402881e421d4d0be0121d4d20e230008
balance:654.8
cardId:402881e421d4d0be0121d4d20e230006
balance:7641.96
cardId:402881e421d4d0be0121d4d20e230007
balance:3650.0
6、Hibernate一对多单向配置注意的问题:
a、hibernate错误提示:Field ‘userId’ doesn’t have a default value解决方法。
刚开始把”userId”设成NOT NULL,但是Hibernate先执行的是:
“insert into db.mycard (balance, id) values (?, ?)”
然后再执行”update db.mycard set userId=? where id=?”,
但userId在insert时没有写入值的,因此就会报错。这时将userId的NOT NULL去掉就可以了。
b、User.hbm.xml要设置cascade=”all”,或者是其它有效值,要不,保存User对象的时候,有关的Card对象不会被保存。
c、User.hbm.xml中set标签的inverse属性不能设为”true”,inverse的默认为”false”,因此不加inverse也行的。看书上说:在一对多的关联关系实现中,最好设置inverse=”true”,将有助于性能的改善。所以一开始就用了inverse=”true”,User和Card对象都分别正确写入数据库了,但是就是userId字段没有被自动写入。
myuser表:
+——————————————–+——+
| id | name |
+——————————————–+——+
| 402881e421d4d0be0121d4d20e140005 | Tom |
+——————————————–+——+
mycard表:
+——————————————–+———+———
| id | balance | userId
+——————————————–+———+———
| 402881e421d4d0be0121d4d20e230006 | 7641.96 | NULL
| 402881e421d4d0be0121d4d20e230007 | 3650.00 | NULL
|
| 402881e421d4d0be0121d4d20e230008 | 654.80 | NULL
+——————————————–+———+———
问题的原因原来在本例应该把inverse设置为false。inverse是很有用的,不过用错了地方。 本文链接地址: Hibernate一对多单向配置详细说明实例教程inverse属性用法