Hibernate框架学习笔记

Hibernate入门

一、概述

  1. hibernate概述:开源的对象关系映射(ORM)框架。它对JDBC进行了非常轻量级的封装,它可以自动生成SQL语句,自动执行,可以让我们使用对象编程思想来操作数据库。持久层框架。注意点:ORM:object relational mapping(Java对象与关系型数据库中的表建立一种映射关系)
  2. 我们使用的hibernate版本是:5x;解压下载的hibernate开发包会得到三个文件夹:
    ①documentation—开发的文档
    ②lib----开发包(required—必须的依赖包、optional-----可选的jar包)
    ③project----提供的项目

二、入门小案例

2.1创建项目引入jar包

①数据库的驱动包:
在这里插入图片描述
②hibernate开发必须包:
在这里插入图片描述
③日志记录包:
在这里插入图片描述

2.2 创建表

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;

这里需要注意的是:列名包含的那个符号是esc下面那个键,而不是单引号

2.3创建实体类

在这里插入图片描述

2.4创建映射配置文件*

<?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.demo1.Customer" table="cst_customer">
		<!-- 建立类中的属性与表的主键对应 -->
		<id name="cust_id" column="cust_id">
			<!-- 主键生成策略 -->
			<generator class="native"></generator>
		</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_mobil" column="cust_mobil"/>
	</class>
</hibernate-mapping>

注意点
①映射文件的约束的位置在hibernate-configuration-3.0.dtd里面寻找
②映射文件的命名格式:类名.hbm.xml
总结
①【class标签的配置】建立类与表的映射关系
属性:
name:类的全路径
table:表名(类名与表名一致的时候可以省略)
catalog:数据库名
②【id标签的配置】建立类中的属性与表的主键的对应关系
属性:
name:类的属性名
column:表的字段名(类中属性名与表中字段名一致可以省略column)
length:长度
type:类型
③【property标签的配置】建立类中普通属性与表的字段的对应关系
属性:
name:类中属性名
column:表中的字段名
length:长度
type:类型
not-null:非空
unique:设置唯一

2.5创建核心的配置文件

<?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>
	<session-factory>
		<!-- 连接数据库的基本参数 =======================-->
		<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
		<property name="hibernate.connection.url">jdbc:mysql:///repeathibernate</property>
		<property name="hibernate.connection.username">root</property>
		<property name="hibernate.connection.password">root</property>
		
		<!-- 配置hibernate的方言 =====================-->
		<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
		
		<!-- 可选的配置============================== -->
		<!-- 是否让控制台打印sql语句 -->
		<property name="hibernate.show_sql">true</property>
		<!-- 是否格式化sql语句 -->
		<property name="hibernate.format_sql">true</property>
		<!-- 是否让hibernate自动创建表 -->
		<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>
		
		<!-- 引入映射文件 =====================================-->
		<mapping resource="com/itheima/hibernate/demo1/Customer.hbm.xml"/>
	</session-factory>
</hibernate-configuration>

注意点:
①约束的位置在libraries/core.jar最后几个文件
②数据库连接的配置信息在hibernate开发包提供的项目案例里面(etc)
③hibernate只会读取核心配置文件,所以需要将映射文件包含在核心配置里面
总结:
①必须的配置
【连接数据库的基本参数】驱动类,URL路径,用户名,密码
【方言】
②可选的配置
显示sql:hibernate.show_sql
格式化sql:hibernate.format_sql
自动建表:hibernate.hbm2ddl.auto,具体参数如下:

none不使用hibernate的自动建表
create如果数据库中已经有表,删除原有表,重新创建;如果没有表就新建一个表(主要用来进行测试)
create-drop如果数据库中已有表,删除原有表,执行操作,删除这个表;如果没有表,新建一个表,使用结束删除该表(测试)
update如果数据库中有表,使用原有表;如果没有表,创建新表(更新表结构)
validate如果没有表,不会创建表;只会使用数据库中的原有表(校验映射和表结构)

③映射文件的引入,使用标签mapping 文件路径放在resource标签里面

2.6编写测试代码

