Hibernate3 第一天

时间:2023-03-08 22:53:35
Hibernate3 第一天

Hibernate3 第一天

课程安排:4天(框架的使用+理论知识)

  1. 第一天Hibernate快速入门(单表的CRUD)+核心api讲解(配置+接口)
  2. 第二天:Hibernate一级缓存,快照,对象持久化状态,多表映射操作
  3. 第三天Hibernate各种查询的使用(三种方法),抓取策略优化(lazy加载等)
  4. 第四天 Hibernate二级缓存\查询缓存,jpa注解的使用

内容安排:

  1. Hibernate概述、有什么优缺点等
  2. Hibernate的快速入门:环境搭建、CRUD(增删改查)Create-Read-Update-Delete
  3. Hibernate核心配置常用属性详解
  4. Hibernate核心API常用操作详解
  5. 持久化对象的PO\OID的说明
  6. hbm映射文件配置常用参数详解

学习目标:

快速入门,可应用Hibernate的常见的CRUD进行单表。

  1. Hibernate概述

    1. Hibernate的来历

Hibernate3 第一天

关键词:开源框架,属于jboss公司产品,时间久远。可以不写SQL就可以操作数据库。

(EJB的CMP技术)

  1. 什么是Hibernate

Hibernate是轻量级JavaEE应用的持久层解决方案,是一个关系数据库ORM框架。

  • 轻量级:使用方便(比Apache DbUtils 复杂很多倍)这个概念是个相对概念。(主要是对比EJB来说的,ejb是重量级的(内建组件很多,启动很慢,东西很多))
  • 持久层: JavaEE分为表现层、业务层(service)、持久层(dao)

    Struts2 是一个表现层框架

    Hibernate 是一个持久层框架,底层就是封装了JDBC,也就说,HIbernate最终进入数据库执行的还是sql语句(操作数据库)--ssh

  • 关系数据库: mysql、oracle 都是关系型数据库(主流数据库)

    最近 NOSQL 非关系型数据库开始流行(mongodb、 redis)

  • ORM :Object Relational Mapping对象关系映射(一种思想)

Java--面向对象的语言

Mysql--关系型数据库

将数据表的关系,映射为类和对象之间关系:

数据库(关系型)

Java(面向对象的编程语言)

表的字段

类的属性

表的一行数据

类的一个实例对象

ORM好处: java程序员只需要在程序中操作对象,因为存在映射关系,自动生成SQL语句。不需要你写sql语句,就可以操作数据库。

允许你以面向对象的方式直接操作sql数据库。

Java中常见的ORM实现(持久层框架):

  • JPA( Java Persistence API).Sun公司的规范,JPA通过JDK 5.0注解或XML描述对象-关系表的映射关系(只有接口规范)
  • Hibernate 最流行ORM框架,通过对象-关系映射配置,可以完全脱离底层SQL(全自动)
  • MyBatis 本是apache的一个开源项目 iBatis,支持普通 SQL查询,存储过程和高级映射的优秀持久层框架(半自动)
  • 其他的持久层框架(非ORM):Apache DBUtils 、Spring JDBCTemplate

【提示】

Jpa是一种规范,里面只有接口,而Hibernate是它的一种实现,那么hibernate必然去实现了jpa中的接口。

使用Jpa的一个好处是,可以更换实现而不必改动太多代码。Hibernate框架是基于JPA接口的实现,但又对其做了一些补充,因此,可以理解为Hibernate中有两套规范(JPA和自己的,事实上只是补充)。

  1. Hibernate能做什么

Hibernate3 第一天

  1. Hibernate的优缺点

优点:

  • Hibernate完全是ORM,自动生成sql语句,完全不需要懂sql,极大简化jdbc的操作。
  • 具有很强的反射和代理机制,生成代理对象,(可以代码增强)在数据获取可以进行延迟抓取、缓存的使用、达到优化的目的。

缺点:

  • hibernate完全orm,自动生成sql,所以很多企业用户对hibernate性能存在质疑(任何持久层框架都不如jdbc速度快,开发效率和性能的平衡)。在hibernate框架中,提供了很多优化手段。
  1. hibernate的快速入门

开发工具:MyEclipse 10.0(自带很多插件)

数据库层面:mysql5

  1. hibernate的jar包下载和导入

    1. 开发包的下载:

百度搜索:

Hibernate3 第一天

Hibernate3 第一天

Hibernate3 第一天

Hibernate3 第一天

本次课程使用3.x系列的经典版本3.6.10

Hibernate3 第一天

【版本使用说明】

框架的版本并不是越高越好,适合的最好;

不同的版本对jdk环境、不同框架的整合方面都有一定要求。

Hibernate开发包内容:

Hibernate3 第一天

另外:Hibernate开发包中只是提供了一个日志接口的包slf4j,并没有提供日志的具体实现,因此,需要额外下载slf4j和log4j的开发包。

Hibernate3 第一天Hibernate3 第一天

  1. Jar包的导入(开发环境的搭建)

新建web工程Hibernate3_day01

Hibernate3 第一天

导入jar包到工程:共个

  • 核心jar:hibernate3.jar
  • 必须jar:\lib\required\*
  • jpa规范jar:\lib\jpa---后面会用到jpa的注解。
  • jdbc驱动包:mysql-connector-java-5.0.8-bin.jar—连接数据库
  • 使用日志系统-slf4j系列(slf4j核心+slf4j和log4j的整合包+log4j)—使用静态日志绑定体系+在src中添加log4j的核心配置文件:log4j.properties

【什么是slf4j】

Hibernate3 第一天

Hibernate3 第一天

slf4j-api只是接口包(解耦合的思想,静态绑定思想),需要日志系统的实现log4j

  • slf4j整合log4j的jar:slf4j-log4j12-1.7.2.jar
  • log4j的开发jar:log4j-1.2.16.jar

【导入完成的包】共11个

