1、Hibernate
1、简介
- 基于ORM
2、基本使用步骤
1、引入Hibernate核心jar包
- Hibernate3.jar+required目录中所有+jpa+数据库驱动包
2、配置文件hibernate.cfg.xml
jdbc:mysql:///hib_demo
com.mysql.jdbc.Driver
root
root
org.hibernate.dialect.MySQLDialect
3、配置映射文件(xxx.hbm.xml)
4、测试类
// 对象
Users users = new Users();
users.setUserName("Jack");
users.setAge(30);
// 1. 创建配置管理器对象
Configuration config = new Configuration();
// 2. 加载主配置文件, 默认加载src/hibernate.cfg.xml
config.configure();
// 3. 根据加载的主配置文件,创建对象
SessionFactory sf = config.buildSessionFactory();
// 4. 创建Session对象
Session session = sf.openSession();
// 5. 开启事务
Transaction tx = session.beginTransaction();
// --- 保存
session.save(users);
// 6. 提交事务/关闭session
tx.commit();
session.close();
3、Hibernate Api
1、Session
一个与数据库连接的会话信息, Sesison里面维护了一个连接对象,且对常用操作进行封装。
-
保存对象
session.save(obj);
-
主键查询
Users u = (Users) session.get(Users.class, 1);//查询的主键不存在,返回null 或Session.load(clazz,id); //查询的主键不存在只要使用就报错
-
删除
Object obj = session.get(Users.class, 21); if (obj != null) { session.delete(obj); }
-
修改
Users u = new Users(); u.setUserId(30000); //主键一定要在数据库存在 u.setAge(30); session.update(u);
-
保存或更新
Users u = new Users(); u.setUserId(5); u.setUserName("Jacky001"); session.saveOrUpdate(u);//如果有设置主键且主键存在执行更新
-
HQL查询
// 得到hql查询接口 Query q = session.createQuery("from Users"); // 查询数据 List
list = q.list(); -
criteria 查询 ,完全面向对象的查询
// 获取Criteria接口 Criteria c = session.createCriteria(Users.class); // 设置条件 c.add(Restrictions.eq("userName", "Jacky001")); List
list = c.list();
4、hibernate.cfg.xml配置详解
1、查看配置提示
- hibernate-distribution-3.6.0.Final\project\etc\hibernate.properties
2、自动建表
-
配置方式
true update #hibernate.hbm2ddl.auto create-drop 每次在创建sessionFactory的时候创建表,执行sf.close()删除表。 #hibernate.hbm2ddl.auto create 每次都先删除表,再创建新的表 #hibernate.hbm2ddl.auto update 如果表不存在则创建,存在就不创建! #hibernate.hbm2ddl.auto validate 检查映射配置与数据库结构是否一致,不一致就报错! (严格) -
代码方式
// 创建配置管理器对象,加载主配置文件(会加载映射) Configuration cfg = new Configuration().configure(); // 自动建表工具类 SchemaExport export = new SchemaExport(cfg); // 创建表 // 第一个参数: 是否打印建表语句到控制台 // 第二个参数: 是否执行脚本,生成表 export.create(true, true);
5、映射配置
1、映射文件
命名:*.hbm.xml
作用: 描述“对象”与“表”的映射关系,通过映射文件可以描述一张完整的表。
-
配置详解
6、联合主键映射
1、步骤
-
联合主键对象
public class CompositeKeys implements Serializable{ private String name; private String address; }
-
bean
// 员工 public class Employee { // 联合主键对象 private CompositeKeys keys; private String dept; private Date birth; .. }
-
Employee的映射
7、hibernate对象状态
1、临时状态
- 直接new出来的对象
- 不处于session的管理(即没有与任何一个session关联)
- 对象在数据库中没有对应的记录
2、持久化状态
- 处于session的管理范围,当执行session的方法如:save/update/saveOrUpdate/get/load对象就会自动转变为持久化状态
- 在数据库中有对应的记录
- 处于持久化状态的对象,当对对象属性进行更改的时候,提交事务更改会反映到数据库中
3、游离状态
- 对象不处于session的管理范围,通常指session关闭后对象的状态
- 对象在数据库中有对应的记录
4、转化实例
Session session = sf.openSession();
session.beginTransaction();
// 创建对象 【临时状态】
Employee emp = new Employee();
emp.setName("Rose");
emp.setBirth(new Date());
// 保存
session.save(emp); // 【持久化状态】
emp.setName("Lucy.."); // 修改会反映到数据库中,所以这里会生成update语句
session.getTransaction().commit();
session.close();
emp.setName("New Lucy");
System.out.println(emp.getName()); // 此时对象处于【游离状态】
8、 Session缓存
1、概念
- Session缓存,也叫做一级缓存;
- 当执行session的相关方法,如: save()/update()/get()/load()等方法的时候,对象会自动放入一级缓存中;
- 当Session关闭后,一级缓存内容失效。
2、特点
- 缓存有效范围,只在当前session范围内有效,缓存时间很短、作用范围小;
- 一级缓存,可以在短时间内多次操作数据库的时候,才会明显提升效率;
- 一级缓存的结构:Ma<主键,对象>;
- 在提交事务时候,Hibernate会同步缓存数据到数据库中,会对比缓存数据与数据库数据是否一致,如果不一致,才提交更改到数据库(生成update);
- hibernate提供的一级缓存有hibernate自身维护,如果想操作一级缓存内容,必须通过hibernate提供的方法:
session.flush(): 手动让让一级缓存内容与数据库同步
session.evict(emp1): 清空一级缓存中对象,清除指定的对象
session.clear(); 清空所有缓存
9、list()与iterator()查询区别
1、list(通常使用频率较高)
- Query接口定义的list查询方法,一次查询所有满足需要的数据。
2、iterator
- Query接口定义的iterator查询方法,先查询所有满足条件记录的主键 (查询1次)
再根据每一个id,进行主键查询,有多少记录,查询多少次 (查询n次) - iterator查询,迭代数据的时候,只有用到数据的时候,才会查找数据库(懒加载)
3、区别
- 查询数据方式不同: 查询全部与查询N+1
- 一级缓存
List查询,查询的结果会放入一级缓存,但不会从一级缓存中获取;
Iteraotro查询,会放入一级缓存,同时也会从一级缓存中获取。
10、lazy 属性
1、懒加载
- 用到数据的时候,才向数据库发送查询的sql;
2、懒加载异常(org.hibernate.LazyInitializationException: could not initialize proxy - no Session)
-
在关闭后,不能能懒加载数据, 那么就要求关闭前把懒加载使用的数据先查询出来:
Session session = sf.openSession(); session.beginTransaction(); // 懒加载 Employee emp = (Employee) session.load(Employee.class, 1); /* * 解决懒加载异常: * Session关闭后,不能使用懒加载数据! * (1) 在session关闭之前,先使用一次数据; 那么session关闭后再使用对象数据,就不是懒加载数据了 * (2) 强迫代理对象初始化 * */ //emp.getName(); // select ... Hibernate.initialize(emp); session.getTransaction().commit(); session.close(); System.out.println(emp.getName()); // 不是懒加载数据, 因为数据已经查询出来啦
11、关系映射
1、集合
-
set/list/map
-
多对一
public class Address { private int id; private String name; private String shortName; private String code; // 地址与用户, 是多对一的关系 private Users user; … }
-
一对多
public class Users { private int id; private String name; private int age; // 用户与地址,是一对多的关系 【注意一定要用接口接收!】 private Set address = new HashSet(); }
-
Inverse属性
-
多对多
-
一对一
idCard -
组件映射
-
继承映射
-
hql
12、二级缓存
1、特点
- 基于应用程序的缓存、基于sessionFactory级别的缓存;
- 缓存数据可以被多个session共享,但需要指定哪些对象要放入二级缓存中;
- 放入二级缓存中对象的特点:经常使用、不会被经常修改。
2、步骤
-
hibernate.cfg.xml中配置
开启二级缓存
true 指定使用哪一种二级缓存org.hibernate.cache.HashtableCacheProvider 开启查询缓存true 加入二级缓存的类集合缓存 (集合缓存,集合元素也要放入二级缓存)
3、缓存策略
- usage="read-write" 二级缓存的数据可以读、写
- usage="read-only" 二级缓存的数据只读
- usage="nonstrict-read-write" 非严格读取
- usage="transactional" 基于事务的策略
4、hql 查询缓存
Dept dept = null;
/*
* Session1:
*/
Session session1 = sf.openSession();
session1.beginTransaction();
// hql 查询
Query q = session1.createQuery("from Dept").setCacheable(true);// 放入二级缓存或者从二级缓存中获取
q.list();
session1.getTransaction().commit();
session1.close();
System.out.println("===============================");
/*
* Session2:
*/
Session session2 = sf.openSession();
session2.beginTransaction();
// hql 查询
q = session2.createQuery("from Dept").setCacheable(true); // 放入二级缓存或者从二级缓存中获取
q.list();
session2.getTransaction().commit();
session2.close();
5、 更新数据
- 不会通知一级缓存,会通知二级缓存;
13、连接池
1、Hibernate对连接的支持
- 查看hibernate.properties,hibernate.connection.pool_size 1,hibernate自带的连接池,只有一个连接
2、hibernate对C3p0连接池的支持
org.hibernate.connection.C3P0ConnectionProvider
6
4
2
100
3000
14、创建Session的两种方式
1、方式1
- 每次都创建一个新的session
Session session1 = sf.openSession();
Session session2 = sf.openSession();
System.out.println(session1 == session2); // false
2、方式2
-
线程的方式创建session
thread Session session3 = sf.getCurrentSession(); Session session4 = sf.getCurrentSession(); System.out.println(session3 == session4); // true