public class HibernateTest {
	@Test
	public void demo1(){
		//加载核心配置文件
		Configuration configuration = new Configuration().configure();
		//创建一个sessionFactory对象,类似于JDBC连接池
		SessionFactory sessionFactory = configuration.buildSessionFactory();
		//通过SessionFactory对象获取Session对象,类似于JDBC中的Connection
		Session session = sessionFactory.openSession();
		//手动开启事务
		Transaction transaction = session.beginTransaction();
		//编写代码
		Customer customer = new Customer();
		customer.setCust_name("小豹子");
		customer.setCust_level("小弟");
		session.save(customer);
		//提交事务
		transaction.commit();
		//资源关闭
		session.close();
	}
}

三、hibernate的核心API

3.1Configuration:hibernate的配置对象

①加载核心配置文件
【hibernate.properties】

Congfiguration cfg = new  Configuration();

【hibernate.hbm.xml】

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

②加载映射文件
手动加载:

configuration.addResource("com/ithiema/hibernate/demo1/Customer.hbm.xml");

3.2SessionFactory:Session工厂

描述:SessionFactory接口负责初始化hibernate。充当数据存储源的代理,负责创建session对象。这里用到了工厂模式。SessionFactory不是轻量级的,一个项目通常只需要一个SessionFactory就可以了,用到多个数据库,可以为每个数据库指定一个SessionFactory。
SessionFactory内部维护了Hibernate连接池和Hibernate的二级缓存。是线程安全的对象,一个项目创建一个对象就可以了
抽取工具类:

package com.itheima.hibernate.utils;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtils {

	public static Configuration configure;
	public static SessionFactory sessionFactory;
	static {
		configure = new Configuration().configure();
		sessionFactory = configure.buildSessionFactory();
	}
	
	public static Session openSession(){
		return sessionFactory.openSession();
	}
}

3.3Session:类似connection是连接对象

Session接口负责执行被持久化对象的CRUD操作,Session对象是非线程安全的,与数据库交流的桥梁。
Session中的API:
①保存方法:

	public void demo1(){
		//加载核心配置文件
		Configuration configuration = new Configuration().configure();
		//创建一个sessionFactory对象,类似于JDBC连接池
		SessionFactory sessionFactory = configuration.buildSessionFactory();
		//通过SessionFactory对象获取Session对象,类似于JDBC中的Connection
		Session session = sessionFactory.openSession();
		//手动开启事务
		Transaction transaction = session.beginTransaction();
		//编写代码
		Customer customer = new Customer();
		customer.setCust_name("小豹子");
		customer.setCust_level("小弟");
		session.save(customer);
		//提交事务
		transaction.commit();
		//资源关闭
		session.close();
	}

②查询方法
【T get(Class c,Serializable id)】

	public void demo3(){
		Session session = HibernateUtils.openSession();
		Transaction transaction = session.beginTransaction();
		transaction.begin();
		Customer customer = session.get(Customer.class, 2l);
		System.out.println(customer);
		transaction.commit();
		session.close();
	}

【T load(Class c ,Serializable id)】

	public void demo2(){
		Session session = HibernateUtils.openSession();
		 Transaction transaction = session.beginTransaction();
		 transaction.begin();
		 Customer customer = session.load(Customer.class, 1l);
		 System.out.println(customer);
		 transaction.commit();
		 session.close();
	}

load方法与get方法的区别:
get采用的是立即加载,执行到这行代码的时候,就会马上发送SQL语句去查询
查询后返回的是真实对象本身
查询一个找不到的对象的时候返回的是null

load采用的是延迟加载(lazy懒加载),执行到这行代码的时候,不会发送SQL语句,当真正使用到这个对象的时候才会发送SQL语句
查询后返回的是代理对象
查询一个找不到的对象的时候,返回的是ObjectNotFoundException
③修改方法(先查询再修改)

	public void demo4(){
		Session session = HibernateUtils.openSession();
		Transaction transaction = session.beginTransaction();
		transaction.begin();
		Customer customer = session.get(Customer.class, 1l);
		customer.setCust_name("小煤球");
		session.update(customer);
		transaction.commit();
		session.close();
	}

④删除方法(先查询再删除)

	public void demo5(){
		Session session = HibernateUtils.openSession();
		Transaction transaction = session.beginTransaction();
		transaction.begin();
		Customer customer = session.get(Customer.class, 2l);
		session.delete(customer);
		transaction.commit();
		session.close();
	}