Hibernate3 第一天

1

antlr-2.7.6.jar

一个语言转换工具,Hibernate利用它实现HQL到SQL的转换

2

commons-collections-3.1.jar

Collections Apache的工具集,用来增强Java对集合的处理能力

3

dom4j-1.6.1.jar

Xml解析器

4

hibernate3.jar

核心包

5

hibernate-jpa-2.0-api-1.0.1.Final.jar

Jpa接口开发包

6

javassist-3.12.0.GA.jar

代理类生成工具包

7

jta-1.1.jar

标准的JAVA事务处理接口(跨数据库)

8

slf4j-api-1.6.1.jar

简单日志对象包

9

slf4j-log4j12-1.7.2.jar

连接包

10

log4j-1.2.16.jar

Log4j日志实现包

11

mysql-connector-java-5.0.8-bin.jar

mysql驱动包

  1. 基于hibernate实现数据库表CRUD的操作(重点)

    1. 开发准备和配置(三个准备,7个步骤)

【第一个准备】 :创建数据库itcast33,准备数据库的表:

创建数据库:

Hibernate3 第一天

在数据库中建表:

Hibernate3 第一天

创建一个t_customer表,表中设计如下字段:id(编号)、name(姓名)、age(年龄)、city(城市)

Hibernate3 第一天

Hibernate3 第一天

【第二个准备】:编写实体类和ORM映射文件

Hibernate3 第一天

【实体类和映射的编写前需要知道的】

作为ORM框架,

Java和数据库之间的对应关系:类(POJO)--表, 属性--字段,对象--记录,

类就是普通的POJO实体类,必须提供getter和setter方法。

数据类型之间的对应关系:Java实体类、Hibernate、sql之间有数据类型的对应

对应关系:

Hibernate3 第一天

【编写Customer实体类】:

创建名为cn.itcast.a_quickstart包,在包中创建Customer.java类,类中代码如下:

Hibernate3 第一天

【编写hbm(hibernate mapping )映射】:

习惯上,在实体类所在目录,创建类名.hbm.xml的数据表映射配置文件.

—作用,让实体和数据库的具体字段和表进行对应映射。

Hibernate3 第一天

引入dtd的头信息:

Hibernate3 第一天

Hibernate3 第一天

Hibernate3 第一天

<!DOCTYPE hibernate-mapping PUBLIC

"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

配置本地提示:

Hibernate3 第一天

【请注意】在配置完catalog之后,需要重新打开Customer.hbm.xml文件

【编写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>

<!-- 配置java类与表之间的对应关系 -->

<!--

name:类名:类对应的完整的包路径

table:表名

-->

<class name="cn.itcast.a_quickstart.Customer" table="t_customer">

<!-- 配置主键

name:java类中的属性

column:表中的字段,列名,当name和column一致的时候,column可以省略

-->

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

<!-- 主键生成策略

mysql的自增长:identity

-->

<generator class="identity"></generator>

</id>

<!-- 其他属性

name:java中的属性

column:表中字段名

当name和column一致的时候,column可以省略

-->

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

<!-- age :-->

<property name="age"></property>

<property name="city"></property>

</class>

</hibernate-mapping>

【第三个准备】: 配置Hibernate的灵魂文件

编写hibernate核心配置.—jdbc连接数据库、配置hbm映射文件等等

习惯上在src下创建hibernate.cfg.xml(必须叫这个名字,虽然说可以改,但是不建议改)

引入头部信息:

Hibernate3 第一天

Hibernate3 第一天

<!DOCTYPE hibernate-configuration PUBLIC

"-//Hibernate/Hibernate Configuration DTD 3.0//EN"

"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

Hibernate3 第一天

【请注意】需要重新打开hibernate.cfg.xml这个灵魂文件

在hibernate.cfg.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>

<!-- 生产Connection的工厂,hibernate中的session可以直接看成是Connection -->

<session-factory>

<!-- 先配置jdbc需要的四个值 -->

<!-- 驱动 -->

<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>

<!-- URL -->

<property name="hibernate.connection.url">jdbc:mysql:///itcast32</property>

<!-- 用户名 -->

<property name="hibernate.connection.username">root</property>

<!-- 密码 -->

<property name="hibernate.connection.password">123456</property>

<!-- 要告诉hibernate接下来连接那个数据,主要是告知连接的方言 -->

<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>

<!-- 上面的5个配置,可以说是hibernate的最低配置 -->

<property name="hibernate.show_sql">true</property>

<property name="hibernate.format_sql">true</property>

<!-- 配置一个自动建表 -->

<property name="hibernate.hbm2ddl.auto">update</property>

<!-- 读取资源文件

-->

<mapping resource="cn/itcast/a_quickstart/Customer.hbm.xml"/>

</session-factory>

</hibernate-configuration>

【提示1】方言的位置

Hibernate3 第一天

Hibernate3 第一天

【7个步骤】 : java编程实现CRUD,基本示例如下:

Hibernate3 第一天

  1. 保存(插入)数据

在cn.itcast.a_quickstart中创建TestCustomer类,在类中编写testSave方法用来保存数据,代码如下:

@Test

public void testSave(){

//1 加载配置文件:hibernate.cfg.xml

//Configuration().configure() 会自动加载src路径下的hibernate.cfg.xml

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

//2 创建会话工厂:此处的sessionFactory可以理解成ConnectionFactory

SessionFactory sessionFactory = cfg.buildSessionFactory();

//3 创建会话

//这里的session跟jsp九大内置对象的session不是同一个session

//这里的session可以理解为connection,session的底层封装了connection

Session session = sessionFactory.openSession();

//4 开启事务

Transaction tran = session.beginTransaction();

//5 进行CRUD操作:保存操作

Customer customer = new Customer();

customer.setName("rose");

customer.setAge(18);

customer.setCity("上海");

//执行保存操作:save操作的时候,会自动拼装sql语句

session.save(customer);

//6 提交事务

tran.commit();

//7 关闭连接

session.close();

sessionFactory.close();

}

