Hiberante框架学习(一)

项目中框架的体系结构

 ORM框架

对象关系映射(英语:(Object Relational Mapping,简称ORM,或O/RM,或O/R mapping)

对象和表字段进行对应

是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。

Object:对象,java对象,此处特指JavaBean,Model

Relational:关系,二维表,数据库中的表。

Mapping:映射

什么是hibernate

Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装

DBUtils也是对JDBC的封装

它将POJO与数据库表建立映射关系,是一个全自动的orm框架

POJO(Plain Ordinary Java Object)简单的Java对象,实际就是普通JavaBeans

hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库

Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用

 

Hibernate是一个数据持久化层的ORM框架,它的主要功能就是把对象映射到表中,操作API,只需要将一个对象存储到数据库,不需要写sql语句

Hibernate提供了对关系型数据库增删改成操作

主流的ORM框架

JPA Java Persistence API.JPA通过JDK 5.0注解或XML描述对象关系表的映射关系(只有接口规范)

Hibernate 最流行ORM框架,通过对象-关系映射配置,可以完全脱离底层SQL

MyBatis  本是apache的一个开源项目 iBatis,支持普通 SQL查询,存储过程和高级映射的优秀持久层框架

Apache DBUtils 、Spring JDBCTemplate

Hibernate的优点

Hibernate对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码

Hibernate是一个基于jdbc的主流持久化框架,是一个优秀的orm实现,它很大程度的简化了dao层编码工作  session.save(User);

Hibernate使用java的反射机制

Hibernate的性能非常好,因为它是一个轻量级框架。映射的灵活性很出色。它支持很多关系型数据库,有一对一到多对多的各种复杂关系映射

Hibernate的使用步骤

下载hibernate 的jar包,并导入到项目中(http://hibernate.org/orm/)

创建数据库和表

配置核心配置文件hibernate.cfg.xml【这个文件有连接数据库的配置】

编写映射文件hibernate mapping(*.hbm.xml),【声明对象如何关联数据库表字段】

调用hibernate的api

入门案例

创建一个项目,引入jar包

 

创建表

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;

创建实体类

创建映射

映射需要通过XML的配置文件来完成,这个配置文件可以任意命名。尽量统一命名规范(类名.hbm.xml)

 创建一个Hibernate的核心配置文件

Hibernate的核心配置文件的名称:hibernate.cfg.xml

 编写测试代码

 XML提示的配置

配置XML提示问题

 

映射的配置

【class标签的配置】

标签用来建立类与表的映射关系

属性:

        name 类的全路径

        table 表名(类名与表名一致,table可以省略)

        catalog 数据库名

        class标签的dynamic-insert="true" 是否动态生成插入语句

 

【id标签的配置】

标签用来建立类中的属性与表中的主键的对应关系

属性:

        name 类中的属性名

        column 表中的字段名(类中的属性名和表中的字段名如果一致,column可以省略)

        length 长度

        type 类型

【property标签的配置】

属性:

        name 类中的属性名

        column 表中的字段名(类中的属性名和表中的字段名如果一致,column可以省略)

        length 长度

        type 类型

        not-null 设置非空

        unique 设置唯一 

 Hibernate的核心配置方式

一种方式:属性文件的方式

       hibernate.properties

           hibernate.connection.driver_class=com.mysql.jdbc.Driver

           …

           hibernate.show_sql=true

      属性文件的方式不能引入映射文件(手动编写代码加载映射文件)

二种方式:XML文件的方式

hibernate.cfg.xml

核心的配置

必须的配置

       连接数据库的基本的参数

       驱动类 hibernate.connection.driver_class

       url路径 hibernate.connection.url

      用户名 hibernate.connection.username

      密码 hibernate.connection.password

可选的配置

       显示SQL  hibernate.show_sq

       格式化SQL hibernate.format_sql 

       自动建表 hibernate.hbm2ddl.auto

              none 不使用hibernate的自动建表

              create 如果数据库中已经有表,删除原有表,重新创建,如果没有表,新建表。(测试)

              create-drop 如果数据库中已经有表,删除原有表,然后创建执行操作,删除这个表。 如果没有表,新建一个,                    使用完了删除该表。(测试)

              update 如果数据库中有表,使用原有表,如果没有表,创建新表(更新表结构)

              validate           :如果没有表,不会创建表。只会使用数据库中原有的表。(校验映射和表结构)。

映射文件的引入

       <mapping resource="cn/zjut/hibernate/domain/Customer.hbm.xml" />

Hibernate的API

Configuration Hibernate的配置对象

 

 

 作用:

        加载核心配置文件

         hibernate.properties

         Configuration cfg = new Configuration();

         hibernate.cfg.xml

         Configuration cfg = new Configuration().configure();

        加载映射文件

        // 手动加载映射

        configuration.addResource("cn/zjut/hibernate/domain/Customer.hbm.xml")

SessionFactory Session工厂   

 

 

SessionFactory内部维护了Hibernate的连接池和Hibernate的二级缓存。是线程安全的对象。一个项目创建一个对象即可。

 配置连接池

<property name="connection.provider_class">org.hibernate.c3p0.internal.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>

 抽取工具类

 Session 类似Connection对象是连接对象

Session代表的是Hibernate与数据库的链接对象。不是线程安全的。与数据库交互桥梁。

Session中的API

      保存方法:

      Serializable save(Object obj);

      查询方法:

      T get(Class c,Serializable id);

      T load(Class c,Serializable id);

      get方法和load方法的区别?

      

     

      load执行原理图

      修改方法

      void update(Object obj);

      

      删除方法

      void delete(Object obj);

     

      保存或更新

      void saveOrUpdate(Object obj)

     

      查询所有 

     

Transaction 事务对象

    commit();  

    rollback();

持久化类

        Hibernate是持久层的ORM映射框架,专注于数据持久化工作。所谓持久化,就是将内存中的数据永久存储到关系型数据库中。所谓持久化类就是一个Java类与数据库表建立映射关系,那么这个类称为持久化类。

持久化类编写规则

       持久化类需要提供无参构造方法。Hibernate底层需要使用反射生成类的实例对象。

       持久化类的属性需要私有,对私有属性提供get和set方法。在Hibernate底层会将查询到的数据进行封装。

      持久化类属性尽量使用包装类类型。包装类和基本数据类型默认值不同,包装类类型语义描述更清晰而基本数据类型不容易描述。

      持久化类要有一个唯一标识OID与表的主键对应。Hibernate需要通过这个唯一标识OID区分内存中是否是同一个持久化类。在关系型数据库的表中是通过主键区分是否是同一条记录。Hibernate是不允许在内存中出现两个OID相同的持久化对象。

     持久化类尽量不要使用final进行修饰。Hibernate有延迟加载机制,这个机制会产生代理对象,Hibernate产生代理对象是使用字节码增强技术完成的,其实是产生当前类的一个子类对象实现的。如果使用final修饰持久化类,那么不能产生子类,那么Hibernate延迟加载机制就会失效

主键生成策略

主键具备:不为空/不能重复/不能改变

自然主键:把具有业务含义的字段作为主键,称之为自然主键。

代理主键:把不具有业务含义的字段作为主键,称之为代理主键。

 

持久化对象三种状态

瞬时态(transient)

瞬时态也称为临时态或者自由态,瞬时态的实例是由new命令创建、开辟内存空间的对象,不存在持久化标识OID(相当于主键值),尚未与Hibernate Session关联,在数据库中也没有记录,瞬时状态的对象在内存中是孤立的,与数据库中的数据无任何关联,仅是一个信息携带的载体。

持久态(persistent)

       持久化对象存在持久化标识OID,加入到Session缓存中,并且相关联的Session没有关闭,数据库中有对应的记录,每条记录只对应唯一的持久化对象,持久态对象是在事务还未提交前变成持久态的。

脱管态(detached)

        脱管态也称为离线态或者游离态,当某个持久化状态的实例与Session的关联被关闭就变成脱管态,脱管态对象存在持久化标识OID,并且仍然与数据库中的数据存在关联,只是失去了与当前Session的关联,脱管状态对象发生改变时Hibernate不能检测到。

三种状态互相转化

 Hibernate持久化对象能够自动更新数据库

 Hibernate一级缓存

      Hibernate的一级缓存就是指Session缓存,Session缓存是一块内存空间,用来存放相互管理的Java对象,在使用Hibernate查询对象的时候,首先使用对象属性的OID值在Hibernate的一级缓存中进行查找,如果匹配OID值的对象,就直接将该对象从一级缓存中取出使用,不会再查询数据库;如果没有找到相同OID值对象,就会去数据库中查找相应数据。当从数据库查询到所需数据时,该信息也会放到一级缓存中。Hibernate的一级缓存的作用就是减少对数据库的访问次数。

       在Session接口实现中包含一系列Java集合,这些集合集合构成Session缓存。只要session实例没有结束生命周期,存放在它缓存中的对象也不会结束生命周期。

测试一级缓存

 移除缓存

 一级缓存内部结构(快照区)

        Hibernate向一级缓存存放数据时,同时复制一份数据到Hibernate快照中,当使用commit()提交事务时,同时会清理Session的一级缓存,这时会清理Session的一级缓存,这时会使用OID判断一级缓存中的对象和快照中对象是否一致,如果两个对象中的属性发生变化,则执行update语句,将缓存内容同步到数据库,并更新数据库;如果一致,则不执行update语句。Hibernate快照的作用就是确保一级缓存中的数据和数据库中的数据一致。

 事务

在数据库操作中,一项事务(Transaction)是由一条或多条操作数据库的SQL语句组成的一个不可分割的工作单元。当事务中的所有操作都正常完成时,整个事务才能被提交到数据库中,如果有一项操作没有完成,则整个事务会被回滚。总的来说:逻辑上的一组操作,组成这组操作的各个单元,要么一起成功,要么一起失败。

事务的四个特性

事务由很严格的定义,需要同时满足四个特性,即原子性、一致性、隔离性、持久性。这四个特性通常称之为ACID特性。

       原子性(Atomic):表示事务中所做的操作捆绑成一个不可分割的单元,即对事务所进行的数据修改等操作,要么全部执行,要么全都不执行。

       一致性(Consistency):表示事务完成时,必须使所有的数据都保持一致状态。

      隔离性(Isolation):指一个事务的执行不能被其它事务干扰。即一个事务内部操作及使用的数据对并发的其它事务是隔离的,并发执行的各个事务之间不能互相干扰。

      持久性(Durability):持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。提交后的其他操作或故障不会对其有任何影响。

事务的并发问题

       脏读:一个事务读取到另一个事务未提交的数据。

       不可重复读:一个事务读到另一个事务已经提交的update的数据,导致在同一个事务中的多次查询结果不一致。

       虚读/幻读:一个事务读到了另一个事务已经提交到的insert的数据,导致在同一个事务中的多次查询结果不一致。

事务隔离级别

       读未提交(Read Uncommitted, 1级)

       读已提交(Read Committed,2级)

       可重复读(Repeatable Read,4级)

       序列化/串行化(Serializable,8级)

事务隔离级别,是由数据库提供的,并不是所有数据库都支持四种隔离级别

MySQL:READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ、SERIALIZABLE

Oracle:READ_UNCOMMITTED、READ_COMMITTED、SERIALIZABLE

在使用数据库时候,隔离级别越高,安全性越高,性能越低

实际开发中,不选择最高或者最低隔离级别,选择READ_COMMITTED(Oracle默认)、REPEATABLE_READ(MySQL默认)

Hibernate中的事务管理

 在真正进行事务管理的时候,需要考虑事务的应用场景,也就是事务控制不应该是在DAO层实现的,应该在Service层实现,并且在Service中调用多个DAO实现一个业务逻辑的操作。最主要是如何保证在Service中开启的事务时时使用的Session对象和DAO中多个操作使用是同一个Session对象。

两种办法可以实现

       可以在业务层获取到Session,并将Session作为参数传递给DAO

       可以使用ThreadLocal将业务层获取的Session绑定到当前线程中,然后在DAO中获取Session的时候,都从当前线程获取。

 Hibernate的其他API

Query代表面向对象的一个Hibernate查询操作。在Hibernate中,通常使用session.createQuery()接受一个HQL语句,然后调用Query的list()或uniqueResult()执行查询。所谓HQL是Hibernate Query Language缩写,其语法很像SQL语法,但它是完全面向对象的。

Session session = HibernateUtil.openSession();
//查询所有记录
/*
Query query = session.createQuery("from Customer");
List<Customer> list = query.list();
System.out.println(list);
*/
//条件查询
/*
Query query = session.createQuery("from Customer where cust_name = ?");
query.setString(0,"张三");
//query.setParameter(0, "张三");
List<Customer> list = query.list();
System.out.println(list);
*/
//条件查询
 /*
Query query = session.createQuery("from Customer where cust_name = :aaa and cust_source = :bbb");
query.setString("aaa","张三");
query.setString("bbb","旁门左道");
List<Customer> list = query.list();
System.out.println(list);
*/
//分页查询询
Query query = session.createQuery("from Customer");
query.setFirstResult(0);
query.setMaxResults(3);
List<Customer> list = query.list();
System.out.println(list);
session.close();

Query中除了使用list()方法查询全部数据外,还有其它一些常用方法

setter方法:Query接口中提供一系列setter方法用于设置查询语句中的参数,针对不同数据类型,需要不同的setter方法

iterator()方法:该方法用于查询语句,返回结果是一个Iterator对象,在读取时只能按照顺序方式读取,它仅把使用到的数据转换成Java实体对象。

uniqueResult()方法:该方法用于返回唯一结果,在确保只有一条记录查询时可以使用该方法。

setFirstResult()方法:该方法可以设置获取第一个记录的位置,也就是它表示从第几条记录开始查询,默认从0开始计算。

setMaxResult()方法:该方法用于设置结果集的最大记录数,通常与setFirstResult()方法结合使用,用于限制结果集的范围,以实现分页功能。

executeUpdate()方法:该方法是Hibernate3的新特性,它支持HQL语句的更新和删除操作。

Criteria

Criteria是一个完全面向对象,可扩展的条件查询API,通过它完全不需要考虑数据库底层如何实现,以及SQL语句如何编写,它是Hibernate框架的核心查询对象。Criteria查询,又称为QBC查询,它是Hibernate的另一种对象检索方式。

org.hibernate.criterion.Criterion是Hibernate提供的一个面向对象查询条件接口,一个单独的查询就是Criterion接口的一个实例,用于限制Criteria对象的查询,在Hibernate中Criterion对象的创建通常是通过Restrictions工厂类完成的,它提供了条件查询的方法。

 

Session session = HibernateUtil.openSession();
//查询所有记录
/*
Criteria criteria = session.createCriteria(Customer.class);
List<Customer> list = criteria.list();
System.out.println(list);
*/
//条件查询
/*
Criteria criteria = session.createCriteria(Customer.class);
criteria.add(Restrictions.eq("cust_name","张三"));
List<Customer> list = criteria.list();
System.out.println(list);
*/
//条件查询
/*
Criteria criteria = session.createCriteria(Customer.class);
criteria.add(Restrictions.eq("cust_name","张三"));
criteria.add(Restrictions.eq("cust_source","旁门左道"));
List<Customer> list = criteria.list();
System.out.println(list);
*/
//分页查询询
Criteria criteria = session.createCriteria(Customer.class);
criteria.setFirstResult(3);
criteria.setMaxResults(3);
List<Customer> list = criteria.list();
System.out.println(list);
session.close();

在Criteria对象中,除了使用criteria.list()方法查询全部数据外,还有其它一些常用方法:如果只返回一个值,可以使用criteria的uniqueResult()方法

SQLQuery

SQLQuery这个接口用于接收一个sql语句进行查询,然后调用list()或者uniqueResult()方法进行查询。但是sql语句不会直接封装到实体对象中,需要手动写代码封装到实体中

Session session = HibernateUtil.openSession();
SQLQuery sqlQuery = session.createSQLQuery("select * from cst_customer");
List<Object[]> list = sqlQuery.list();
for (Object[] objects: list) {
    System.out.println(Arrays.toString(objects));
}
session.close();

数据库表与表之间的关系

一对多关系

        一个部门对应多个员工,一个员工只能属于某一个部门

       一个客户对应多个联系人,一个联系人只能属于某一个客户

一对多的建表原则

多对多关系

       一个学生可以选择多门课程,一门课程也可以被多个学生选择。

      一个用户可以选择多个角色,一个角色也可以被多个用户选择。

多对多的建表原则

 一对一关系

一对一的建表原则

Hibernate一对多的关系配置

创建一个项目,引入相应jar包

创建数据库和表

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) DEFAULT 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;

创建实体

一的一方的实体

 多的一方的实体

 创建映射文件

多的一方的映射的创建

<?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="cn.zjut.hibernate.domain.LinkMan" table="cst_linkman">
   <id name="lkm_id" column="lkm_id">
      <generator class="native"/>
   </id>
   <property name="lkm_name"/>
   <property name="lkm_gender"/>
   <property name="lkm_phone"/>
   <property name="lkm_mobile"/>
   <property name="lkm_email"/>
   <property name="lkm_qq"/>
   <property name="lkm_position"/>
   <property name="lkm_memo"/>
   <!--
   配置多对一关系,放置的是一的一方对象
   many-to-one标签
       name 一的一方对
象属性名称
       class 一的一方类的全路径
       column 多的一方表的外键名称
   -->
   <many-to-one name="customer" class="cn.zjut.hibernate.domain.Customer" column="lkm_cust_id"/>
   </class>
</hibernate-mapping>

一的一方的映射的创建

<?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="cn.zjut.hibernate.domain.Customer" table="cst_customer">
      <id name="cust_id" column="cust_id" >
         <generator class="native"/>
      </id>
      
      <property name="cust_name" column="cust_name" length="32" />
      <property name="cust_source" column="cust_source" length="32"/>
      <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="cn.zjut.hibernate.domain.LinkMan"/>
      </set>
   </class>
</hibernate-mapping>

创建核心配置文件

引入工具类

编写测试类

       

 一对多关系只保存一边是否可以

一对多的级联操作

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

级联是有方向性

       操作一的一方的时候,是否操作到多的一方

       操作多的一方的时候,是否操作到一的一方

保存客户级联联系人

 

Session session = HibernateUtil.openSession();
Transaction transaction = session.beginTransaction();

Customer customer = new Customer();
customer.setCust_name("张三");

LinkMan linkMan = new LinkMan();
linkMan.setLkm_name("关门");

customer.getLinkMans().add(linkMan);
linkMan.setCustomer(customer);

session.save(customer);


transaction.commit();
session.close();

保存联系人级联客户

 

Session session = HibernateUtil.openSession();
Transaction transaction = session.beginTransaction();

Customer customer = new Customer();
customer.setCust_name("张三");

LinkMan linkMan = new LinkMan();
linkMan.setLkm_name("关门");

customer.getLinkMans().add(linkMan);
linkMan.setCustomer(customer);

session.save(linkMan);

transaction.commit();
session.close();

测试对象的导航

Session session = HibernateUtil.openSession();
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);

