Hibernate的学习笔记
Hibernate的核心类和接口
一.Hibernate是什么?
1. Hibernate是一个框架(framework)
2.Hibernate是一个o(object)r(relation)m(mapping)框架
3.Hibernate处于项目的持久层(所以有人将其称为持久层框架)
4.Hibernate实际上就是将jdbc进行了轻量级的封装
5.Hibernate的基础还是java的反射机制
6.Hibernate可以用在j2ee和j2se项目中,但是Struts是web层框架,所以他只能用在j2ee项目中
总结:Hibernate是对jdbc进行轻量级封装的orm框架,处于项目的持久层位置。
二.为什么需要Hibernate?
三.Hibernate的三种开发方式:
1.由Domain object->mapping->db。(官方推荐)
2.由db开始,用工具生成mapping和Domain object。(使用较多)(建议domain类的首字母大写和表的名字对应 )
3.由映射文件开始。
什么是pojo?
在使用Hibernate的时候,要求数据局的某张表相互映射的那个java类,是一个pojo类,一般放在com.xxx.domain包下,pojo类翻译过来就是:简繁的就java对象(plain ordinary java objects)实际上就是普通的Javabeans,使用pojo名称是为了避免个ejb混淆起来。一个pojo类应该具有:
1.有一个主键属性,用于唯一标示该对象。(这就是为什么Hibernate的设计者建议要映射的表需要一个主键)
2.有其他的属性
3.有对各个属性操作的get/set方法。
4.属性一般是private修饰。
5.一定有一个无参的构造函数(用于Hibernate框架的反射用)。
Hibernate的配置文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<!-- 映射文件需要一个dtd文件 来指定格式 -->
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.liheng.domain">
<class name = "Employee" table = "employee">
<!-- id元素用于指定主键属性 -->
<id name = "id" column="id" type="java.lang.Integer">
<!-- 该元素用于指定主键生成策略 hilo native increment sequence uuid-->
<!-- <generator class="sequence">
<param name="sequence">id</param>
</generator> -->
<generator class="increment"></generator>
</id>
<!-- 对其他属性进行配置 -->
<property name="name" type="java.lang.String">
<column name="name" not-null="false"></column>
</property>
<property name="email" type="java.lang.String">
<column name="email" not-null="false"/>
</property>
<property name="hiredate" type="java.util.Date">
<column name="hiredate" not-null="false"></column>
</property>
</class>
</hibernate-mapping>
Hibernate的增删改:
public static void delEmp() {
//删除
Session session = MySessionFactory.getSessionFactory().openSession();
Transaction ts = session.beginTransaction();
//删除1.现获取该雇员 然后删除
Employee emp = (Employee) session.load(Employee.class, 1);
session.delete(emp);
ts.commit();
session.close();
}
public static void updateEmp() {
//修改用户
//创建configuaration
//创建会话工厂 这是一个重量级的对象 应当保证sessionFactory是单态的
Session session = MySessionFactory.getSessionFactory().openSession();
Transaction ts = session.beginTransaction();
//修改用户1 获取要修改的用户 , 2 修改
//load是通过主键属性,获取该对象实例 与表的记录对应
Employee emp = (Employee) session.load(Employee.class, 1);
emp.setName("zhangsan");//update
ts.commit();
session.close();
}
public static void addEmployee() {
//我么使用Hibernate完成srud操作 这里我们只键对象,不见表
//现在不使用service 直接测试
//1.创建configration 该对象用来读取Hibernate.cfg.xml文件,并完成初始化
Configuration configuration = new Configuration().configure();
//2.创建sessionfactory 这是一个会话工厂 是一个重量级对象
SessionFactory sessionFactory = configuration.buildSessionFactory();
//创建Session 相当于jdbc的connection
Session session = sessionFactory.openSession();
//对于Hibernate来说要求程序员 在进行 增加 删除 修改 时候用事务提交
Transaction transaction = session.beginTransaction();
//添加一个雇员
Employee employee = new Employee();
employee.setName("liheng");
employee.setEmail("liheng216.sina.com");
employee.setHiredate(new Date());
//insert...保存
session.save(employee);//对应insert into 。。。
transaction.commit();
session.close();
}
1.configuration类
它的用处是:
- 读取Hibernate.cfg.xml文件
- 管理对象关系映射文件<mapping resource ="">
- 加载Hibernate的驱动,url,用户。。。
- 管理配置信息
2.Hibernate.cfg.xml配置文件
3.对象关系映射文件
4.sessionFactory(会话工厂)
- 缓存sql语句和某些数据(称为session级缓存)
- 是一份重量级的类,因此,我们需要保证一个数据库有一个SessionFactory
- 通过SessionFactory接口可以获得Session(会话)实例
这里讨论一个
SessionFactory接口可以获得Session的两个方法,openSession()和getCurrentSession();
1.
openSession()是获取一个新的session
Session s1 = MySessionFactory.getSessionFactory().openSession();
Session s2 = MySessionFactory.getSessionFactory().openSession();
//输出hashcode
System.out.println("s1 =" + s1.hashCode() +" "+"s2=" + s2.hashCode() );
s1 =7858936 s2=14900151
2.
getCurrentSession()
获取和当前线程绑定的session,换言之,在同一个线程中,我们获取的session是同一个session,这样可以利于事务处理。如果希望使用
getCurrentSession() 需要配置Hibernate.cfg.xml中配置
Session s1 = MySessionFactory.getSessionFactory().getCurrentSession();
Session s2 = MySessionFactory.getSessionFactory().getCurrentSession();
//输出hashcode
System.out.println("s1 =" + s1.hashCode() +" "+"s2=" + s2.hashCode() );
s1 =1673653 s2=1673653
3如何选择:
原则:
- 如果在同一线程中,保证使用同一个Session,则使用getCurrentSession()
- 如果在一个线程中需要使用不同的Session,则使用openSession()
4.两种方式的不同
5.如果是getCurrentSession()获取session,进行查询需要事务提交。
6.jta
5.如果是getCurrentSession()获取session,进行查询需要事务提交。
6.jta
7.Session(会话)接口
- session一个实例代表与数据库的一次操作(当然一次操作可以是crud组合)
- session实例同过sessionFactory获取,用完需要关闭
- session是线程不同步的(不安全),因此要保证在同一线程中使用,可以用getCurrentSession()
- Session可以看做是持久化管理器,它是与持久化操作的接口
4.通过修改配置文件我们可以修改懒加载。
<
class name = "Employee" lazy="true" table = "employee"
>
Hibernate的缓存的介绍:
分两级 主要作用:减少用户对数据库的操作
query接口:
通过query接口我们可以完成更为复杂的操作
Session session = HibernateUtil.getCurrentSession();
Transaction ts = null;
try {
ts = session.beginTransaction();
//获取一个query借口引用 这里的Employee不是表而是domain类名 where后面的是类的成员变量
Query query = session.createQuery("from Employee where id = 2");
//通过list方法获取结果
//原来使用jdbc二次封装的工作就没有了
List<Employee> list = query.list();
for (Employee e :list) {
System.err.println(e.getName());
}
ts.commit();
} catch (Exception e) {
if (ts !=null) {
ts.rollback();
}
throw new RuntimeException(e.getMessage());
}finally{
//关闭session
if (session != null && session.isOpen()) {
session.close();
}
}
HQL(Hibernate query language)语句
模拟创建三张表:
--建立学生表
create table student
(sid number primary key , --这是学生的学号
sname varchar2(45) not null, --学生姓名
ssex char(2) not null,--性别
sdept varchar2(10) not null, --所在系
sage number(3) ,--年龄
saddress varchar2(45) --住址
)
create table course
(
cid number primary key ,--这是课程号
cname varchar2(50) not null,--课程名
ccredit number(3) --课程学分
)
--建立选课表
create table studCourse
(
stuCourseId number primary key ,--这是一个自增的,表示一次选课
sid number references student(sid),--学生号
cid number references course(cid),--课程号
grade number not null--成绩
)
Hibernate的设计者在我们设计表的时候,应当每张表都有一个主键,而且该主键最好不包含任何的业务逻辑。
使用Hibernate工具,自动生成domain和映射文件,如果我们的表有主外键的关系应当先映射主表再映射从表。
Hibernate对象的三种关系:
1.one-to-one:人和身份证的关系;
2.one-to-many:部门和员工的关系;
3.many-to-one:员工和部门;
4.many-to-many:学生和老师;
Hibernate对象的三种状态:
瞬时态:不处于session的管理之下,在数据库中没有对应的记录。超过作用域就会被jvm回收,一般是new出来的并且与session没有关联的对象。
持久态:在session的管理之下,在数据库中有对应的记录,相关联的session没有关闭,事务没有提交。持久对象的状态发生变化,在事务提交时会影响到数据库(Hibernate能检测到)。
脱管态/游离态:没有处于session的管理之下,在数据库中有对应的记录。托管状态发生改变,Hibernate不能检测到。
懒加载:
简述:当我们查询一个对象的时候,在默认情况下返回的只是该对象的普通属性,当用户使用对象属性时,才会向数据库再一次发出查询,这种现象我们称之为懒(lazy)加载现象。
三种解决方法:
1.显式初始化 Hibernate initized(代理对象)
2.修改对象关系文件 lazy 改写 lazy = false
3.通过过滤器(web项目)openSessionInView
一个内部留言本的项目
在jsp页面中获取当前的项目名可以:
<%= this.getServletContext().getContextPath()%>
通过标签:${pageContext.request.contextPath}
Hibernate的缓存
为什么需要缓存?
一级缓存(session级缓存)
1.什么操作会向一级缓存里面放进东西?
2.是么操作会从一级缓存取数据?
get/load/list
get/load会首先从一级缓存中取。如果没有,再有 不同的操作【get 会立即向数据库发请求,而load会返回一个代理对象,直到用户真的去使用数据,才会向数据库发请求】
3.一级缓存不需要配置,就可以使用,它本身没有保护机制,所以我们程序员要考虑这个问题,
二级缓存(sessionFactory级缓存):
为什么需要二级缓存?
因为一级缓存有限,还有一级缓存的生命周期很短,所以我们需要二级缓存来弥补这个问题。
1.二级缓存需要配置
2.二级缓存需要交给第三方处理
3.二级缓存的对象可能放到内存中,也可能放到磁盘上。
Hibernate最佳实践:
对于数据量大,性能要求高的系统,不太使用Hibernate
主要用于事务操作比较多的项目。(oa/某个行业软件【石油、税务、crm、财务系统】)