⑤保存或更新方法(void saveOrUpdate(Object obj))

	public void demo6(){
		Session session = HibernateUtils.openSession();
		Transaction transaction = session.beginTransaction();
		transaction.begin();
		Customer customer = new Customer();
		customer.setCust_name("小茗子");
		customer.setCust_source("小豹子推荐");
		session.saveOrUpdate(customer);
		transaction.commit();
		session.close();
	}

⑥查询所有
【面向对象查询:HQL】

	public void demo7(){
		Session session = HibernateUtils.openSession();
		Transaction transaction = session.beginTransaction();
		transaction.begin();
		Query query = session.createQuery("from Customer");
		List<Customer> list = query.list();
		for (Customer customer : list) {
			System.out.println(customer);
		}
	}

【接收SQL】

	public void demo8(){
		Session session = HibernateUtils.openSession();
		Transaction transaction = session.beginTransaction();
		transaction.begin();
		SQLQuery query = session.createSQLQuery("select * from cst_customer");
		List<Object[]> list = query.list();
		for (Object[] objects : list) {
			System.out.println(Arrays.toString(objects));
		}
		transaction.commit();
		session.close();
	}

3.4事务对象:Transaction

begin()
commit()
rollback()

四、持久化类

4.1持久化类的编写规则

持久化:将内存中的一个对象持久化到数据库的过程,hibernate就是用来进行持久化的框架
持久化类:一个Java对象与数据库中的表建立了映射关系,这个类在hibernate中就被称为持久化类。

规则描述
对持久化类提供一个无参数的构造方法hibernate底层需要使用反射生成实例
属性需要私有,对私有属性提供public的get和set方法hibernate中获取与设置对象的值
对持久化类提供一个唯一标识OID与数据库的主键对应Java中通过对象的地址区分是否是同一个对象;数据库中通过主键确定是否是同一个记录,在hibernate中通过持久化类的OID的属性区分是否是同一个对象
持久化类的属性尽量使用包装类类型因为基本数据类型默认值是0,0会产生很多歧义。包装类类型的默认值是null
持久化类不要使用final修饰延迟加载本身是hibernate的一个优化手段,返回的是一个代理对象(javassist可以对没有实现接口的类产生代理,使用了非常底层的字节码增强技术,继承这个类进行代理),如果不能被继承,不能产生代理对象,延迟加载也就失效,load方法与get方法也就别无二致了。

4.2持久化类的三种状态

hibernate是持久层框架,通过持久化类完成ORM操作。hibernate为了更好的管理持久化类,将持久化类分成三种状态
持久化类 = Java类+映射文件
持久化类的三种状态:

状态描述
瞬时态这种对象没有唯一标识OID,没有被sesssion管理
持久态这种对象有唯一标识OID,被session管理(持久化类的持久态对象,可以自动更新数据库)
脱管态有唯一标识,没有被session管理

4.3持久化类三种状态的转换(了解)

①瞬时态对象:
获取:Customer customer = new Customer();
状态转换:
瞬时态→持久态 save()、saveOrUpdate()
瞬时态→脱管态 customer.setCust_id(1)

②持久态对象:
获得:get()、load()、find()、iterate()
状态转换:
持久态→瞬时态 delete()
持久态→脱管态 close()、clear()、evict()

③脱管态对象:
获得:Customer customer = new Customer();
customer.setCust_id(1);
状态转换:
脱管态→持久态:update()、saveOrUpdate()
脱管态→瞬时态:customer.setCust_id(null);

五、主键生成策略

5.1主键的分类

①自然主键:主键本身就是表中的一个字段(实体中一个具体属性)
如:创建一个人员表,人员都会有个身份证号(唯一的不可重复的),使用了身份证号作为主键,这些主键称为自然主键。
②代理主键:主键本身不是表中的一个字段(不是实体中某一个具体的属性)
如:创建一个人员表,没有使用人员中的身份证号,用一个与这个表不相关的字段ID,这种主键称为代理主键
在实际开发中,尽量使用代理主键:
一旦自然主键参与到逻辑中,后期有可能修改源代码
好的程序设计满足OCP原则。对程序的扩展是open的,对修改源码是close的

5.2主键的生成策略

在实际开发中一般不允许用户手动设置主键,一般将主键交给数据库,手动编写程序进行设置,在hibernate中为了减少程序编写,提供了很多种主键的生成策略。