Hibernate3 第一天

当看到控制台打印如下语句的时候,表明所有的配置都是正确的

  1. 修改(更新)数据

更新数据,通过session的update方法

@Test

public void testUpdate(){

//1 加载配置文件

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

//2 创建会话工厂

SessionFactory sessionFactory = cfg.buildSessionFactory();

//3 获取会话

Session session = sessionFactory.openSession();

//4 开启事务

Transaction tran = session.beginTransaction();

//5 执行操作

Customer customer = new Customer();

//更新操作必须设置ID属性

customer.setId(1);

customer.setName("lucy");

//在更新需要注意:由于hibernate执行更新操作,更新的是所有的字段

//所以,不需要更新的字段需要赋值

customer.setCity("上海");

customer.setAge(18);

//操作:底层自动拼装update语句

session.update(customer);

//6 提交事务

tran.commit();

//7 关闭连接

session.close();

sessionFactory.close();

}

Hibernate3 第一天

更新前表中数据:

Hibernate3 第一天

更新后表中数据

Hibernate3 第一天

【补充】:注意update默认会更新所有字段.

Hibernate3 第一天

注意:在使用update的时候,一定要保证属性都有值。没值的会被赋默认值。

  1. 删除数据

删除数据,通过session的delete方法,hibernate的删除是根据主键删除的,所以删除的时候,你必须要传递拥有主键的对象(具有id的对象)

@Test

public void testDelete()

{

// 1 加载灵魂文件

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

// 2 创建会话工厂

SessionFactory sessionFactory = cfg.buildSessionFactory();

// 3 获取连接

Session session = sessionFactory.openSession();

// 4 开启事务

Transaction tran = session.beginTransaction();

// 5 操作:删除

Customer customer = new Customer();

//id必须要设置的

customer.setId(3);

//其余属性没必要

session.delete(customer);

// 6 提交事务

tran.commit();

// 7 关闭连接

session.close();

sessionFactory.close();

}

Hibernate3 第一天

 

【注意】:删除是根据主键删除的,与其他字段没关系

  1. 通过主键来查询数据:

根据主键查找数据,通过session的get或load

@Test

public void testQueryById(){

//1 加载配置文件

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

//2 创建会话工厂

SessionFactory sessionFactory = cfg.buildSessionFactory();

//3 获取会话

Session session = sessionFactory.openSession();

//4 开启事务

Transaction tran = session.beginTransaction();

//5 各种操作

//get:根据主键查询数据

//第一个参数:查询的数据封装的类型

//        Customer customer = (Customer)session.get(Customer.class, 20);

//load:根据主键查询数据,方法参数跟get一致

Customer customer = (Customer)session.load(Customer.class, 20);

//get和load有区别吗?

//区别1 :当主键不存在的时候,get方法直接返回null,load报错

//

System.out.println(customer);

//6 提交事务

tran.commit();

//7 关闭事务

session.close();

sessionFactory.close();

}

【注意点1 】当使用junit单元测试的时候,如果不加@Test,报错:

Hibernate3 第一天

Hibernate3 第一天

当load获取的时候,主键不存在,报错

Hibernate3 第一天

 
  1. 查询所有数据

使用hibernate提供的Query接口来完成,使用HQL(hibernate Query language)语句完成

Hibernate提供了两种查询所有数据的方式

Hibernate3 第一天

Hibernate3 第一天

【提示】为了方便学习,建议大家关联源码,关联方式:

Hibernate3 第一天

采用两种方式查询所有:

@Test

public void testQueryAll(){

//1 加载配置文件

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

//2 创建会话工厂

SessionFactory sessionFactory = cfg.buildSessionFactory();

//3 获取会话

Session session = sessionFactory.openSession();

//4 开启事务

Transaction tran = session.beginTransaction();

//5 各种操作

//方式一:采用HQL语句查询所有?何为HQL,类似sql

//但是在HQL中缩写的内容要么是类,要么是类中的属性,不能写跟表相关的内容

//HQL是面向对象的查询语句

//        Query query = session.createQuery("from Customer");

//查询

//        List<Customer> list = query.list();

//方式二:继续采用SQL查询所有

SQLQuery sqlQuery = session.createSQLQuery("select * from t_customer");

//sqlQuery查出来的对象是数组类型,所以要转成Customer对象

//在使用SQLQuery查询之前,一定先封装实体(addEntity),再查询

List list = sqlQuery.addEntity(Customer.class).list();

System.out.println(list);

//6 提交事务

tran.commit();

//7 关闭事务

session.close();

sessionFactory.close();

}

hql执行的查询语句

Hibernate3 第一天

Sql执行的查询语句

Hibernate3 第一天

  1. hibernate的基本运行流程分析(图解)

Hibernate3 第一天

  1. hibernate核心配置(灵魂配置)

    1. Hibernate的基本体系结构

Hibernate3 第一天

通过上面的体系结构图得知:应用程序通过持久化对象(po)间接的完成对数据库的操作(crud)。

持久化对象(persistent object),简写为PO,这里就是Customer这个实体类

  1. Hibernate核心配置文件分类

Hibernate框架支持properties和xml两种方式的Hibernate属性的配置,对应的两种核心配置文件为:

  • hibernate.properties 配置常用的属性,必须手动编程加载hbm文件或持久化类。(了解)
  • hibernate.cfg.xml配置常用的属性,配置加载hbm映射,配置缓存策略等。(推荐)

【提示】配置Hibernate的属性很多,可以参考hibernate解压包的project/etc/hibernate.properties。

Hibernate3 第一天

  1. hibernate.properties配置示例(了解)

目的:通过properties格式配置最小化的hibernate属性(连接和方言)

【配置示例】

hibernate.properties:

hibernate.connection.driver_class com.mysql.jdnc.Driver

