Hiberante第三天(Hibernate的关联关系映射(一对多,多对多))


1.1 多表关系分析和创建

1.1.1 表关系分析和创建

1.2 Hibernate中的一对多关系映射

1.2.1 Hibernate的一对多环境搭建

1.2.2 创建表和实体

l 创建表

CREATE TABLE `cst_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;

 

CREATE TABLE `cst_linkman` (

  `lkm_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '联系人编号(主键)',

  `lkm_name` varchar(16) DEFAULT NULL COMMENT '联系人姓名',

  `lkm_cust_id` bigint(32) NOT NULL COMMENT '客户id',

  `lkm_gender` char(1) DEFAULT NULL COMMENT '联系人性别',

  `lkm_phone` varchar(16) DEFAULT NULL COMMENT '联系人办公电话',

  `lkm_mobile` varchar(16) DEFAULT NULL COMMENT '联系人手机',

  `lkm_email` varchar(64) DEFAULT NULL COMMENT '联系人邮箱',

  `lkm_qq` varchar(16) DEFAULT NULL COMMENT '联系人qq',

  `lkm_position` varchar(16) DEFAULT NULL COMMENT '联系人职位',

  `lkm_memo` varchar(512) DEFAULT NULL COMMENT '联系人备注',

  PRIMARY KEY (`lkm_id`),

  KEY `FK_cst_linkman_lkm_cust_id` (`lkm_cust_id`),

  CONSTRAINT `FK_cst_linkman_lkm_cust_id` FOREIGN KEY (`lkm_cust_id`) REFERENCES `cst_customer` (`cust_id`) ON DELETE NO ACTION ON UPDATE NO ACTION

) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

l 创建实体

客户端(一的一方)

联系人端(多的一方)

1.2.3 创建映射文件

创建Customer.hbm.xml

<?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.itheima.hibernate.domain.Customer" table="cst_customer">

<!-- 建立oid与主键映射 -->

<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属性:多的一方集合的属性名称

 -->

<set name="linkMans">

<!--

配置key标签 :

* column属性:多的一方的外键的名称

-->

<key column="lkm_cust_id"/>

<!--

one-to-many

* class属性:多的一方的类的全路径

 -->

 <one-to-many class="com.itheima.hibernate.domain.LinkMan"/>

</set>

</class>

</hibernate-mapping>

创建LinkMan.hbm.xml

<?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.itheima.hibernate.domain.LinkMan" table="cst_linkman">

<!-- 建立oid与主键映射 -->

<id name="lkm_id" column="lkm_id">

<generator class="native"/>

</id>

<!-- 建立普通属性与表字段的映射 -->

<property name="lkm_name" column="lkm_name"/>

<property name="lkm_gender" column="lkm_gender"/>

<property name="lkm_phone" column="lkm_phone"/>

<property name="lkm_mobile" column="lkm_mobile"/>

<property name="lkm_email" column="lkm_email"/>

<property name="lkm_qq" column="lkm_qq"/>

<property name="lkm_position" column="lkm_position"/>

<property name="lkm_memo" column="lkm_memo"/>

<!-- 建立与客户的映射关系 -->

<!--

many-to-one标签:

* name:一的一方的对象的属性名称。

* class:一的一方的类的全路径

* column :表的外键的名称

 -->

<many-to-one name="customer" class="com.itheima.hibernate.domain.Customer" column="lkm_cust_id"/>

</class>

</hibernate-mapping>

1.2.4 编写代码

@Test

/**

 * 保存客户,同时保存客户关联联系人

 * 必须同时保存两边对象,不能只保存一边,会出现异常

 */

public void demo1(){

Session session = HibernateUtils.getCurrentSession();

Transaction transaction = session.beginTransaction();

// 创建一个客户 和两个联系人

Customer customer = new Customer();

customer.setCust_name("郝宝强");

LinkMan linkMan1 = new LinkMan();

linkMan1.setLkm_name("宋喆");

LinkMan linkMan2 = new LinkMan();

linkMan2.setLkm_name("马蓉");

customer.getLinkMans().add(linkMan1);

customer.getLinkMans().add(linkMan2);

linkMan1.setCustomer(customer);

linkMan2.setCustomer(customer);

session.save(customer);

session.save(linkMan1);

session.save(linkMan2);

transaction.commit();

}

 

1.2.5 双向维护产生多余SQL

@Test

/**

 * 双向维护产生多余的SQL

 */

public void demo7(){

Session session = HibernateUtils.getCurrentSession();

Transaction transaction = session.beginTransaction();

// 查询2号客户

Customer customer = session.get(Customer.class, 2l);

// 查询2号联系人

LinkMan linkMan = session.get(LinkMan.class, 2l);

customer.getLinkMans().add(linkMan);

linkMan.setCustomer(customer);

transaction.commit();

}

l 解决这个问题:将一的一方的外键维护权放弃掉:

1.2.6 一对多的级联保存操作

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

级联操作是有方向性:

l 保存客户级联保存联系人

@Test

/**

 * 级联保存操作:

 * * 保存客户级联保存联系人

 *  Customer.hbm.xml<set>上配置cascade="save-update"

 */

public void demo2(){

Session session = HibernateUtils.getCurrentSession();

Transaction transaction = session.beginTransaction();

// 创建一个客户 和两个联系人

Customer customer = new Customer();

customer.setCust_name("郝宝强");

LinkMan linkMan1 = new LinkMan();

linkMan1.setLkm_name("宋喆");

customer.getLinkMans().add(linkMan1);

linkMan1.setCustomer(customer);

session.save(customer);

// session.save(linkMan1);

transaction.commit();

}

l 保存联系人级联保存客户

@Test

/**

 * 级联保存操作:

 * * 保存联系人级联保存客户在LinkMan.hbm.xml<many-to-one>上配置cascade="save-update"

 */

public void demo3(){

Session session = HibernateUtils.getCurrentSession();

Transaction transaction = session.beginTransaction();

// 创建一个客户 和两个联系人

Customer customer = new Customer();

customer.setCust_name("郝强勇");

LinkMan linkMan1 = new LinkMan();

linkMan1.setLkm_name("马蓉");

customer.getLinkMans().add(linkMan1);

linkMan1.setCustomer(customer);

//session.save(customer);

session.save(linkMan1);

transaction.commit();

}

1.2.7 测试级联和对象导航(关联关系)的关系

@Test

/**

 * 测试导航和级联关系

 * 前提:双方都配置cascade="save-update"

      * 联系人1关联客户   客户关联联系人23

 */

public void demo6(){

Session session = HibernateUtils.getCurrentSession();

Transaction transaction = session.beginTransaction();

// 创建一个客户

Customer customer = new Customer();

customer.setCust_name("郝宝强");

// 创建三个联系人

LinkMan linkMan1 = new LinkMan();

linkMan1.setLkm_name("宋喆");

LinkMan linkMan2= new LinkMan();

linkMan2.setLkm_name("马蓉");

LinkMan linkMan3 = new LinkMan();

linkMan3.setLkm_name("郝如花");

linkMan1.setCustomer(customer);

customer.getLinkMans().add(linkMan2);

customer.getLinkMans().add(linkMan3);

// session.save(linkMan1); // 问发送几条insert语句? 4

// session.save(customer); // 问发送几条insert语句? 3

session.save(linkMan2); // 问发送几条insert语句? 1

transaction.commit();

}

 

1.2.8 一对多的级联删除操作

删除客户级联删除联系人

@Test

/**

 * 级联删除操作:

 * * 删除客户级联删除联系人

 * Customer.hbm.xml<set>上配置cascade="delete"

 */

public void demo4(){

Session session = HibernateUtils.getCurrentSession();

Transaction transaction = session.beginTransaction();

Customer customer = session.get(Customer.class, 1l);

session.delete(customer);

transaction.commit();

}

l 删除联系人级联删除客户(很少用)

@Test

/**

 * 级联删除操作:

 * * 删除联系人级联删除客户

 * LinkMan.hbm.xml<many-to-one>上配置cascade="delete"

 */

public void demo5(){

Session session = HibernateUtils.getCurrentSession();

Transaction transaction = session.beginTransaction();

LinkMan linkMan = session.get(LinkMan.class, 1l);

session.delete(linkMan);

transaction.commit();

}

1.3 Hibernate中的多对多关系映射

1.3.1 搭建多对多开发环境

1.3.2 创建表