方式描述
incrementhibernate中提供的自动增长机制,适用于short、int、long类型的主键,在单线程的程序中使用(首先发送一条语句:select max(id) from 表,然后让id+1作为下一条记录的主键)
identity适用于short、int、long类型的主键,使用的是数据库底层的自动增长机制,适用于有自动增长机制的数据库(MySQL、MSSQL,但是Oracle没有自动增长机制)
sequence适用于short、int、long类型的主键,采用的序列的方式(oracle支持序列)MYSQL不支持序列的方式
uuid适用于字符串类型主键,使用hibernate中随机方式生成字符串主键
native本地策略,可以在identity和sequence中随意切换
assignedhibernate放弃外键的管理,需要手动编写程序或者用户自己设置
foreign外部的。一对一的关联映射的情况下使用

六、缓存

6.1概述

缓存:一种优化方式,将数据存入到内存中,使用的时候直接从缓存中获取,不用通过存储源。
hibernate 一级缓存:hibernate提供了优化手段:缓存、抓取策略。hibernate提供了两种缓存机制,hibernate的一级缓存,称为是session级别的缓存,一级缓存生命周期与session一致(一级缓存是由session中的一系列Java集合构成的),一级缓存是自带的不可卸载的(hibernate的二级缓存是SessionFactory级别的缓存,需要配置的缓存)

七、事务

7.1概述

事务:事务是指逻辑上的一组操作,组成这组操作的各个逻辑单元要么全部成功要么全部失败

7.2事务的特性

特性描述
原子性代表事务不可分割
一致性事务执行前后,事务的完整性保持一致
隔离性代表事务执行的过程中,不应该受到其他事务的干扰
持久性代表事务执行完成后,数据就持久到数据库中

7.3如果不考虑隔离性,会引发安全性问题

读问题描述
脏读一个事务读到另一个事务未提交的数据
不可重复读一个事务读到另一个事务已经提交的update数据,导致前一个事务多次查询的结果不一致
虚读(幻读)一个事务读到另一个事务已经提交的insert数据,导致前一个事务多次查询的结果不一致

写问题:引发两类丢失更新

7.4读问题的解决

设置事务的隔离级别

隔离级别能解决的问题
Read uncommitted1以上读问题都会发送
Read committed2解决脏读,但是不可重复读和虚读有可能发生
Repeatable read4解决脏读和不可重复读,但是虚读有可能发生
Serializable8解决所有问题

在hibernate如何设置事务的隔离级别

<property name="hibernate.connection.isolation">4</property>

线程绑定的Session:

<property name="hibernate.current_session_context_class">thread</property>

八、一对多案例

8.1 建表原则

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

8.2创建实体类

【客户类】:

package com.itheima.hibernate.domain;

import java.util.HashSet;
import java.util.Set;

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> linkMans = new HashSet<LinkMan>();
	public Long getCust_id() {
		return cust_id;
	}
	public void setCust_id(Long cust_id) {
		this.cust_id = cust_id;
	}
	public String getCust_name() {
		return cust_name;
	}
	public void setCust_name(String cust_name) {
		this.cust_name = cust_name;
	}
	public String getCust_source() {
		return cust_source;
	}
	public void setCust_source(String cust_source) {
		this.cust_source = cust_source;
	}
	public String getCust_industry() {
		return cust_industry;
	}
	public void setCust_industry(String cust_industry) {
		this.cust_industry = cust_industry;
	}
	public String getCust_level() {
		return cust_level;
	}
	public void setCust_level(String cust_level) {
		this.cust_level = cust_level;
	}
	public String getCust_phone() {
		return cust_phone;
	}
	public void setCust_phone(String cust_phone) {
		this.cust_phone = cust_phone;
	}
	public String getCust_mobile() {
		return cust_mobile;
	}
	public void setCust_mobile(String cust_mobile) {
		this.cust_mobile = cust_mobile;
	}
	public Set<LinkMan> getLinkMans() {
		return linkMans;
	}
	public void setLinkMans(Set<LinkMan> linkMans) {
		this.linkMans = linkMans;
	}
	
}

【联系人类】:

package com.itheima.hibernate.domain;