hibernate.connection.url jdbc:mysql:///itcast32

hibernate.connection.username root

hibernate.dialect org.hibernate.dialect.MySQL5Dialect

Hibernate3 第一天

提示:上述配置是Hibernate的最小化配置。

【注意】使用hibernate.properties文件的时候,一定知道,这种配置的缺陷是:无法动态的加载*.hbm.xml文件

,正是因为这种缺陷,导致了这种配置方式基本不用,那如果使用这种方式,未来项目中,如何加载配置文件呢?

答:在代码中手动的加载

【示例测试】

建立包:cn.itcast.b_corecfg,创建类TestCoreCFG类

@Test

public void testCoreConfigProperties(){

//1 加载配置文件

//读取hibernate.properties属性文件

Configuration cfg = new Configuration();

//手动读取hbm文件

cfg.addResource("cn/itcast/a_quickstart/Customer.hbm.xml");

//2 创建会话工厂

SessionFactory sessionFactory = cfg.buildSessionFactory();

//3 获取会话

Session session = sessionFactory.openSession();

//4 开启事务

Transaction tran = session.beginTransaction();

//5 各种操作

List<Customer> list = session.createQuery("from Customer").list();

System.out.println(list);

//6 提交事务

tran.commit();

//7 关闭事务

session.close();

sessionFactory.close();

}

打印结果,由于没有配置show_sql,所以说,不会显示sql语句

Hibernate3 第一天

【提示】

properties方式,主要缺点:不能配置加载hbm映射文件,因此后面都使用xml的方式进行配置和使用。

【思考】

如果两个配置文件都存在,hibernate会加载使用哪个?

new Configuration();只加载properties文件

Configuration configuration = new Configuration().configure();会先加载properties文件,再加载cfg.xml文件。

Hibernate3 第一天

后加载的会覆盖先加载的属性的值

Hibernate3 第一天

  1. hibernate.cfg.xml配置示例+框架常用属性

    1. 数据库连接参数和数据库方言

connection连接参数、数据库方言的配置

Hibernate3 第一天

方言是用来将实体类的映射转换为不同数据库的sql的一种配置策略.

操作hibernate必须配置的5个属性—最小化配置

方言:

Hibernate3 第一天

【了解】

在配置hibernate.cfg.xml时,hibernate属性:hibernate.dialect中的"hibernate"可以省略.

  1. 连接池

  • Hibernate默认连接池(了解):

默认情况下,我们有没有用连接池呢?

查看日志发现Hibernate使用了一个默认的连接池:

Hibernate3 第一天

【提示】

不建议在生产环境使用。

默认的连接池大小配置(了解):

Hibernate3 第一天

  • c3p0连接池的配置:---生产环境

Hibernate3 第一天

更换C3P0的连接池:

【第一步】解压目录的lib中

Hibernate3 第一天

导入c3p0的jar

【第二步】配置更改连接池提供者(插件机制,可以随时换,可插拔)

Hibernate3 第一天

切换到c3p0连接池:

Hibernate3 第一天

准备代码:

@Test

public void testConnectionPool(){

//1 加载配置文件

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

//2 创建会话工厂

SessionFactory sessionFactory = cfg.buildSessionFactory();

//3 获取连接

Session session = sessionFactory.openSession();

//4 开启事务

Transaction transaction = session.beginTransaction();

//5 查询所有操作

Query query = session.createQuery("from Customer");

List<Customer> list = query.list();

System.out.println(list);

//6 提交事务

transaction.commit();

//7 关闭连接

session.close();

sessionFactory.close();

}

再次执行查看结果:

Hibernate3 第一天

【报错的原因】没有导入C3P0的jar包:直接去项目中找项目导入

Jar包的位置

Hibernate3 第一天

在运行,就OK啦

Hibernate3 第一天

  1. 控制台打印sql

Hibernate3 第一天

建议在测试环境下,都将sql打开,便于调试。

Hibernate3 第一天

Hibernate3 第一天

  1. 自动建表

该配置是让hibernate是否自动建立相应的表。也就是说,你数据库可以没有表,hibernate可以自动给你建立一个。

Hibernate3 第一天

  • create-drop:在程序运行时,(创建session工厂的时候)会自动建表,在程序停止时(关闭sessionFactory时),表删除

如何证明 create-drop的功能?

直接使用debug的方式,断点查看

Hibernate3 第一天

第一步,观察表是否创建成功(标志:原先的表被删除,数据丢失)

第二步,实现保存操作,观察表中是否有数据

第三步,程序运行结束,观察表是否被删除

编写建表的代码:

@Test

public void testSave(){

//1 加载配置文件

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

//2 创建会话工厂

SessionFactory sessionFactory = cfg.buildSessionFactory();

//3 获取连接: 此处的session可以看成是Connection

Session session = sessionFactory.openSession();

//4 开启事务

Transaction transaction = session.beginTransaction();

//5 各种CRUD 操作

//准备数据

Customer customer = new Customer();

customer.setName("jack");

customer.setAge(18);

customer.setCity("北京");

//保存

session.save(customer);

//6 提交事务

transaction.commit();

//7 关闭连接

session.close();

sessionFactory.close();

}

  • create:在程序运行时,如果表不存在,自动建表,如果存在,则不进行任何操作(mysql会先删除再创建)

Hibernate3 第一天

  • update:在程序运行时,如果表不存在,自动建表,如果表存在,则检查表和类的结构是否一致,如果不一致,则更新表结构.(推荐)

update:

Hibernate3 第一天

Hibernate3 第一天

Hibernate3 第一天

如果当表中的字段比配置文件多的时候,那么表中多的字段,hibernate将无法维护。(因为没有映射)

  • validate:在程序运行时,如果表结构和类不一致,则报错!(表中没有相应的字段,则报错,表中有冗余字段,不报错)

Hibernate3 第一天

