数据库表关系及配置--多对多&一对多
1.数据库表中的关系
一对一
一对多(多对一)
多对多
2.如何确立和实现数据库中的表关系
一对多的表关系实现:
使用外键约束
我们习惯把一的方称为主表,把多的方称为从表
外键:从表中有一列,除了null之外,只能来源于主表的主键
默认情况下,外键的字段是可以重复的
多对多的表关系在数据库中实现:
使用中间表
中间表有两个外键,引用两个多对多表的主键
不能有其它字段信息,至于中间表的主键,应该采用联合主键
任何一个多方表和中间表去比较都是一对多的关系
一对一的表关系再数据库中实现:
有两种:
1.以建立外键的方式
使用外键约束,唯一约束,非空约束
他是把外键字段加上了非空和唯一约束,从而实现一对一
2.使用主键的方式
让其中一张表即是主键,又是外键。
3.多表映射配置要遵循的步骤
第一步:确定两张表之间的关系
第二步:在数据库中实现两张表之间的关系建立
第三步:在实体类中描述出两个实体之间的关系
第四步:在映射配置文件中简历两个实体和两个表之间的关系
4.一对多关系映射配置及操作
示例:人员表和角色表
第一步:确定两个表之间的关系
一个角色可以对应多个人员
role角色表是主表,person人员表是从表
第二步:在数据库表中简历联系
实现一对多关系,靠外键
person表中的r_id外键,是person的主键。
代码示例:
1.数据库表
2.hibernate.md.xml配置
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <!--SessionFactory用来创建Session对象,Session对象时操作数据库的核心--> <!--SessionFactory必要部分:1.连接数据库信息;2.hibernate的可选配置;3.映射文件配置--> <session-factory> <!-- 1.连接数据库的基本信息 --> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://127.0.0.1:3306/mybatis</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">root</property> <!-- 2.hibernate的可选配置 --> <!-- hibernate里的配置,数据库使用的方言,开发过程中要在控制台显示,sql --> <!--<property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>--> <property name="hibernate.show_sql">true</property> <!-- <property name="hibernate.format_sql">true</property>--> <property name="hibernate.hbm2ddl.auto">update</property> <!--绑定线程和session,实现一个session只有一个线程。--> <property name="hibernate.current_session_context_class">thread</property> <!-- c3p0的配置 --> <!-- hibernate.connection.provider_class使用c3p0数据库连接池的一个配置 --> <property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property> <!--3.映射文件配置--> <!-- ORM映射关系 ,导入相应模型的绝对路径--> <mapping resource="person.hbm.xml"/> <mapping resource="role.hbm.xml"/> </session-factory> </hibernate-configuration>
3.person.hbm.xml
<?xml version="1.0" encoding="utf-8" ?> <!--导入dbd约束--> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.bean"> <class name="Person" table="person"> <id name="pId" column="p_id"> <generator class="native"></generator> </id> <property name="pName" column="p_name"></property> <property name="pAddress" column="p_address"></property> <!--一对多关系映射:从表实体的映射配置 涉及的标签: many-to-one 作用:建立多对一的映射配置 属性:name 从实体中映入主表实体对象的引用名称 class 指定属性对应的实体类名称 column 指定从表中外键字段的名称 --> <many-to-one name="role" class="Role" column="p_r_id"></many-to-one> </class> </hibernate-mapping>
4.role.hbm.xml
<?xml version="1.0" encoding="utf-8" ?> <!--导入dbd约束--> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.bean"> <class name="Role" table="role"> <id name="rId" column="r_id"> <generator class="native"></generator> </id> <property name="rName" column="r_name"></property> <!--一对多关系映射:主表实体的映射配置 涉及的标签: set/list key many-to-one 作用:用于配置set/list集合属性 属性:name 指定实体中set/list集合属性名称 table 指定从表名称。一对多配置可以补血 key作用:用于映射外键字段 属性:column 指定外键名称 many-to-one作用:建立一对多的映射配置 属性:calss 指定从表实体的名称 cascade="save-update" 级联更新为true 级联删除需要配置inverse="true" cascade="save-update,delete"(开发中一般慎用) --> <set name="set" table="person" inverse="true" cascade="save-update,delete"> <key column="p_r_id" ></key> <one-to-many class="Person"></one-to-many> </set> </class> </hibernate-mapping>
5.实体类
public class Person implements Serializable { private Integer pId; private String pName; private String pAddress; //一对多关系映射,从表实体包含主表实体的对象引用 private Role role; } //省了get/set方法
public class Role implements Serializable { private Integer rId; private String rName; //一对多关系映射,主表实体应该包含从表实体的集引用 private Set<Person> set; } //省去get/set方法
6.测试类
public class TestHibernate01 { //查询Person @Test public void test01() { Session s = HibernateUtils.getCurrnetSession(); Transaction tx = s.beginTransaction(); Query query = s.createQuery("from Person "); List list = query.list(); for (Object o : list) { Person person = (Person) o; System.out.println(person.getpName() + ":" + person.getRole().getrName()); } tx.commit(); } //查询所有的Role @Test public void test02() { Session s = HibernateUtils.getCurrnetSession(); Transaction tx = s.beginTransaction(); Query query = s.createQuery("from Role"); List list = query.list(); for (Object o : list) { Role role = (Role) o; System.out.println(role.getrName()); for (Person person : role.getSet()) { System.out.println("set:" + person.getpName()); } } tx.commit(); } //修改角色的操作保存操作 @Test public void test03() { Session s = HibernateUtils.getCurrnetSession(); Transaction tx = s.beginTransaction(); Role o = (Role) s.get(Role.class, 1); System.out.println("Role=" + o); Person o1 = (Person) s.get(Person.class, 2); o1.setRole(o); System.out.println("Person=" + o1); s.update(o1); tx.commit(); } //级联更新 // set标签的属性cascade="save-update" 级联更新为true @Test public void test04() { Session s = HibernateUtils.getCurrnetSession(); Transaction tx = s.beginTransaction(); Role o = (Role) s.get(Role.class, 3); o.setrName("大将"); System.out.println("Role=" + o.getrName()); s.save(o); tx.commit(); } //级联删除 // set标签 级联删除需要配置inverse="true" cascade="save-update,delete"(开发中一般慎用) @Test public void test05() { Session s = HibernateUtils.getCurrnetSession(); Transaction tx = s.beginTransaction(); Role o = (Role) s.get(Role.class, 3); s.delete(o); tx.commit(); } }
5.多对多关系映射配置及操作
使用中间表
中间表有两个外键,引用两个多对多表的主键
需求:实现角色表和权限表之间的多对多,没个角色多个权限,每个权限对应多个角色
1.修改Role角色类和创建Astrict权限类
public class Role implements Serializable { private Integer rId; private String rName; //一对多关系映射,主表实体应该包含从表实体的集引用 private Set<Person> set=new HashSet<Person>(0); private Set<Astrict> astricts=new HashSet<Astrict>(0); public Set<Astrict> getAstricts() { return astricts; } public void setAstricts(Set<Astrict> astricts) { this.astricts = astricts; } @Override public String toString() { return "Role{" + "rId=" + rId + ", rName='" + rName + '\'' + ", set=" + set + '}'; } public Set<Person> getSet() { return set; } public void setSet(Set<Person> set) { this.set = set; } public Integer getrId() { return rId; } public void setrId(Integer rId) { this.rId = rId; } public String getrName() { return rName; } public void setrName(String rName) { this.rName = rName; } }
import java.io.Serializable; import java.util.HashSet; import java.util.Set; public class Astrict implements Serializable { private Integer aId; private String aName; private String aType; public Set<Role> getRoles() { return roles; } public void setRoles(Set<Role> roles) { this.roles = roles; } private Set<Role> roles=new HashSet<Role>(0); public String getaType() { return aType; } public void setaType(String aType) { this.aType = aType; } public Integer getaId() { return aId; } public void setaId(Integer aId) { this.aId = aId; } public String getaName() { return aName; } public void setaName(String aName) { this.aName = aName; } }
2.配置astrict.hbm.xml和role.hbm.xml文件
<?xml version="1.0" encoding="utf-8" ?> <!--导入dbd约束--> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.bean"> <class name="Astrict" table="astrict"> <id name="aId" column="a_id"> <generator class="native"></generator> </id> <property name="aName" column="a_name"></property> <property name="aType" column="a_type"></property> <!-- 多对多 table指定中间表名称 many-to-many作用:建立多对多的映射配置 属性:column 对方在中间表的外键字段名称 calss 指定从表实体的名称 --> <set name="roles" table="astrict_role_ref"> <key column="a_id"></key> <many-to-many class="Role" column="r_id"></many-to-many> </set> </class> </hibernate-mapping>
<?xml version="1.0" encoding="utf-8" ?> <!--导入dbd约束--> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.bean"> <class name="Role" table="role"> <id name="rId" column="r_id"> <generator class="native"></generator> </id> <property name="rName" column="r_name"></property> <!--一对多关系映射:主表实体的映射配置 涉及的标签: set/list key many-to-one 作用:用于配置set/list集合属性 属性:name 指定实体中set/list集合属性名称 table 指定从表名称。一对多配置可以补血 key作用:用于映射外键字段 属性:column 指定外键名称 lazy="true" 懒加载 many-to-one作用:建立一对多的映射配置 属性:calss 指定从表实体的名称 cascade="save-update" 级联更新为true 级联删除需要配置inverse="true" cascade="save-update,delete"(开发中一般慎用) --> <set name="set" table="person" inverse="true" cascade="save-update,delete" lazy="true"> <key column="p_r_id" ></key> <one-to-many class="Person"></one-to-many> </set> <!-- inverse="true" 只有多对多只有一方执行操作 多对多 table指定中间表名称 many-to-many作用:建立多对多的映射配置 属性:column 对方在中间表的外键字段名称 calss 指定从表实体的名称 --> <set name="astricts" table="astrict_role_ref" inverse="true"> <key column="r_id"></key> <many-to-many class="Astrict" column="a_id"></many-to-many> </set> </class> </hibernate-mapping>
3.在主配置文件添加映射
<mapping resource="astrict.hbm.xml"/>
4.测试
多对多保存,多对多全部查询,多对多添加查询
/**
* 多对多保存操作
* 需求:角色-主公的带兵,献计和封侯权限;军事-主公的带兵和献计权限;大将-主公的带兵
*/
@Test
public void test01() {
Session s = HibernateUtils.getCurrnetSession();
Transaction tx = s.beginTransaction();
Role r1 = (Role)s.get(Role.class, 1); //角色1 主公
Role r2 = (Role)s.get(Role.class, 2); //角色1 军师
Role r3 = (Role)s.get(Role.class, 3); //角色1 大将
Astrict a1=new Astrict();
a1.setaName("带兵");
Astrict a2=new Astrict();
a2.setaName("献计");
Astrict a3=new Astrict();
a3.setaName("封侯");
//建立双向联系
//1.先建立角色的
//主公 -- 带兵,献计,封侯
r1.getAstricts().add(a1);
r1.getAstricts().add(a2);
r1.getAstricts().add(a3);
//军师 -- 带兵,封侯
r2.getAstricts().add(a1);
r2.getAstricts().add(a2);
//大将 -- 带兵
r3.getAstricts().add(a1);
//2.在建立权限的
//带兵 -- 主公,军事,大将
a1.getRoles().add(r1);
a1.getRoles().add(r2);
a1.getRoles().add(r3);
//献计 -- 主公,军事
a2.getRoles().add(r1);
a2.getRoles().add(r2);
//封侯 -- 主公
a3.getRoles().add(r1);
s.update(r1);
s.update(r2);
s.update(r3);
s.save(a1);
s.save(a2);
s.save(a3);
tx.commit();
}
/**
* 多对多全部查询
* 同过获取属性的方法,直接查询p1.getRole().getAstricts()
*/
@Test
public void test02(){
Session s = HibernateUtils.getCurrnetSession();
Transaction tx = s.beginTransaction();
Query query=s.createQuery("from Person ");
List<Person> list = query.list();
for (Person person : list) {
System.out.println("姓名:"+person.getpName()+",角色:"+person.getRole().getrName());
Set<Astrict> set= person.getRole().getAstricts();
for (Astrict astrict : set) {
System.out.println(astrict.getaName());
}
}
tx.commit();
}
/**
* 多对多条件查询
* 同过获取属性的方法,直接查询p1.getRole().getAstricts()
*/
@Test
public void test03(){
Session s = HibernateUtils.getCurrnetSession();
Transaction tx = s.beginTransaction();
Person p1 = (Person)s.get(Person.class, 1);
System.out.println("姓名:"+p1.getpName()+",角色:"+p1.getRole().getrName());
Set<Astrict> set= p1.getRole().getAstricts();
for (Astrict astrict : set) {
System.out.println(astrict.getaName());
}
tx.commit();
}
}