public class LinkMan {
	private Long lkm_id;
	private String lkm_name;
	private String lkm_gender;
	private String lkm_phone;
	private String lkm_mobile;
	private String lkm_email;
	private String lkm_qq;
	private String lkm_position;
	private String lkm_memo;
	private Customer customer;
	public Long getLkm_id() {
		return lkm_id;
	}
	public void setLkm_id(Long lkm_id) {
		this.lkm_id = lkm_id;
	}
	public String getLkm_name() {
		return lkm_name;
	}
	public void setLkm_name(String lkm_name) {
		this.lkm_name = lkm_name;
	}
	public String getLkm_gender() {
		return lkm_gender;
	}
	public void setLkm_gender(String lkm_gender) {
		this.lkm_gender = lkm_gender;
	}
	public String getLkm_phone() {
		return lkm_phone;
	}
	public void setLkm_phone(String lkm_phone) {
		this.lkm_phone = lkm_phone;
	}
	public String getLkm_mobile() {
		return lkm_mobile;
	}
	public void setLkm_mobile(String lkm_mobile) {
		this.lkm_mobile = lkm_mobile;
	}
	public String getLkm_email() {
		return lkm_email;
	}
	public void setLkm_email(String lkm_email) {
		this.lkm_email = lkm_email;
	}
	public String getLkm_qq() {
		return lkm_qq;
	}
	public void setLkm_qq(String lkm_qq) {
		this.lkm_qq = lkm_qq;
	}
	public String getLkm_position() {
		return lkm_position;
	}
	public void setLkm_position(String lkm_position) {
		this.lkm_position = lkm_position;
	}
	public String getLkm_memo() {
		return lkm_memo;
	}
	public void setLkm_memo(String lkm_memo) {
		this.lkm_memo = lkm_memo;
	}
	public Customer getCustomer() {
		return customer;
	}
	public void setCustomer(Customer customer) {
		this.customer = customer;
	}
}

8.3创建数据库及表

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;

效果图:
【客户】
在这里插入图片描述
【联系人】
在这里插入图片描述
两个表的联系示意图:
在这里插入图片描述

8.4创建映射文件

【客户】

<?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="linkMans" cascade="save-update,delete">
			<!-- 外键 -->	
			<key column="lkm_cust_id"></key>
			<!-- 多的一方类的全路径 -->
			<one-to-many class="com.itheima.hibernate.domain.LinkMan"/>
		</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="com.itheima.hibernate.domain.LinkMan" table="cst_linkman">
		<id name="lkm_id" column="lkm_id">
			<generator class="native"></generator>
		</id>
		<property name="lkm_name" column="lkm_name"></property>
		<property name="lkm_gender" column="lkm_gender"></property>
		<property name="lkm_phone" column="lkm_phone"></property>
		<property name="lkm_mobile" column="lkm_mobile"></property>
		<property name="lkm_email" column="lkm_email"></property>
		<property name="lkm_qq" column="lkm_qq"></property>
		<property name="lkm_position" column="lkm_position"></property>
		<property name="lkm_memo" column="lkm_memo"></property>
		<!-- 配置客户 -->
		<many-to-one name="customer" cascade="save-update,delete" column="lkm_cust_id" class="com.itheima.hibernate.domain.Customer"></many-to-one>
	</class>
</hibernate-mapping>    

8.5一对多测试1

①创建两个客户和三个联系人

	//创建两个客户和三个联系人并将他们联系起来
	public void test1(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		transaction.begin();
		//创建两个客户
		Customer customer1 = new Customer();
		customer1.setCust_name("罗甲");
		Customer customer2 = new Customer();
		customer2.setCust_name("罗乙");
		//创建三个联系人
		LinkMan linkMan1 = new LinkMan();
		linkMan1.setLkm_name("罗A");
		LinkMan linkMan2 = new LinkMan();
		linkMan2.setLkm_name("罗B");
		LinkMan linkMan3 = new LinkMan();
		linkMan3.setLkm_name("罗C");
		//设置关系
		linkMan1.setCustomer(customer1);
		linkMan2.setCustomer(customer1);
		linkMan3.setCustomer(customer2);
		customer1.getLinkMans().add(linkMan1);
		customer1.getLinkMans().add(linkMan2);
		customer2.getLinkMans().add(linkMan3);
		//保存
		session.save(linkMan1);
		session.save(linkMan2);
		session.save(linkMan3);
		session.save(customer1);
		session.save(customer2);
		transaction.commit();
	}