【自动建表小结】

Hibernate3 第一天

  1. jdbc的其他相关设置(不建议使用,了解)

Hibernate3 第一天

我们发现,在使用hibernate的时候,都需要手动提交事务,原因是hibernate默认是关闭自动提交事务功能的。

所以我们需要手动提交。

如果开启自动提交功能呢,当前,也只有mysql支持,oracle不支持

@Test

public void testSave(){

//1 加载配置文件

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

//2 创建会话工厂

SessionFactory sessionFactory = cfg.buildSessionFactory();

//3 获取回话

Session session = sessionFactory.openSession();

//4 开启事务

//        Transaction tran = session.beginTransaction();

//5 操作

Customer customer = new Customer();

customer.setName("rose");

customer.setAge(19);

customer.setCity("北京");

session.save(customer);

//6 提交事务

//        tran.commit();

//7 关闭连接

session.close();

sessionFactory.close();

}

【扩展1】

没有提交的事务,数据库中这条记录是否存在?(默认情况下,是不会存在的,数据只是暂时的在内存中存在过)

【扩展2】

oracle默认是false,即使改成true也没效果!

Hibernate3 第一天

原因:Oracle不支持自动提交事务,不能自动提交(Oracle数据库必须手动提交,即使你在hibernate中设置了自动提交,也没用。),但msyql是可以自动提交的.

  1. Hibernate核心API

    1. 概述

Hibernate3 第一天

通过该体系结构图,可以看到Hibernate的核心API接口,它们之间的关系:

Hibernate通过Configuration来读取核心配置文件,SessionFactory缓存配置并用来提供Session,而Session是用来操作PO的,让Hibernate生成crud的sql语句,在操作过程中使用Transaction来管理事务。Query和Criteria是Hibernate提供的查询的两种不同方式。

下面详解:

  1. Configuration配置对象

作用:加载Hibernate的相关配置(Hibernate.cfg.xml配置\Hibernate.properties配置[不支持配置hbm映射])

第一种:加载Hibernate.cfg.xml

Configuration configuration=new Configuration().configure();//加载默认src类路径的hibernate.cfg.xml

也可以加载其他命名的配置文件new Configuration().configure("文件路径");

Hibernate3 第一天

第二种:加载Hibernate.properties

Configuration configuration=new Configuration();//加载默认的Hibernate.properties

需要手动加载hbm映射

configuration.addResource(xxx.hbm.xml)

  1. SessionFactory会话工厂

作用:用来缓存一些配置和数据的

可以缓存:

  • Hibernate常用属性(包括连接池)
  • hbm类和数据表映射信息
  • 预定义SQL语句(命名查询语句)
  • 二级缓存

获取SessionFactory的方式: configuration.buildSessionFacotry()获取对象

【提示】

SessionFactory是线程安全的.即当多个线程访问同一个SessionFactory是不存在线程问题的。构造SessionFactory很消耗资源,一般情况下,一个应用(项目)只需要初始化一个,即操作一个全局的SessionFactory对象。

SessionFactory和Session的关系有点像连接池和连接的关系,我们操作数据库时主要使用的连接和session,连接池和SessionFactory只需要创建后从里面获取连接和session即可。

【练习示例】

创建包:cn.itcast.utils,抽取HibernateUtils来提供Session对象。

package cn.itcast.utils;

import org.hibernate.Session;

import org.hibernate.SessionFactory;

import org.hibernate.cfg.Configuration;

public class HibernateUtils {

private static SessionFactory sessionFactory;

//在静态块中加载SessionFactory

static{

sessionFactory = new Configuration().configure().buildSessionFactory();

//关闭:系统停止运行的时候关闭

//JVM停止运行的时候:为JVM增加一个监听事件, 在JVM停止工作的时候,关闭sessionFactory

//addShutdownHook:添加关闭事件

Runtime.getRuntime().addShutdownHook(new Thread(){

@Override

public void run() {

sessionFactory.close();

System.out.println("sessionFactory关闭了....");

}

});

}

//获得连接工厂

public static SessionFactory getSessionFactory(){

return sessionFactory;

}

//获得连接

public static Session openSession(){

return sessionFactory.openSession();

}

}

创建包:cn.itcast.c_coreapi,在包中创建类:TestCoreAPI,使用工具类来进行操作数据(查询示例):

@Test

public void createTable(){

//自动建表

HibernateUtils.getSessionFactory();

}

@Test

public void testSave(){

//1 获取连接

Session session = HibernateUtils.openSession();

//2 开启事务

Transaction tran = session.beginTransaction();

//3 操作

Customer customer = new Customer();

customer.setName("jack");

customer.setAge(11);

customer.setCity("上海");

session.save(customer);

//4 提交事务

tran.commit();

//5 关闭连接

session.close();

}

  1. session会话

Session是hibernate的核心,所有的CRUD操作都要依靠session完成。

作用:Session对象相当于JDBC的Connection,主要用于操作数据的(CRUD)。
但是功能比Connection强大NN倍,

Session底层封装了Connection

  • 其内部实际上也确实持久化了一个Connection对象,即一个Session对应一个Connection。
  • Session是应用程序与数据库之间交互操作的一个单线程对象,是Hibernate的运作中心。
  • Session是线程不安全的。

【问题】:如何解决Session线程不安全问题?

不要将Session定义为成员变量,只在方法中的局部变量使用.

(方法内部为什么不存在线程安全问题:用的私有栈空间,不存在线程共享问题)

(每个方法使用栈空间是线程私有空间,不存在多线程并发问题)

Hibernate3 第一天

另外:Session还提供了一级缓存和持久化对象的常用操作。

Session的常用方法:

Hibernate3 第一天

Hibernate3 第一天

  1. Transaction事务

hibernate默认不自动提交事务,而且oracle数据库也不支持自动提交事务,所以我们推荐,每次都手动提交事务

作用:用于事务的管理(提交或回滚等)