//双方都设置cascade
//session.save(linkMan1);//4条insert语句
//session.save(customer);//3条insert语句
session.save(linkMan2);//1条insert语句
transaction.commit();
session.close();

级联删除

       删除一边的时候,同时将另一方的数据也一并删除。

删除客户级联删除联系人

 删除联系人级联删除客户(基本不用)

 

 

一对多设置了双向关联产生多余的SQL语句

 

解决多余的SQL语句

单向维护

    使一方放弃外键维护权

               一的一方放弃。在set上配置inverse=”true”

区分cascadeinverse

 Hibernate多对多关系的配置

创建表

用户表

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=1 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;

创建实体

 

 

创建映射

用户的映射

<?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="cn.zjut.hibernate.domain.User" table="sys_user">
      <id name="user_id" column="user_id">
         <generator class="native"></generator>
      </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 当前对象对应中间表的外键名称
         -->
         <key column="user_id"/>
         <!--
         many-to-many标签
         class 对方类的全路径
         column 对方对象在中间表的外键名称
         -->
         <many-to-many class="cn.zjut.hibernate.domain.Role" column="role_id"/>
      </set>
   </class>
</hibernate-mapping>

角色的映射

<?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="cn.zjut.hibernate.domain.Role" table="sys_role">
      <id name="role_id" column="role_id">
         <generator class="native"/>
      </id>
      <property name="role_name"/>
      <property name="role_memo"/>
      <!--建立与用户的多对多关系-->
      <!--
      set标签
      name 对方集合属性名称
      table 多对多关系需要中间表,放的是中间表名称
      -->
      <set name="users" table="sys_user_role" inverse="true">
         <!--
         key标签
         column 当前对象对应中间表的外键名称
         -->
         <key column="role_id"/>
         <!--
         many-to-many标签
         class 对方类的全路径
         column 对方对象在中间表的外键名称
         -->
         <many-to-many class="cn.zjut.hibernate.domain.User" column="user_id"/>
      </set>
   </class>
 </hibernate-mapping>