CREATE TABLE `sys_user` (

  `user_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '用户id',

  `user_code` varchar(32) NOT NULL COMMENT '用户账号',

  `user_name` varchar(64) NOT NULL COMMENT '用户名称',

  `user_password` varchar(32) NOT NULL COMMENT '用户密码',

  `user_state` char(1) NOT NULL COMMENT '1:正常,0:暂停',

  PRIMARY KEY (`user_id`)

) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

 

CREATE TABLE `sys_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=6 DEFAULT CHARSET=utf8;

 

CREATE TABLE `sys_user_role` (

  `role_id` bigint(32) NOT NULL COMMENT '角色id',

  `user_id` bigint(32) NOT NULL COMMENT '用户id',

  PRIMARY KEY (`role_id`,`user_id`),

  KEY `FK_user_role_user_id` (`user_id`),

  CONSTRAINT `FK_user_role_role_id` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`role_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,

  CONSTRAINT `FK_user_role_user_id` FOREIGN KEY (`user_id`) REFERENCES `sys_user` (`user_id`) ON DELETE NO ACTION ON UPDATE NO ACTION

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

1.3.3 创建实体

用户端

角色端

1.3.4 创建映射

l 用户端

<?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.itheima.hibernate.domain.User" table="sys_user">

<!-- 建立oid与表的主键映射 -->

<id name="user_id" column="user_id">

<generator class="native"/>

</id>

<!-- 建立属性与表字段映射 -->

<property name="user_code"/>

<property name="user_name"/>

<property name="user_password"/>

<property name="user_state"/>

<!-- 建立用户与角色的映射关系 -->

<!--

set标签:

name属性:角色集合属性名称

table属性:中间表的名称

 -->

<set name="roles" table="sys_user_role">

<!-- 用户端的在中间表的外键的名称 -->

<key column="user_id"/>

<!--

配置多对多映射

many-to-many标签

* class:另一端的实体类的全路径

* column:另一端在中间表外键的名称

-->

<many-to-many class="com.itheima.hibernate.domain.Role" column="role_id"/>

</set>

</class>

</hibernate-mapping>

l 角色端

<?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.itheima.hibernate.domain.Role" table="sys_role">

<!-- 建立oid与表的主键映射 -->

<id name="role_id" column="role_id">

<generator class="native"/>

</id>

<!-- 建立属性与表字段映射 -->

<property name="role_name"/>

<property name="role_memo"/>

<!-- 建立关联关系映射 -->

<set name="users" table="sys_user_role">

<key column="role_id"/>

<many-to-many class="com.itheima.hibernate.domain.User" column="user_id"/>

</set>

</class>

</hibernate-mapping>

1.3.5 编写保存代码

@Test

/**

 * 保存数据

 */

public void demo1(){

Session session = HibernateUtils.getCurrentSession();

Transaction transaction = session.beginTransaction();

User user1 = new User();

user1.setUser_name("小王");

User user2 = new User();

user2.setUser_name("小勇");

Role role1 = new Role();

role1.setRole_name("Java教研部");

Role role2 = new Role();

role2.setRole_name("前台");

Role role3 = new Role();

role3.setRole_name("学工部");

user1.getRoles().add(role1);// 1 1

user1.getRoles().add(role3);

user2.getRoles().add(role3);

role1.getUsers().add(user1);// 1 1

role3.getUsers().add(user1);

role3.getUsers().add(user2);

session.save(user1);

session.save(user2);

session.save(role1);

session.save(role2);

session.save(role3);

transaction.commit();

}

1.3.6 级联保存操作(基本不会用)

l 保存用户级联保存角色

l 保存角色级联保存用户

1.3.7 级联删除操作(不会用-避免去使用) 用的默认删除

l 删除用户级联删除角色

l 删除角色级联删除用户

1.3.8 多对多其他相关操作(掌握)

l 给用户选择角色

@Test

/**

 * 1号用户选择1号和2号角色

 */

public void demo6(){

Session session = HibernateUtils.getCurrentSession();

Transaction transaction = session.beginTransaction();

User user = session.get(User.class, 1l);

Role role1 = session.get(Role.class, 1l);

Role role2 = session.get(Role.class, 2l);

user.getRoles().add(role1);

user.getRoles().add(role2);

transaction.commit();

}

l 给用户删除角色

@Test

/**

 * 1号删除2号角色

 */

public void demo7(){

Session session = HibernateUtils.getCurrentSession();

Transaction transaction = session.beginTransaction();

User user = session.get(User.class, 1l);

Role role = session.get(Role.class, 2l);

user.getRoles().remove(role);

transaction.commit();

}

l 给用户改选角色

@Test

/**

 * 1号用户的1号角色修改为2号角色

 */

public void demo8(){

Session session = HibernateUtils.getCurrentSession();

Transaction transaction = session.beginTransaction();

User user = session.get(User.class, 1l);

Role role1 = session.get(Role.class, 1l);

Role role2 = session.get(Role.class, 2l);

user.getRoles().remove(role1);

user.getRoles().add(role2);

transaction.commit();

}

 

------------------------------------------------------------------------------------------------------------------------------------------

 

对象导航查询(多表关系查询)

有一个客户,获取他的联系人个数

Customer c1 = session.get(Customer.class,1L);

syso(c1.getLinkmas().size())

有一个联系人,获取他所属客户名称

Linkman l1 = session.get(Linkman.class,1L);

syso(l1.getCustomer().getCust_name());

 

 

延迟加载

提高hibernate效率,决定发送sql的时机.

分类:

类级别的延迟加载 (单表数据查询)

      Load

 

关联级别的延迟加载(多个对象的数据查询-多表数据查询)

通过一个对象查询其关联对象的数据

 

 

 

set标签上有一个属性 lazy 用来配置关联级别是否延迟加载的

常用的值:

true:使用延迟加载 默认值

false:不使用延迟加载

查询客户的同时,立马发送sql查询联系人

many-to-one标签上也有一个属性 lazy  用来配置是否延迟加载的

常用的值:

false:不使用延迟加载 (记住)

查询联系人的时候,立马发送sql查询客户

总之(按需求):

根据一的一方查多的一方的时候,使用延迟加载(默认值)

根据多的一方查一的一方一般使用立即加载,所以需要在多的一方的many-to-one标签上配置 lazy=false

猜你喜欢

转载自blog.csdn.net/wuqianjing/article/details/80885956