常用操作:

Hibernate3 第一天

代码中操作事务:

@Test

public
void testTransaction(){

//获取连接

Session session = HibernateUtils.openSession();

//开启事务

//        Transaction transaction = session.beginTransaction();

//开启事务的方式二

session.beginTransaction();

Customer customer = new Customer();

customer.setName("rose");

customer.setAge(18);

customer.setCity("上海");

session.save(customer);

//         /提交事务

//        transaction.commit();

session.getTransaction().commit();

//关闭连接

session.close();

}

【注意】

如果没有手动开启事务,那么每个Session的操作,都相当于一个独立的事务。

默认情况下,JDBC的事务是自动提交的,而hibernate的事务默认是不提交的,但可以通过配置Hibernate3 第一天的值为true,变成自动事务提交(mysql)

Hibernate3 第一天

【思考题面试题】:

问题:数据库中保存了几条数据?

Hibernate3 第一天

【分析】运行结果是啥?

分情况讨论

如果是oracle,0条

如果是mysql,开启了自动事务提交,1条

没有开启自动事务提交,0条

  1. Query查询接口

作用:Query对象主要用于执行查询操作。

Query接口用于接收HQl语句执行查询。

HQL是Hibernate Query Language缩写,语法很像SQL语法,但是完全面向对象的。

Hibernate3 第一天

Hibernate为照顾和兼容原生的SQL,Hibernate提供了Query的子接口SqlQuery来执行SQL语句,用法和query接口的一样。

【示例】

通过Query接口执行查询,分别查询所有数据列表、根据条件查询一条数据(分别不使用和使用占位符)、...

@Test

public
void testQuery(){

Session session = HibernateUtils.openSession();

session.beginTransaction();

//HQL

//        /方式一

//        List<Customer> list = session.createQuery("from Customer").list();

//方式二:返回的结果是多条的时候,使用list

//        List<Customer> list = session.createQuery("select c from Customer c ").list();

//根据条件查询 方式一(查询name=rose的客户的信息),返回的结果是0条或者1条用uniqueResult

//        Customer customer = (Customer) session.createQuery("from Customer where name = 'rose'").uniqueResult();

//根据条件查询 方式二:匿名的方式注入参数

//        Customer customer = (Customer) session.createQuery("from Customer where name = ?")

//                    .setString(0, "rose").uniqueResult();

//根据条件查询 方式三:匿名的方式注入参数

//        Customer customer = (Customer) session.createQuery("from Customer where name = ?")

//                    .setParameter(0, "rose").uniqueResult();

//        /根据条件你查下方式四:命名的方式注入参数

//        Customer customer = (Customer) session.createQuery("from Customer where name = :name")

//                    .setString("name", "rose").uniqueResult();

//根据条件查询方式五

//        Customer customer = (Customer) session.createQuery("from Customer where name = :name")

//                .setParameter("name", "rose").uniqueResult();

//        System.out.println(list);

//SQL

//条件查询方式一

//        Customer customer = (Customer) session.createSQLQuery("select * from t_customer where name = ?")

//                    .addEntity(Customer.class).setString(0, "rose").uniqueResult();

//方式二

//        Customer customer = (Customer) session.createSQLQuery("select * from t_customer where name = ?")

//                .addEntity(Customer.class).setParameter(0, "rose").uniqueResult();

//方式三:命名的方式

//        Customer customer = (Customer) session.createSQLQuery("select * from t_customer where name = :name")

//                .addEntity(Customer.class).setString("name", "rose").uniqueResult();

//方式四:命名的方式

Customer customer = (Customer) session.createSQLQuery("select * from t_customer where name = :name")

.addEntity(Customer.class).setParameter("name", "rose").uniqueResult();

System.out.println(customer);

session.getTransaction().commit();

session.close();

}

【注意】

SqlQuery.list 默认是生成的object[],必须使用Hibernate3 第一天绑定实体后,Hibernate才会将结果自动封装成实体对象。

  1. Criteria查询接口

作用:用于执行查询操作。

特点:完全面向对象的方式添加条件,不需要写hql或sql

Hibernate3 第一天

【示例】

使用Criteria接口对象执行查询,分别查询所有数据列表、根据条件查询一条数据

@Test

public
void
testCriteria(){

Session session = HibernateUtils.openSession();

session.beginTransaction();

//创建Criteria

//        Criteria criteria = session.createCriteria(Customer.class);

//        /查询所有

//        List list = criteria.list();

//        System.out.println(list);

//根据条件查询rose

Criteria criteria = session.createCriteria(Customer.class);

//加条件

criteria.add(Restrictions.eq("name", "rose"));

//拼命的加条件

criteria.add(Restrictions.eq("age", 19));

//...

//执行

Customer customer = (Customer) criteria.uniqueResult();

System.out.println(customer);

session.getTransaction().commit();

session.close();

}

  1. 小结回顾

常用的Hibernate核心API:

  • Configuration核心配置对象,用来加载Hibernate配置文件,用来创建会话工厂
  • SessionFactory 会话工厂,用来创建Hibernate会话Session,缓存了一些配置。(连接池等)
  • Session 会话,相当于一个数据库连接(持久了一个connection),进行数据库表CRUD操作,它是hibernate的运作核心。
  • Transaction 事务,对操作进行事务管理
  • Query查询接口,接收HQL语句,子接口SQLQuery接受sql语句
  • Criteria条件查询(QBC:query by Criteria),完全面向对象方式进行多条件的组合查询,无需关心sql的写法。
  1. 持久化对象PO

    1. 理解持久化对象PO

      1. PO对象是什么

全称:Persistent Object。

持久化(Persistence),即把数据(内存中的对象)保存到可永久保存的存储设备中(如硬盘)。

持久化的主要应用是将内存中的对象存储在关系型的数据库中,当然也可以存储在磁盘文件中、XML数据文件中等等