②一对多只保存一边是否可以?

	//只保存一边是否可行
	public void test2(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		transaction.begin();
		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();
	}

这样是不可以的,会出现异常,无法保存

8.6级联操作

级联:操作一个对象的时候是否会操作其关联的对象
级联的方向性:
操作一的一方的时候,是否会操作到多的一方。
操作多的一方的时候,是否会操作到一的一方。
①级联保存或更新
【保存客户级联联系人】需要在客户的映射文件里面配置一下级联信息!
在这里插入图片描述
现在下面这个保存一边就不会出现异常了!

	public void test3(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		transaction.begin();
		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();
	}

【保存联系人级联客户】需要在联系人的映射文件中配置级联信息!
在这里插入图片描述
下面这个就是保存另外一边!

	//保存联系人级联客户
	public void test4(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		transaction.begin();
		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();
	}

②级联删除
【删除客户级联删除联系人】:
如果没有在客户的映射文件中去配置级联信息,删除的时候,可以删除客户,但是不能删除联系人,联系人的外键会修改为null;
如果设置了级联信息,删除客户会同时删除联系人。

	public void test5(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		transaction.begin();
		Customer customer = session.get(Customer.class, 9l);
		session.delete(customer);
		transaction.commit();
	}

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

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

解决办法:
①单向维护
②使一方放弃外键维护权(一的一方放弃,在set上设置inverse=“true”)

九、多对多关联映射

9.1创建表

①用户表:

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;

9.2创建实体类

【用户类】

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>();
	public Set<Role> getRoles() {
		return roles;
	}
	public void setRoles(Set<Role> roles) {
		this.roles = roles;
	}
	public Long getUser_id() {
		return user_id;
	}
	public void setUser_id(Long user_id) {
		this.user_id = user_id;
	}
	public String getUser_code() {
		return user_code;
	}
	public void setUser_code(String user_code) {
		this.user_code = user_code;
	}
	public String getUser_name() {
		return user_name;
	}
	public void setUser_name(String user_name) {
		this.user_name = user_name;
	}
	public String getUser_password() {
		return user_password;
	}
	public void setUser_password(String user_password) {
		this.user_password = user_password;
	}
	public String getUser_state() {
		return user_state;
	}
	public void setUser_state(String user_state) {
		this.user_state = user_state;
	}
	
}

【角色类】

public class Role {
	private Long role_id;
	private String role_name;
	private String role_memo;
	//一个角色被多个用户选择:放置一个用户的集合
	private Set<User> users = new HashSet<User>();
	
	public Set<User> getUsers() {
		return users;
	}
	public void setUsers(Set<User> users) {
		this.users = users;
	}
	public Long getRole_id() {
		return role_id;
	}
	public void setRole_id(Long role_id) {
		this.role_id = role_id;
	}
	public String getRole_name() {
		return role_name;
	}
	public void setRole_name(String role_name) {
		this.role_name = role_name;
	}
	public String getRole_memo() {
		return role_memo;
	}
	public void setRole_memo(String role_memo) {
		this.role_memo = role_memo;
	}
	
}

9.3创建映射

【用户的映射文件配置】

<?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" 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 放的是中间表的名称 -->
		<set name="roles" table="sys_user_role" cascade="sava-update">            
			<key column="user_id"/>       
			   <!-- column 当前对象对应中间表的外键名称 -->
			<many-to-many class="com.itheima.hibernate.domain.Role" column="role_id"/> 
			<!-- class对方类的全路径 column 对方对象在中间表的外键名称 -->
		</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="com.itheima.hibernate.domain.Role" table="sys_role">
		<!-- 建立OID与主键的映射 -->
		<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"/>
		<!-- 建立与用户多对多的关系 -->
		<set name="users" table="sys_user_role" inverse="true">
			<key column="role_id"/>
			<many-to-many class="com.itheima.hibernate.domain.User" column="user_id"/>
		</set>
	</class>
</hibernate-mapping>    
    

十、hibernate的查询方式

10.1OID查询

OID检索:hibernate根据对象的OID (主键)进行检索
①get方法:

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

②load方法:

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

10.2对象导航检索

hibernate根据已经查询到的对象,获得其关联对象的一种查询方式。

