Hibernate 第 一 天
1 hibernate基本原理
1) 为什么使用hibernate?
a hibernate属于 M(模型层),与jdbc相同,都是对数据库的操作
b hibernate是对jdbc的封装,底层依然是jdbc
c hibernate是ORM框架,O--->Object(实体类对象) R--->Relational(表) M --->Mapping(映射)
hibernate就是用面向对象的方式,来操作数据库简化程序员的开发
d hibernate也叫持久层框架
e 市场上能占到40%左右
f hibernate因为底层封装jdbc,性能相比jdbc稍弱--------------------------------》(*缺点面试时说)
2 简要介绍一下hibernate3.2文件
1) doc :hibernate3.2的说明文档,包含hibernate的Api(全英文版)
2) eg:hibernate官方提供的案例,包含User.hbm.xml
(映射文件:实体类跟数据库表关联桥梁)
4) etc:hibernate中所有的配置,其中最重要hibernate.cfg.xml
(hibernate核心配置文件,hibernate运行必要的文件),包括一些缓存文件ehcache.xml
4 ) lib :跟hibernate有关所有的第3方jar
5 ) src : hibernate所有的源代码,开源框架
6 ) hibernate3.jar:hibernate核心jar
归纳hibernate特点:
(1) 简单(对于程序员)
(2) 开源
(3) orm框架,持久层(M)框架
(4) 可以兼容现在所有主流的数据库
(5) 完全面向对象
(6) 性能不好
3 使用hibernate的步骤
2) 导入jar:hibernate_lib(共16个)
2) 导入核心配置文件:hibernate.cfg.xml,连接到数据库
(在hibernate-3.2.4.ga\hibernate-3.2\etc下有hibernate.cfg.xml)
A:eclipse连接数据库:**(jdbc:mysql://localhost:3306/zhanghao?useUnicode=true&characterEncoding=utf8)
B:配置hibernate.cfg.xml,
4) 创建Po类以及修改orm映射文件
A:创建po类
B:在hibernate-3.2.4.ga\hibernate-3.2\里搜:XXX.hbm.xml,放在po类中。
C:修改映射文件
D;把orm映射文件,加载到hibernate.cfg.xml中
4) 使用hibernate的Api操作
跳转至下面:3) Configuration
案例: 使用hibernate来创建一张表
t_user
主键
id name age pwd
User.hbm.xml(ORM映射文件)
class User{
private int id;
private String name;
private int age;
private String pwd;
//get、set
}
po类的属性,必须跟要创建的表的列一致
4 hibernate核心
1)hibernate.cfg.xml:
a 连接数据库:Driver ,url,用户名, 密码dialect(方言) : 通过配置方言可以帮我们操作任何数据库,
底层对数据库的操作的sql语句,会自动转化对应数据库的sql
b hibernate自身的属性:
show_sql:把hibernate底层执行jdbc的sql语句,打印控制台上,使用hibernate必须配置该属性
c 配置ORM映射文件:hibernate执行的时候,会读取hibernate.cfg.xml文件 ,只有把orm映射文件配置到hibernate.cfg.xml,才能加载到hibernate当中
2) ORM映射文件(注意看提示{指eclipse自带的提示}):
po类跟数据库中表,之间映射的桥梁
<class name="com.tarena.po.User" table="t_user">
<id name="id">//hibernate当中默认主键最重要
//generator :主键生成策略
identity:每次添加新的数据,主键自动加1
<generator class="identity"></generator>
</id>
<!-- 配置一般属性信息 -->
<property name="name"></property>
<property name="age"></property>
<property name="pwd"></property>
3) Configuration (上接4) 使用hibernate的Api操作)
a) 读取配置文件
hibernate.cfg.xml (核心配置文件)
xxx.hbm.xml (映射文件)
b) hibernate程序只要一启动,立刻就会调用
Configuration读取文件
执行Main方法,如果异常提示:
Exception in thread "main" org.hibernate.MappingException: Cannot cache an unknown entity: org.hibernate.test.legacy.Simple
可能是此处错误:将其从核心配置文件:hibernate.cfg.xml删除
4) SessionFactory
重量级对象(资源):大量侵占内存资源,功能强大
a)创建Session (SessionFactory是产生Session的工厂)
b)管理hibernate二级缓存(以后讲)
c)一个项目对应/一个数据库中对应一个SessionFactory,生命周期很长,跟整个系统生命周期一致
5) Session:
Hibernate当中最核心的(功能)类,hibernate对数据库中都依赖Session来实现的
a) Session:可以实现增删查改
b)session的生命周期较短,代表一个用户对数据库访问的一个连接
c)每次对数据库的操作都要使用session,(最好能把session跟当前访问用户绑定在一起)
6)Transaction:
hibernate中管理事务:
Hibernate的事务是手动提交的,必须要开启事务,并提交才可以改变表中的数据
jdbc 自动的提交事务:关闭jdbc自动提交方法
5 使用hibernate来实现增删查改
1) load 与get
a) load 去数据库查询一个不存在的数据,会直接抛出一个异常(ObjectNotFoundException)
get去数据库查询一个不存在的数据,会返回一个null值对象;
b)load方法支持延迟加载,当访问该对象的属性,才发出sql对数据库查询
get方法不支持延迟加载,使用get方法立刻发出sql语句,去数据库中查询
2) 延迟加载:需要才发出sql,去数据库中查询
3) hibernate底层怎么实现延迟加载的/load返回对象是什么类型的?
Emp emp = (Emp) session.load(Emp.class, 1);
a) load返回的对象,不是emp对象,没有去数据库中真实查询,所以没有发出sql语句
b)load返回的是一个代理对象(代替要查询的对象叫做代理对象),该代理对象来暂时代替emp对象
c) 该代理对象是目标对象的子类对象
(该子类对象是hibernate内部自动生成,跟我们无关)
eg: class Student extends Person{}
Person person = new Student();
d) 这是代理模式:cglib动态代理,能提高hibernate性能,减少对数据库的访问次数
案例:hibernate_day01Pm
创建一张员工表t_emp
id name age birthday salary
实现增删查改,全部使用hibernate
package com.tarena.test;
import java.util.Date;
import org.hibernate.Session;
import org.junit.Test;
import com.tarena.po.Emp;
import com.tarena.util.HibernateUtils;
public class SessionTest {
//保存emp到数据库中
@Test
public void testSave(){
Session session = null;
try {
session = HibernateUtils.getSession();
// 开启事务
session.beginTransaction();//使用session直接开启事务
Emp emp = new Emp();
emp.setName("liu");
emp.setAge(29);
emp.setBirthday(new Date());
emp.setSalary(100000.0);
session.save(emp);
// session.getTransaction().commit():
// 获得开启事务Transaction对象,然后commit(提交)
// 如果保存没有提交事务的话,在控制台会发出sql
// 语句,但数据库中没有该数据,而且主键自动增1
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally{
HibernateUtils.closeSession(session);
}
}
// 查询id = 1的数据
// 1 查询一个数据库中,不存在的数据
// 会返回一个nulll
@Test
public void testGet1(){
Session session = null;
try {
session = HibernateUtils.getSession();
//session.get(类名.class,主键的值):返回的结果是
// Object类型的对象,需强制类型转化
Emp emp = (Emp)session.get(Emp.class, 300);
System.out.println(emp);
// System.out.println(emp.getName()+" , "+emp.getSalary());
} catch (Exception e) {
e.printStackTrace();
} finally{
HibernateUtils.closeSession(session);
}
}
// 判断 get()什么时候发出sql语句
@Test
public void testGet2(){
Session session = null;
try {
session = HibernateUtils.getSession();
// 发出sql:当调用get方法立刻对数据库发出sql,
// 做出查询操作
Emp emp = (Emp) session.get(Emp.class, 1);
System.out.println("---------------------------");
System.out.println(emp.getAge());
} catch (Exception e) {
e.printStackTrace();
} finally{
HibernateUtils.closeSession(session);
}
}
// load什么时候发出的sql
@Test
public void testLoad2(){
Session session = null;
try {
session= HibernateUtils.getSession();
Emp emp = (Emp) session.load(Emp.class, 1);
System.out.println("--------------------------------");
//发出sql语句:因为load支持延迟加载(需要才去
// 发出sql语句,访问数据库),load返回的emp
// 是hibernate通过cglib代理返回Emp类的子类对象
// 只有当我们真实去访问该对象的属性的时候,
// 该代理对象才发出sql语句,去访问数据库
System.out.println(emp.getAge());
System.out.println("-------------------------------");
} catch (Exception e) {
e.printStackTrace();
} finally{
HibernateUtils.closeSession(session);
}
}
// select emp0_.id as id0_0_, emp0_.name as name0_0_, emp0_.age as age0_0_, emp0_.birthday as birthday0_0_, emp0_.salary as salary0_0_ from t_emp emp0_ where emp0_.id=?
// 使用load,也是用来查询对象
// 1 使用load查询一个数据库中,不存在的数据
// 抛出ObjectNotFoundException:对象没有找到
@Test
public void testLoad1(){
Session session = null;
try {
session = HibernateUtils.getSession();
Emp emp = (Emp) session.load(Emp.class, 100);
System.out.println(emp.getAge()+" , "+emp.getName());
} catch (Exception e) {
e.printStackTrace();
} finally{
HibernateUtils.closeSession(session);
}
}
// 删除
@Test
public void testDelete1(){
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Emp emp =(Emp) session.load(Emp.class, 3);
session.delete(emp);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally{
HibernateUtils.closeSession(session);
}
}
// 生成对象,然后把该对象id属性设为要删除数据库
// 数据主键
@Test
public void testDelete2(){
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Emp emp = new Emp();
emp.setId(1);
session.delete(emp);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally{
HibernateUtils.closeSession(session);
}
}
// 修改,最好使用load/get,把要修改的数据,从数据库
// 先查询出来,然后再调用update(obj)
// 可以修改需要修改的信息,而且可以保存原有信息
@Test
public void testUpdate1(){
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
// 最好使用先load/get,然后再update
Emp emp = (Emp) session.load(Emp.class, 1);
// Emp emp = new Emp();
// 尽量不要使用,因为凡是没有修改信息,全部设为
// 0或null
// emp.setId(1);
emp.setName("gaoyuanyuan");
emp.setAge(35);
session.update(emp);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally{
HibernateUtils.closeSession(session);
}
}
}