到2011年寒假之末,我终于把当前java主流的三大开源框架——hibernate,struts,spring——初步学完。我看的是尚学堂马士兵老师的视频教程。学完后觉得必须找点东西练练手,于是自己意淫出一个小项目,计划用三大框架,结合软件工程的一些知识去把它做出来,以巩固刚学到一些用法。
但是,我在开始就遇到了难题——数据库如何设计、hibernate里的关联是啥回事、ER图如何设计?这时我才发现我其实根本就不懂数据库。记得我当时是如何开心而轻松的看完马士兵老师关于关联的教程,现在才知道我没有从稍微根本的层面去理解关联。这个实验就是为了帮助我“从稍微根本的层面去理解关联”而做的。
在这次比较认真的实验之前,我零零星星的做了好多次各种情况的实验,试图帮助自己更好的理解关联,但是我的意图都没达到。原因是我每次实验后都试图把结果记住而达到目的,但事实上结果我很快就忘记了,忘记了又得做。所以这次索性做认真点,做完之后也不去记实验结果,而是去总结关系数据库是如何表示实体之间的关联的。也希望大家不要记实验结果,而去理解规律。
实验中有错误之处,请无情指出,笔者会及时改过,以免误人子弟:)。
myeclipse集成环境,powerdesigner数据库工具,mysql数据库,mysql query browser图形化管理工具。
本实验只用到hibernate框架,所有数据库表都有hibernate自动生成。而且为了写文档的方便,用的是hibernate annotation做的实验。
工程环境见下图:
图表 1工程环境
第一个类:
package me.hibernate.model; import java.util.*; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToMany; import javax.persistence.Table; @Entity @Table(name="myGroup") public class Group { private int id; private String name; private Set<User> users = new HashSet<User>(); @OneToMany(cascade={CascadeType.ALL}) @JoinColumn(name="groupId") public Set<User> getUsers() { return users; } public void setUsers(Set<User> users) { this.users = users; } @Id @GeneratedValue public int getId() { return id; } public String getName() { return name; } public void setId(int id) { this.id = id; } public void setName(String name) { this.name = name; } }
第二个类:
package me.hibernate.model; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.ManyToOne; import javax.persistence.Table; @Entity @Table(name="myUser") public class User { private int id; private String name; private Group group; @Id @GeneratedValue public int getId() { return id; } public String getName() { return name; } public void setId(int id) { this.id = id; } public void setName(String name) { this.name = name; } public void setGroup(Group group) { this.group = group; } @ManyToOne() public Group getGroup() { return group; } }
Junit测试类:
package me.hibernate.model; import java.util.*; import org.hibernate.Session; import org.hibernate.cfg.AnnotationConfiguration; import org.junit.Test; public class TestORM { @Test public void testSave(){ User u1,u2,u3; Group g; Set<User> users = new HashSet<User>(); u1 = new User(); u2 = new User(); u3 = new User(); g = new Group(); u1.setName("me"); u2.setName("you"); u3.setName("him"); users.add(u1); users.add(u2); users.add(u3); g.setName("bigGroup"); g.setUsers(users); AnnotationConfiguration cfg = new AnnotationConfiguration(); Session session = cfg.configure().buildSessionFactory().getCurrentSession(); session.beginTransaction(); session.save(g); session.getTransaction().commit(); } }
hibernate配置文件:
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="connection.driver_class"> com.mysql.jdbc.Driver </property> <property name="connection.url"> jdbc:mysql://localhost:3306/hibernate </property> <property name="connection.username">root</property> <property name="connection.password">root</property> <property name="dialect"> org.hibernate.dialect.MySQLDialect </property> <property name="current_session_context_class">thread</property> <property name="cache.provider_class"> org.hibernate.cache.NoCacheProvider </property> <property name="show_sql">true</property> <property name="hbm2ddl.auto">update</property> <property name="format_sql">true</property> <mapping class="me.hibernate.model.Group" /> <mapping class="me.hibernate.model.User" /> </session-factory> </hibernate-configuration>
三、实验内容
以下只贴出在实验中改变的代码。在实验的每一个步骤(以为8个步骤,而非2个步骤)之前,上一步骤中生成的数据库表会被全部删除,以免干扰当前的实验内容。其中每一步骤,junit方法都没有报错,最大程度的确保实验结果的可靠性。
做出改动的代码 |
|
Group类 |
User类 |
@OneToMany(cascade={CascadeType.ALL}) @JoinColumn(name="groupId") public Set<User> getUsers() { return users; } |
@ManyToOne() public Group getGroup() { return group; } |
图表 2 数据库内生成的表
图表 3用powerdesigner对表进行逆向的结果
做出改动的代码 |
|
Group类 |
User类 |
@OneToMany(cascade={CascadeType.ALL}) public Set<User> getUsers() { return users; } |
@ManyToOne() public Group getGroup() { return group; } |
图表 4 数据库内生成的表
图表 5 用powerdesigner对表进行逆向的结果
做出改动的代码 |
|
Group类 |
User类 |
@OneToMany(mappedBy="group",cascade={CascadeType.ALL}) @JoinColumn(name="groupId") public Set<User> getUsers() { return users; } |
@ManyToOne() public Group getGroup() { return group; } |
图表 6 数据库内生成的表
图表 7 用powerdesigner对表进行逆向的结果
做出改动的代码 |
|
Group类 |
User类 |
@OneToMany(mappedBy="group",cascade={CascadeType.ALL}) public Set<User> getUsers() { return users; } |
@ManyToOne() public Group getGroup() { return group; } |
图表 8 数据库内生成的表
图表 9 用powerdesigner对表进行逆向的结果
做出改动的代码 |
|
Group类 |
User类 |
@OneToMany(cascade={CascadeType.ALL}) public Set<User> getUsers() { return users; } |
无group属性 |
图表 10 数据库内生成的表
图表 11 用powerdesigner对表进行逆向的结果
做出改动的代码 |
|
Group类 |
User类 |
@OneToMany(cascade={CascadeType.ALL}) @JoinColumn(name="groupId") public Set<User> getUsers() { return users; } |
无group属性 |
图表 12 数据库内生成的表
图表 13 用powerdesigner对表进行逆向的结果
做出改动的代码 |
|
Group类 |
User类 |
无users属性 |
@ManyToOne(cascade={CascadeType.ALL}) @JoinColumn(name="groupId") public Group getGroup() { return group; } |
Junit测试类改成如下 |
|
package me.hibernate.model; import org.hibernate.Session; import org.hibernate.cfg.AnnotationConfiguration; import org.junit.Test; public class TestORM { @Test public void testSave(){ User u1,u2,u3; Group g; u1 = new User(); u2 = new User(); u3 = new User(); g = new Group(); u1.setName("me"); u2.setName("you"); u3.setName("him"); g.setName("bigGroup"); u1.setGroup(g); u2.setGroup(g); u3.setGroup(g); AnnotationConfiguration cfg = new AnnotationConfiguration(); Session session = cfg.configure().buildSessionFactory().getCurrentSession(); session.beginTransaction(); session.save(u1); session.save(u2); session.save(u3); session.getTransaction().commit(); } } |
图表 14 数据库内生成的表
图表 15 用powerdesigner对表进行逆向的结果
做出改动的代码 |
|
Group类 |
User类 |
无users属性 |
@ManyToOne(cascade={CascadeType.ALL}) public Group getGroup() { return group; } |
Junit测试类改成如下 |
|
同上 |
图表 16 数据库内生成的表
图表 17 用powerdesigner对表进行逆向的结果
如果一对多(多对一)和多对多不是一回事的话(我认为其实他们是一回事),那么在关系数据库里只有多对多才有双向关联,一对多和多对一没有双向关联(hibernate里的一对多双向十靠hibernate自己维护的),倘若一对多和多对一有双向关联,它们已经是实际意义上的多对多关系了。
(排版不是很好,特别文章里的一些表格看起来效果好差,大家凑合看哈)