Hibernate3 第一天

  1. 编写规则

POJO:一个干净(没有父类、没有接口的一个类)的类

在hibernate中pojo=po(其他技术中有没有po这个概念?没有。Po是持久化对象,而hibernate正好是持久化的框架)

PO类的要求如下

  • 必须提供一个public的空参构造器
  • 提供一个标识,与数据库的主键进行对应
  • 所有的私有属性都要有getter和setter方法
  • 属性的类型建议使用包装类型
  • PO类一定不能使用final关键字修饰(如果使用final修饰,将无法生成代理子对象)

【示例】修改Customer类,具体代码如下:

Hibernate3 第一天

  1. 属性类型的问题讨论

问题思考:PO属性的数据类型使用包装类型还是原始类型?

【场景模拟阅读】

学生考试:

全部答错

根本就没来

double:全部答错0分,没来 0分 , 87分

Double:全部答错 0分,没来null , 87分

//需求:有个表存放学生的分数,假如有个人没有参加考试,那么这个分数的字段该是什么值?这个字段值是0还是null合适呢?看需求,但用null更合适.

基本数据类型double默认值是0,Double默认值是null

//如果说,使用基本的数据类型,则,无法通过这个字段来区分是否参加了考试(假如有个人考试了但是0分.)。假如要求参加考试的学生必须有分数,而没参加考试的学生没有分数(为空),double无法识别了。一般我们都用包装类

尽量使用包装类型,不要使用原始类型

  1. 理解OID-持久化对象的唯一标识

    1. 什么是OID

OID(Object identifier),即对象标识,用来标识唯一对象的,因此,OID在PO中被称为持久化对象的唯一标识。

Hibernate3 第一天

Hibernate框架根据OID标识,是否为同一个对象

【扩展知识】

在关系数据库中,主键用来识别记录,并保证每条记录的唯一性。数据库中的主键最重要的3个基本要素就是不允许为null,不允许有重复值,主键永远不会改变. 所以通常我们设计表都会设计主键的值为自动增加,没有业务逻辑含义的一组数字,当然针对每个数据库,设置的方法也不同.

在Java语言中,通过比较两个变量所引用对象的内存地址是否相同,或者比较两变量引用的对象是否相等。

Hibernate为了解决两者之间的不同,使用对象标识符(OID)来标识对象的唯一性。OID是关系数据库中主键在Java对象模型中的等价物。在运行时,Hibernate根据OID来维持Java对象和数据库中的对应关系。

OID具有唯一性和不变性,一般是由HIBERNATE或数据库来给其赋值。

OID(Object ID)应当没有任何业务相关含义,OID绝对不应当具有任何业务含义。

/**

* 什么样的对象,hibernate在操作的时候,会认为是同一个对象?

*/

public
void testSame()

{

//java中如何判断是否是同一个对象的?

//判断hashcode

Customer customer = new Customer();

customer.setId(1);

customer.setName("rose");

customer.setAge(18);

customer.setCity("北京");

Customer customer1 = new Customer();

customer1.setId(1);//OID

customer1.setName("rose1");

customer1.setAge(181);

customer1.setCity("北京1");

//在java中,customer和customer1肯定不是同一个对象

//但是在Hibernate比较同一个对象的方式,是比较OID,如果OID一致,他们就是同一个对象

//Customer 和Customer1的OID一致吗?一致,所以hibernate会把这两个对象认为是同一个对象

}

【总结】

Po:持久化对象,在本章中,就是指Customer

Po的唯一标识叫OID

  1. hbm映射配置详解

    1. 准备工作(全天复习)

目标:建立PO和hbm映射(加入到核心配置文件中)、建表(构建工厂)。

创建包:cn.itcast.d_hbm,在包中创建Book的po类:

Hibernate3 第一天

建立hbm映射文件:

Hibernate3 第一天

填充基本的映射文件内容:

<?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>

<!-- 配置java类和表之间的映射

name:java类对饮的完整的包路径

table:表名

-->

<class
name="cn.itcast.d_hbm.Book"
table="t_book">

<!-- 主键 -->

<id
name="id">

<!-- 主键生成策略 -->

<generator
class="identity"></generator>

</id>

<!-- 配置其他属性 -->

<property
name="name"></property>

<property
name="price"></property>

</class>

</hibernate-mapping>

加载hbm映射

<!-- 配置hbm映射文件 -->

<mapping
resource="cn/itcast/d_hbm/Book.hbm.xml"/>

建表测试:

@Test

//建表测试

publicvoid createTabele(){

HibernateUtils.getSessionFactory();

}

  1. class元素

作用:指定类与表的映射,用来映射表的一些属性。

Hibernate3 第一天

  • name:类名
  • table:表名,table也是可以省略的,如果省略,那么表名就是类名
  1. id元素

作用:主键策略,设定持久化类的OID和表主键的映射

Hibernate3 第一天

属性:

  • name: 标识持久化类 OID 的属性名
  • column: 设置标识属性所映射的数据列的列名(主键字段的名字),可省略。
  • length:字段的长度,如果不指定,则使用数据库字段的默认最大长度。
  • type:指定Hibernate 映射类型. Hibernate 映射类型是 Java 类型与 SQL 类型的桥梁。如果没有为某个属性显式设定映射类型, Hibernate 会运用反射机制先识别出持久化类的特定属性的 Java 类型, 然后自动使用与之对应的默认的 Hibernate 映射类型。

    Java 的基本数据类型和包装类型对应相同的 Hibernate 映射类型. 基本数据类型无法表达 null, 所以对于持久化类的 OID 推荐使用包装类型(integer,long,string等)。

Hibernate3 第一天

Hibernate3 第一天

  1. generator元素

作用:持久化类的标识符(OID)生成器,用来指定主键的生成策略。

Hibernate3 第一天

【主键策略知识】

数据库主键分为两种:代理主键和自然主键。