LinkMan linkMan = session.get(LinkMan.class,1l);
Customer customer = linkMan.getCustomer();
或者
Customer customer = session.get(Customer.class,2l);
Set<LinkMan> linkMans = customer.getLinkMans();

10.3HQL检索

hibernate的查询语言,是一种面向对象的查询语言,语法类似sql,通过session.createQuery(),用于接受一个HQL进行查询
①简单查询

	public void test6(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		transaction.begin();
		Query query = session.createQuery("from Customer");
		List<Customer> list = query.list();
		for (Customer customer : list) {
			System.out.println(customer);
		}
		transaction.commit();
	}

②别名查询

	public void test7(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		transaction.begin();
		Query query = session.createQuery("select c from Customer c");
		List<Customer> list = query.list();
		for (Customer customer : list) {
			System.out.println(customer);
		}
		transaction.commit();
	}

③hibernate的排序查询

	public void test8(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		transaction.begin();
		List<Customer> list = session.createQuery("from Customer order by cust_id desc").list();
		for (Customer customer : list) {
			System.out.println(customer);
		}
		transaction.commit();
	}

④条件查询

	public void test9(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		transaction.begin();
		Query query = session.createQuery("from Customer where cust_id = ?");
		query.setParameter(0, 4l);
		List<Customer> list = query.list();
		for (Customer customer : list) {
			System.out.println(customer);
		}
		transaction.commit();
	}
	public void test10(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction transaction = session.beginTransaction();
		transaction.begin();
		Query query = session.createQuery("from Customer where cust_source = ? and cust_name like ?");
		query.setParameter(0, "朋友推荐");
		query.setParameter(1, "罗%");
		List<Customer> list = query.list();
		for (Customer customer : list) {
			System.out.println(customer);
		}
		transaction.commit();
	}

还有一个:

		Query query = session.createQuery("from Customer where cust_source = :aaa and cust_name like :bbb");
		query.setParameter("aaa", "朋友推荐");
		query.setParameter("bbb", "罗%");

⑤投影查询:查询对象的某些或某个属性

List<Object> list = session.createQuery("select c.cust_name from Customer c").list();
List<Object[]> list = session.createQuery("select c.cust_name,c.cust_source from Customer c").list();

查询多个属性然后放入到一个对象中去:

List<Customer> list = session.createQuery("select new Customer(cust_name,cust_source) from Customer").list();

⑥分页查询

	    Query query2 = session.createQuery("from LinkMan");
	    query2.setFirstResult(10);
	    query2.setMaxResults(20);

⑦分组统计查询
聚合函数的使用:count(),max(),min(),avg(),sum()

List<Object[]> list = session.createQuery("select cust_source,count(*) from Customer group by cust_source").list();

⑧多表查询
SQL的多表查询

1连接查询
①交叉连接:笛卡尔积
select * from A,B;
②内连接:inner join (inner 可以省略)
隐式内连接:
select * from A,B where A.id = B.aid;
显式内连接:
select * from A inner join B on A.id = B.aid;
③外连接:
左外连接:left outer join(outer 可以省略)
select * from A left outer join B on A.id = B.aid;
右外连接:right out join (outer 可以省略)
select * from A right outer join B on A.id = B.aid;
2子查询

Hibernate的多表查询相对于SQL的多表查询大致差不多,但是其在内连接与外连接多了:迫切内连接和迫切左外连接

10.4QBC查询

query by criteria :一种更加面向对象的查询方式
①简单查询

List<Customer> list = session.createCriteria("Customer.class").list();

②排序查询

	    Criteria criteria = session.createCriteria("Customer.class");
	    criteria.addOrder(Order.desc("cust_id"));

desc:降序
asc:升序
③分页查询

	    Criteria criteria = session.createCriteria("Customer.class");
	    criteria.setFirstResult(10);
	    criteria.setMaxResults(20);

④条件查询

符号含义
eq=
gt>
ge>=
lt<
le<=
ne<>

还有:like、in、and、or

 Criteria criteria = session.createCriteria("Customer.class");
	    criteria.add(Restrictions.like("cust_name", "罗%"));
	    criteria.add(Restrictions.eq("cust_source","小广告"));

10.5使用SQL查询

SQLQuery sqlQuery = session.createSQLQuery("select * from cst_customer");
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值