编写测试代码

 

只保存一边是否可以

Session session = HibernateUtil.openSession();
Transaction transaction = session.beginTransaction();

User user = new User();
user.setUser_name("张三");

Role role = new Role();
role.setRole_name("研发");

user.getRoles().add(role);
role.getUsers().add(user);

//session.save(user);
session.save(role);

transaction.commit();
session.close();

多对多的级联保存或更新

保存用户级联保存角色

Session session = HibernateUtil.openSession();
Transaction transaction = session.beginTransaction();

User user = new User();
user.setUser_name("张三");

Role role = new Role();
role.setRole_name("研发");

user.getRoles().add(role);
role.getUsers().add(user);

session.save(user);


transaction.commit();
session.close();

保存角色级联保存用户

Session session = HibernateUtil.openSession();
Transaction transaction = session.beginTransaction();

User user = new User();
user.setUser_name("张三");

Role role = new Role();
role.setRole_name("研发");

user.getRoles().add(role);
role.getUsers().add(user);


session.save(role);

transaction.commit();
session.close();

多对多的级联删除(基本用不上)

删除用户级联删除角色

 删除角色级联删除用户

 

多对多的其他的操作

 给用户选择角色

给用户改选角色

 

 给用户删除角色

 

 

 

 

 

 

 

 

 

 

 

 

             

 

 

 

 

 

       

 

 

 

 

          

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值