两者的区别为:

  • 代理主键:不具有业务含义的字段作为主键的,---例如自增长id,uuid(在数据库的设计中,推荐使用不具备实际意义的字段作为主键)
  • 自然主键:具有业务含义的字段作为主键的, ---例如订单编号(有些表的设计中订单编号是有规则.2015011002998)

两者的选择:企业开发中,会根据业务需要选择,但使用代理主键居多。

属性:

  • class属性:指定使用的标识符生成器全限定类名或其缩写名。

Hibernate3 第一天

选择:最常用的:native,其次:identity,sequence,uuid,assigned

  1. native

标识符生成器依据底层数据库对自动生成标识符的支持能力, 底层其实自动选择使用 identity, sequence 标识符生成器.

如果数据库 mysql ---- identity

如果数据库 oracle ---- sequence (hibernate 会自动创建一个新的序列)

Hibernate3 第一天

  1. Identity--mysql演示

切换到mysql: (前提是要导入mysql的jar包)

Hibernate3 第一天

依赖数据表底层自增长,用于DB2, Mysql, MSSQLServer, Sybase

创建表后,生成的sql:

Hibernate3 第一天

【主键的生成时机】

在mysql中:在保存的时候,直接发出sql语句,抢占主键,而此时数据库中是没有数据的,

如果没有提交呢,这个主键直接废弃,接下来如果继续完成保存操作并提交,这时候,主键已经越过了

在oracle中:由于oracle的主键生成策略跟mysql不一样,所以,oracle在commit的时候,才会发出sql语句,去抢占主键

【示例代码】

@Test

public
void testSave(){

Session session = HibernateUtils.openSession();

session.beginTransaction();

Book book = new Book();

book.setName("九阴真经");

book.setPrice(9.9d);

//对于mysql而言,在save的时候就会发出sql语句,抢占主键

//而oracle,只有当commit的时候,才会发出sql语句 (两个数据库生成主键的方式不同 )

session.save(book);

session.getTransaction().commit();

session.close();

}

插入数据:

Hibernate3 第一天

采取抢占的形式进行id的赋值。测试.

  1. sequence—oracle演示

依赖于底层数据库,采用序列的机制,主要用于oracle,db2等。

可以指定自定义的序列;

Hibernate3 第一天

修改策略:

Hibernate3 第一天

测试:

Hibernate3 第一天

结果:

Hibernate3 第一天

经过测试,使用了自定义的序列。

如果不指定自定义的序列,会使用默认的序列(hibernate生成)

  1. Increment(不科学)

由hibernate来生成OID和维护的,原理是select max(id) +1

如果数据表中没有数据,则初始的时候,hibernate给值是1,再次给值2

Hibernate3 第一天

表主键没有自增长了

问题:如果手动将主键值改大了,会如何?

Hibernate3 第一天

再次保存会:

Hibernate3 第一天

适用场景:

Hibernate3 第一天

问题:可能出现多线程冲突问题,两个线程同时查询max(id),同时+1 ,insert

Hibernate3 第一天

Hibernate3 第一天

  1. uuid

用于String类型,生成代理主键,采用uuid (32位)作为主键值

Hibernate会产生不重复的32位字符串作为主键

【示例】

增加一个string类型的字段:

Hibernate3 第一天

更改映射的主键:

Hibernate3 第一天

Hibernate3 第一天

  1. Assigned

唯一的一个自然主键设置方式,手动设置主键的值。

Hibernate3 第一天

Hibernate3 第一天

如果不指定会出现:

Hibernate3 第一天

错误如下:

Hibernate3 第一天

指定示例:

Hibernate3 第一天

Hibernate3 第一天

  1. 小结

Hibernate3 第一天

  1. property元素

作用:配置非主键的属性和表字段的映射

属性(和id元素一样):

  • name:类中属性名
  • column: 设置标识属性所映射的数据列的列名(字段的名字),可省略。
  • length:字段的长度,如果不指定,则使用数据库字段的默认最大长度。
  • type:指定Hibernate 映射类型. Hibernate 映射类型是 Java 类型与 SQL 类型的桥梁。如果没有为某个属性显式设定映射类型, Hibernate 会运用反射机制先识别出持久化类的特定属性的 Java 类型, 然后自动使用与之对应的默认的 Hibernate 映射类型。

    Java 的基本数据类型和包装类型对应相同的 Hibernate 映射类型. 基本数据类型无法表达 null, 所以对于持久化类的 OID 推荐使用包装类型(integer,long,string等)。

另外了解:也可以使用子元素<column>来配置数据库中的字段类型(不推荐):

Hibernate3 第一天

【扩展】type:字段类型(是hibernate类型):扩展(如果想写数据库类型,则需要子元素column:)

Hibernate3 第一天

  1. 其他:jee6的bean校验错误

如果你用myeclise2014版本的时候,默认建立的web工程是用jee6,那么在运行hibernate的时候,会报错:bean校验的错误.

Hibernate3 第一天

解决方案:在核心配置文件(hibernate.cfg.xml)中,配置一个阻止bean校验的一个属性

Hibernate3 第一天

<!-- 阻止bean校验 -->

<property
name="javax.persistence.validation.mode">none</property>

Hibernate3 第一天

Hibernate3 第一天

  1. 小结+重点

Hibernate3 第一天

  1. 作业

【作业一】

课程中的快速入门,即基本的增删改查(CRUD),写一遍。

【作业二】

编写一个登录小程序。

业务逻辑:页面输入用户名和密码,在后台验证,是否在数据库中存在,如果存在,则提示登录成功,否则,提示登录失败。

技术要点:将以前的练习中的dbutil改造为Hibernate,用Hibernate作为dao(持久层)的技术与数据库打交道。

参考步骤:

  1. 搭建环境:导入hb的jar,核心配置文件,工具类
  2. 编写PO和hbm映射
  3. 直接在程序中编写crud