表之间关系

1. 一对多

  • 一个部门有多个员工,一个员工只能属于某一个部门
  • 一个班级有多个学生,一个学生只能属于一个班级

2. 多对多

  • 一个老师教多个学生,一个学生可以被多个老师教
  • 一个学生可以先择多门课程,一门课程可以被多个学生选择

3. 一对一

  • 一个公司只能对应一个注册地址

表之间关系建表原则

1. 一对多

在多的一方创建一个外键,指向一的一方的主键

2. 多对多

创建一个中间表,中间表至少有两个字段,分别作为外键指向多对多双方的主键

3. 一对一

唯一外键对应

主键对应

一对多关系配置

一、 建立表

1. 客户

  • 一个客户可以有多个联系人
CREATE TABLE `customer` (
`cust_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)',
`cust_name` varchar(32) NOT NULL COMMENT '客户名称(公司名称)',
`cust_source` varchar(32) DEFAULT NULL COMMENT '客户信息来源',
`cust_industry` varchar(32) DEFAULT NULL COMMENT '客户所属行业',
`cust_level` varchar(32) DEFAULT NULL COMMENT '客户级别',
`cust_phone` varchar(64) DEFAULT NULL COMMENT '固定电话',
`cust_mobile` varchar(16) DEFAULT NULL COMMENT '移动电话',
PRIMARY KEY (`cust_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

2. 销售联系人

  • 一个联系人只能属于某一个客户
CREATE TABLE `linkman` (
`link_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '联系人编号(主键)',
`link_name` varchar(16) DEFAULT NULL COMMENT '联系人姓名',
`link_gender` char(1) DEFAULT NULL COMMENT '联系人性别',
`link_phone` varchar(16) DEFAULT NULL COMMENT '联系人办公电话',
`link_mobile` varchar(16) DEFAULT NULL COMMENT '联系人手机',
`link_email` varchar(64) DEFAULT NULL COMMENT '联系人邮箱',
`link_qq` varchar(16) DEFAULT NULL COMMENT '联系人qq',
`link_position` varchar(16) DEFAULT NULL COMMENT '联系人职位',
`link_memo` varchar(512) DEFAULT NULL COMMENT '联系人备注',
`link_cust_id` bigint(32) NOT NULL COMMENT '客户id',
PRIMARY KEY (`link_id`),
KEY `FK_cst_lkm` (`link_cust_id`),
CONSTRAINT `FK_cst_lkm` FOREIGN KEY (`link_cust_id`) REFERENCES `customer` (`cust_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

关系图

二、建立ORM

1.实体类与数据库中字段进行建立

客户实体类
@Getter@Setter
public class Customer {
private Long cust_id;
private String cust_name;
private String cust_source;
private String cust_industry;
private String cust_level;
private String cust_phone;
private String cust_mobile;
}
销售实体类
@Getter@Setter
public class Linkman {
private Long link_id;
private String link_name;
private String link_gender;
private String link_phone;
private String link_mobile;
private String link_email;
private String link_qq;
private String link_position;
private String link_memo;
private String link_cust_id;
}

2.设置两表之间的关系

  • 一个客户可以有多个联系人
@Getter@Setter
public class Customer {
private Long cust_id;
private String cust_name;
private String cust_source;
private String cust_industry;
private String cust_level;
private String cust_phone;
private String cust_mobile; // 一个客户可以有多个联系人
private Set<Linkman> linkmens = new HashSet<>(); @Override
public String toString() {
return "Customer{" + "cust_id=" + cust_id + ", cust_name='" + cust_name + '\'' + ", cust_source='" + cust_source
+ '\'' + ", cust_industry='" + cust_industry + '\'' + ", cust_level='" + cust_level + '\''
+ ", cust_phone='" + cust_phone + '\'' + ", cust_mobile='" + cust_mobile + '\'' + '}';
}
}
  • 一个联系人只能属于某一个客户
@Getter@Setter
public class Linkman {
private Long link_id;
private String link_name;
private String link_gender;
private String link_phone;
private String link_mobile;
private String link_email;
private String link_qq;
private String link_position;
private String link_memo;
private String link_cust_id;
// 一个联系人只对应一个客户
private Customer customer; @Override
public String toString() {
return "Linkman{" + "link_id=" + link_id + ", link_name='" + link_name + '\'' + ", link_gender='" + link_gender
+ '\'' + ", link_phone='" + link_phone + '\'' + ", link_mobile='" + link_mobile + '\''
+ ", link_email='" + link_email + '\'' + ", link_qq='" + link_qq + '\'' + ", link_position='"
+ link_position + '\'' + ", link_memo='" + link_memo + '\'' + ", link_cust_id='" + link_cust_id + '\''
+ ", customer=" + customer + '}';
}
}

三、添加配置文件

1.客户(Customer)实体类的配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping>
<class name="com.xzh.hibernate.domain.Customer" table="customer">
<!--建立类属性哪一个是主键 还要跟数据库当中主键进行对象 -->
<id name="cust_id" column="cust_id">
<generator class="native" />
</id>
<!--建立类中的普通属性与数据库当中字段进行关联 -->
<property name="cust_name" column="cust_name" />
<property name="cust_source" column="cust_source" />
<property name="cust_industry" column="cust_industry" />
<property name="cust_level" column="cust_level" />
<property name="cust_phone" column="cust_phone" />
<property name="cust_mobile" column="cust_mobile" /> <!--一对多 -->
<set name="linkmens" cascade="save-update,delete" inverse="true"><!--set属性名称 -->
<key column="link_cust_id"></key><!--外键 -->
<one-to-many class="com.xzh.hibernate.domain.Linkman"></one-to-many>
</set> </class>
</hibernate-mapping>

2.联系人(LinkMan)实体类配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping>
<class name="com.xzh.hibernate.domain.Linkman" table="linkman">
<!--建立类属性哪一个是主键 还要跟数据库当中主键进行对象 -->
<id name="link_id" column="link_id">
<generator class="native" />
</id>
<!--建立类中的普通属性与数据库当中字段进行关联 -->
<property name="link_name" column="link_name" />
<property name="link_gender" column="link_gender" />
<property name="link_phone" column="link_phone" />
<property name="link_mobile" column="link_mobile" />
<property name="link_email" column="link_email" />
<property name="link_qq" column=" link_qq" />
<property name="link_position" column=" link_position" />
<property name="link_memo" column=" link_memo" /> <many-to-one name="customer" cascade="save-update"
class="com.xzh.hibernate.domain.Customer" column="link_cust_id" />
</class>
</hibernate-mapping>

四、添加核心配置文件

<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration>
<session-factory>
<!-- 连接数据库的基本参数 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3307/hibernate</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">abcd</property>
<!-- 配置Hibernate的方言 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!-- 打印SQL -->
<property name="hibernate.show_sql">true</property>
<!-- 格式化SQL -->
<property name="hibernate.format_sql">true</property>
<!-- 自动创建表 -->
<property name="hibernate.hbm2ddl.auto">update</property> <!-- C3P0 -->
<property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<!--在连接池中可用的数据库连接的最少数目 -->
<property name="c3p0.min_size">5</property>
<!--在连接池中所有数据库连接的最大数目 -->
<property name="c3p0.max_size">20</property>
<!--设定数据库连接的过期时间,以秒为单位, 如果连接池中的某个数据库连接处于空闲状态的时间超过了timeout时间,就会从连接池中清除 -->
<property name="c3p0.timeout">120</property>
<!--每3000秒检查所有连接池中的空闲连接 以秒为单位 -->
<property name="c3p0.idle_test_period">3000</property> <!--设置事务的隔离级别-->
<property name="hibernate.connection.isolation">4</property>
<!--创建一个session绑定到当前线程-->
<property name="current_session_context_class">thread</property> <!--加载映射文件 -->
<mapping resource="com/xzh/hibernate/domain/customer.hbm.xml" />
<mapping resource="com/xzh/hibernate/domain/linkman.hbm.xml" />
</session-factory>
</hibernate-configuration>

五、引入工具类

public class HibernateUtil {
public static final SessionFactory sessionFactory;
static {
//1.加载配置文件
Configuration configure = new Configuration().configure();
//2.创建sessionFactory --JDBC 连接池
sessionFactory = configure.buildSessionFactory();
}
public static Session openSession(){
Session session = sessionFactory.openSession();
return session;
}
public static Session getCurrentSession(){
Session session = sessionFactory.getCurrentSession();
return session;
} }

六、编写测试类

@Test
public void add(){
Session currentSession = HibernateUtil.getCurrentSession();
Transaction transaction = currentSession.beginTransaction(); Customer customer1 = new Customer();
customer1.setCust_name("customer1");
Customer customer2 = new Customer();
customer2.setCust_name("customer2");
Customer customer3 = new Customer();
customer3.setCust_name("customer3"); Linkman linkman1 = new Linkman();
linkman1.setLink_name("linkman1");
Linkman linkman2 = new Linkman();
linkman2.setLink_name("linkman2");
Linkman linkman3 = new Linkman();
linkman3.setLink_name("linkman3"); /* 配置关系 双向维护*/
customer1.getLinkmens().add(linkman1);
customer1.getLinkmens().add(linkman2);
customer2.getLinkmens().add(linkman3); linkman1.setCustomer(customer1);
linkman2.setCustomer(customer1);
linkman3.setCustomer(customer2); /* 保存数据 */
currentSession.save(customer1);
currentSession.save(customer2);
currentSession.save(customer3); currentSession.save(linkman1);
currentSession.save(linkman2);
currentSession.save(linkman3); transaction.commit(); }

懒加载:

在 linkman.hbm.xml 中修改

<many-to-one name="customer" cascade="save-update"
class="com.xzh.hibernate.domain.Customer" column="link_cust_id" lazy="false"/>

@Test
public void get(){
Session currentSession = HibernateUtil.getCurrentSession();
Transaction transaction = currentSession.beginTransaction();
Linkman linkman = currentSession.get(Linkman.class, 3L);
transaction.commit();
System.out.println(linkman.getLink_name());
System.out.println(linkman.getCustomer().getCust_name());
}
@Test
public void delete(){
Session currentSession = HibernateUtil.getCurrentSession();
Transaction transaction = currentSession.beginTransaction();
//删除 默认
//打断两个表之间关系 ,再去删除记录 并没有级联去删除操作
Customer customer = currentSession.get(Customer.class, 1L);
currentSession.delete(customer);
transaction.commit();
}
@Test
public void update() {
Session currentSession = HibernateUtil.getCurrentSession();
Transaction transaction = currentSession.beginTransaction();
// 更新
Linkman linkman1 = currentSession.get(Linkman.class, 1L);
Customer customer2 = currentSession.get(Customer.class, 2L);
// 关联
// 单向维护
customer2.getLinkmens().add(linkman1);
// linkman1.setCustomer(customer2); // 双向维护 让一方放弃外键维护权
// inverse="true" true 放弃外键维护权; false 不放弃外键维护权
customer2.getLinkmens().add(linkman1);
linkman1.setCustomer(customer2);
transaction.commit();
}

级联操作

问题: 在两张表建立一对多关系时,如果只保存一边的对象,就会发异常

示例

一、什么是级联

在操作一个对象的时候,是否会操作其关联的对象。

二、级联分类

  • 级联保存或更新
  • 级联删除

三、级联是有方向性

  • 在操作一的一方,是否会操作多的一方
  • 操作多的一方时, 是否会操作一的一方

四、级联保存或更新

1. 级联保存和级联更新

  • 操作的主体是谁,就要在谁的映射配置文件当中进行配置
  • 在开始配置的set当中添加一个新的属性 cascade="save-update"

  • 再去运行,就不会报异常,两条记录都会被添加
  • 在一的一方添加级联

2. 对象导航

  • 两方如果都加了级联,这种我们也称为双向导航
  • 设置双向导航时,当对象存在关系时, 就会做出对应的操作

五、级联删除

  • 删除一边数据时,同时将另一边的数据一并删除

1. 不设置级联删除。

默认:先打断表之间的关系,把外键改为空,然后再删除记录。

2.设置级联删除

示例代码

六、双向级联

在双向级联的过程当中,会产生一些多余的sql语句

原因:当双向维护时,两都都维护了外键,当做更新操作时, 两边的外键都要去修改

解决办法:

1.使用单向维护

有些地方还是会有问题

2.一方放弃维护权

  • 在一的一方放弃外键维护权
  • 在配置文件当中添加一个inverse="false/true"
  • true为放弃外键维护权,false为不放弃外键维护权

3. cascade与inverse

  • cascade控制有没有关联对象
  • inverse控制有没有外键

多对多关系配置

一、建立表

1. 用户表

  • 一个用户可以有多个角色
CREATE TABLE `user` (
`user_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '用户id',
`user_code` varchar(32) DEFAULT NULL COMMENT '用户账号',
`user_name` varchar(64) NOT NULL COMMENT '用户名称',
`user_password` varchar(32) DEFAULT NULL COMMENT '用户密码',
`user_state` char(1) DEFAULT NULL COMMENT '1:正常,0:暂停',
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

2. 角色表

  • 一个角色可以被多个用户选择
CREATE TABLE `role` (
`role_id` bigint(32) NOT NULL AUTO_INCREMENT,
`role_name` varchar(32) NOT NULL COMMENT '角色名称',
`role_memo` varchar(128) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`role_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

3. 中间表

CREATE TABLE `user_role` (
`role_id` bigint(32) NOT NULL,
`user_id` bigint(32) NOT NULL,
PRIMARY KEY (`role_id`,`user_id`),
KEY `FK_user_id` (`user_id`),
CONSTRAINT `FK_role_id` FOREIGN KEY (`role_id`) REFERENCES `role` (`role_id`),
CONSTRAINT `FK_user_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

关系图

二、建立ORM

1. 用户

@Setter@Getter
public class User {
private Long user_id;
private String user_code;
private String user_name;
private String user_password;
private String user_state;
// 一个用户选择多个角色
private Set<Role> roles = new HashSet<Role>(); @Override
public String toString() {
return "User{" + "user_id=" + user_id + ", user_code='" + user_code + '\'' + ", user_name='" + user_name + '\''
+ ", user_password='" + user_password + '\'' + ", user_state='" + user_state + '\'' + ", roles=" + roles
+ '}';
}
}

2. 角色

@Setter@Getter
public class Role {
private Long role_id;
private String role_name;
private String role_memo;
// 角色下面的所有用户
private Set<User> users = new HashSet<User>(); @Override
public String toString() {
return "Role{" + "role_id=" + role_id + ", role_name='" + role_name + '\'' + ", role_memo='" + role_memo + '\''
+ '}';
}
}

三、添加配置文件

1. 用户

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping>
<class name="com.xzh.hibernate.domain.User" table="user" >
<!--建立类属性哪一个是主键 还要跟数据库当中主键进行对象-->
<id name="user_id" column="user_id" >
<generator class="native"/>
</id>
<!--建立类中的普通属性与数据库当中字段进行关联-->
<property name="user_code" column="user_code" />
<property name="user_name" column="user_name" />
<property name="user_password" column="user_password" />
<property name="user_state" column="user_state" /> <!--多对多关系
name:当前集合属性名称
table: 多对多中间表 表名
<key column=""></key> :当前表的外键
<many-to-many class="" column=""/>
class:集合中对象的全路径
column:集合中对象的外键
-->
<set name="roles" table="user_role" cascade="save-update" lazy="true">
<key column="user_id"></key>
<many-to-many class="com.xzh.hibernate.domain.Role" column="role_id"/>
</set>
</class>
</hibernate-mapping>

2. 角色

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping>
<class name="com.xzh.hibernate.domain.Role" table="role" >
<!--建立类属性哪一个是主键 还要跟数据库当中主键进行对象-->
<id name="role_id" column="role_id" >
<generator class="native"/>
</id>
<!--建立类中的普通属性与数据库当中字段进行关联-->
<property name="role_name" column="role_name" />
<property name="role_memo" column="role_memo" /> <!--多对多关系
name:当前集合属性名称
table: 多对多中间表 表名
<key column=""></key> :当前表的外键
<many-to-many class="" column=""/>
class:集合中对象的全路径
column:集合中对象的外键
-->
<set name="users" table="user_role" inverse="true">
<key column="role_id"></key>
<many-to-many class="com.xzh.hibernate.domain.User" column="user_id"/>
</set>
</class>
</hibernate-mapping>

四、在核心配置文件当中添加两个新配置

五、编写测试类

双向维护

  • 双向维护时,必须要有一方放弃外键维护
  • 如果两边都有维护的话, 就会有重复的的记录,由于关系表是两个字段作为共同主键,不能有相同的记录
  • 解决办法:通常都是让被动方放弃,用户选角色,角色为被动方

    ·
@Test
public void add() {
Session currentSession = HibernateUtil.getCurrentSession();
Transaction transaction = currentSession.beginTransaction();
// 创建用户
User user1 = new User();
user1.setUser_name("user1");
User user2 = new User();
user2.setUser_name("user2"); // 创建角色
Role role1 = new Role();
role1.setRole_name("role1");
Role role2 = new Role();
role2.setRole_name("role2");
Role role3 = new Role();
role3.setRole_name("role3"); // 配置关系 单向维护
user1.getRoles().add(role1);
user1.getRoles().add(role2);
user2.getRoles().add(role2);
user2.getRoles().add(role3); // 双向维护 必须得要有一方放弃外键维护权 inverse="true"
// 被动(被选择)的一方放权 如果没有放弃 会报异常 主键重复
role1.getUsers().add(user1);
role2.getUsers().add(user1);
role2.getUsers().add(user2);
role3.getUsers().add(user2); // 保存
currentSession.save(user1);
currentSession.save(user2);
// cascade="save-update"
// currentSession.save(role1);
// currentSession.save(role2);
// currentSession.save(role3); transaction.commit();
} @Test
public void test2(){
//关系操作 操作内部集合
Session currentSession = HibernateUtil.getCurrentSession();
Transaction transaction = currentSession.beginTransaction();
//用户1 添加一个新的角色3
User user1 = currentSession.get(User.class, 3L);
Role role3 = currentSession.get(Role.class, 6L);
user1.getRoles().add(role3);
role3.getUsers().add(user1); transaction.commit();
} @Test
public void test3(){
Session currentSession = HibernateUtil.getCurrentSession();
Transaction transaction = currentSession.beginTransaction(); //把用户2的角色3 修改成角色1
User user2 = currentSession.get(User.class, 2L);
Role role3 = currentSession.get(Role.class, 3L);
Role role1 = currentSession.get(Role.class, 1L); user2.getRoles().remove(role3);
user2.getRoles().add(role1);
transaction.commit();
}

最新文章

  1. JAVA常用时间操作类
  2. Linux ubuntu 10.10安装OpenCv
  3. BugTracker.NET的配置
  4. SKEffectNode类
  5. UML-类图,包图
  6. 使用LabVIEWPC的制备
  7. android打成apk
  8. 周一04.3流程控制while循环
  9. windows系统下Disconf web安装-分布式配置管理平台
  10. 【PMP】项目风险管理~重点知识
  11. centos 7 搭建openvpn-2.4.6
  12. Codeforces.838D.Airplane Arrangements(思路)
  13. 算法笔记_226:填符号凑算式(Java)
  14. MongoDB(课时10 数组)
  15. SurfaceFlinger 讲解
  16. mina2中IoHandler
  17. TCPIP协议编程:基于UDP协议的局域网聊天工具的研发
  18. js中的日期
  19. 【mysql】【转发】my.cnf 讲解
  20. RS232

热门文章

  1. JavaScript内置一些方法的实现原理--new关键字,call/apply/bind方法--前戏
  2. 读取普通java web项目下的WEB-INF目录下的配置文件(application.xml,xx.properties等配置文件)
  3. [iOS]UIButton内、外边距设置
  4. 阿里面试官总结40 个 Java 多线程问题
  5. FDD-LTE上下行带宽一样的,为什么上下行流量差别这么大
  6. Linux命令——column
  7. roles
  8. c++第五次博客作业
  9. shell 文本替换 ---出现--- sed:-e 表达式 #1,字符 8:“s”的未知选项
  10. Android测试-monkey