Hibernate笔记
来源:互联网 发布:sql数据库管理工具 编辑:程序博客网 时间:2024/06/03 04:42
Hibernate框架的优势与适用场景
优点:
1. 它是纯面向对象的持久化技术,不用使用者会SQL,用纯面向对象的接口去操作数据。
2. Hibernate是一个ORM(Object Relation Mapping)持久化技术。
3. Hibernate它提供了数据缓存技术,而且不止一个缓存(一级缓存、二级缓存、查询缓存)。
4. Hibernate持久化技术可以跨数据库,它是通过方言来解决这个问题的。
缺点:
1. 性能问题,因为SQL是Hibernate生成的,我们无法控制SQL的生成,但数据库性能优化的一个非常重要的的手段就是通过优化SQL来完成的。比如:
select * from employee where id in (1, 2, 3);
Select * from employee where id = 1 or id = 2 or id = 3;
Select * from employee where id between 1 and 3;
Select * from employee where id = 1 union
Select * from employee where id = 2 union
Select * from employee where id = 3
适用场景:
1. Hibernate适用于中小型项目。
2. 不适用项目中存在大量的表与表之间特别复杂的关系。
3. 对性能要求很高的项目。
Hibernate的开发环境搭建
1. 把Hibernate的相关的jar包导入项目中的classpath.
antlr-2.7.6.jar
asm-1.5.3.jar
asm-attrs-1.5.3.jar
backport-util-concurrent.jar
cglib-2.1_3.jar
commons-collections-2.1.1.jar
commons-logging-1.0.4.jar
dom4j-1.6.1.jar
ehcache-1.5.0.jar
ejb3-persistence-1.0.1.GA.jar
hibernate-3.2.6.ga.jar
hibernate-annotations-3.3.1.GA.jar
hibernate-commons-annotations-3.0.0.ga.jar
jta-1.0.1B.jar
mysql-connector-java-5.1.10-bin.jar
mysql-connector-java-5.1.10.jar
2. Hibernate开发的三要素
a) 配置文本件:配置的是数据库连接、配置Hibernate特性功能、配置ORM配置文件的路径. hibernate.cfg.xml
1、数据库的链接信息
<propertyname="hibernate.connection.username">root</property>
<propertyname="hibernate.connection.password">123456</property>
<propertyname="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<propertyname="hibernate.connection.url">jdbc:mysql://localhost:3306/privatesecretary</hibernate>
2、动态生成表
<propertyname="hbm2ddl.auto">update</property>
create:表示启动的时候先drop,再create (测试人员 准备标准测试数据)
create-drop:也表示创建,只不过再系统关闭前执行一下drop (测试程序是否正确)
update: 这个操作启动的时候会去检查schema是否一致,如果不一致会做scheme更新 (建表,更新表结构【只能加】)
validate:启动时验证现有schema与你配置的hibernate是否一致,如果不一致就抛出异常,并不做更新
3、引入映射文件
<mappingresource="com/voole/vo/Role.hbm.xml" />
4、输出SQL语句
<property name="show_sql">true</property>
5、格式化SQL语句
<propertyname="format_sql">true</property>
6、方言
<propertyname="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
6、关于二级缓存的配置
<propertyname="cache.use_second_level_cache">true</property>
<propertyname="cache.provider_class">
org.hibernate.cache.EhCacheProvider
</property>
7、关于查询缓存的配置
<propertyname="cache.use_query_cache">true</property>
8、统计机制
<propertyname="hibernate.generate_statistics">true</property>
9、从当前线程中产生session
<propertyname="current_session_context_class">thread</property>
b) ORM配置文件:配置对象与表的映射关系 javabean的名称.hbm.xml.
1. 如果java的属性名与表中的字段名不匹配时我们可以通过如下方式来解决:
<property name=”name” column=”t_name”>
2. Java属性的类型与表中字段的类型的映射,如果不指定类型映射那么Hibernate会用反射机制来自动根据一定的规则去匹配(参考 官方文档 92页)
3. 配置表的一些约束非空约束 长度约束
not-null="true"length="23"
4. 主键生成策略
在<id>元素中 通过 <generator class="生成策略"></generator> 指定数据表主键生成策略
常用六种主键生成策略
1) increment
increment标识符生成器由 Hibernate以递增的方式为代理主键赋值
原理:select max(id), insert max(id)+1
*使用 increment创建数据表 没有主键自增长, 通过hibernate在程序内部完成自增
*好处跨平台 ,缺点 高并发访问时,可以出现主键冲突问题
2) identity(无线程问题)---- Mysql
identity标识符生成器由底层数据库来负责生成标识符,它要求底层数据库把主键定义为自动增长字段类型
原理: 依赖数据库内部自增长,和hibernate无关
*创建数据表 `id` int(11) NOT NULLAUTO_INCREMENT
*优点,无需程序处理,数据库自己完成主键增长,缺点 Mysql支持 自增主键, oracle 不支持
3) sequence --- Oracle
sequence 标识符生成器利用底层数据库提供的序列来生成标识符
原理: 依赖数据库序列支持 ,和hibernate程序无关
* Oracle支持序列, Mysql不支持序列
4) native
native标识符生成器依据底层数据库对自动生成标识符的支持能力,来选择使用 identity, sequence 或 hilo 标识符生成器.
* Mysql自动选择 identity,oracle 自动选择 sequence
5) uuid
uuid的主键生成,采用String类型主键
随机生成32位字符串
6) assigned
assigned是自然主键生成策略 ----必须用户在程序中指定 (无法自动生成)
c) javaBean
1. 在写javabean时一定要保证javabean中有oid(对应表中的主键)
2. 尽写成员变量时不要用基本类型,要用对应的包装类型
3. Javabean这个类不要用final去修饰,因为hibernate有个延迟加载的功能(动态代理cglib)。
4. Javabean一定要有一个默认无参的构造方法。
3. 把log4j.properties放到classpath中
4. 编写Hibernate的持久化代码。
publicvoid test(){ // 1.新增配置文件对象,此对象是用来读取Hibernate的配置文件, //默认是放在classpath根据目录 //名字为hibernate.cfg.xml Configuration config =new Configuration().configure(); // 2.通过configuration对象再创建SessionFactory对象 SessionFactorysessinFactory = config.buildSessionFactory(); // 3.通过SessionFactory对象创建Session Session session =sessinFactory.openSession(); // 4.利用session开启事务 Transaction t =session.beginTransaction(); try { // 5.创建一个Student对象并初始化 Student student =new Student(); student.setAge(18); student.setName("张三"); // 6.调用session的save方法把数据存到数据库的表中 session.save(student); // 7.提交事务 t.commit(); }catch (Exception e) { e.printStackTrace(); t.rollback(); }finally{ // 8.释放资源 session.close(); sessinFactory.close(); } }
Hibernate所涉及的主要类
Configuration
l 它是专门读取Hibernate配置文件与映射文件的类,它是SessionFactory对象的工厂,这个类是单例的,在你的项目中这个类只能产生一个对象,这个类是线程安全的。
SessionFactory
l sessionFactory这个对象中存放了Hibernate配置信息、存放了映射配置信息、二级缓存,这个类的对象是重量级的(建立这个对象需要大量的资源,非常耗时),所这个对象不能随便去创建,这个类的对象是进程级别的,这个对象也是单例的,这个对象是产生session对象的工厂。
Session
l Session对象是专门用于操作数据库(CRUD),此对象中包含着Hibernate的一级缓存,这个对象是每次操作数据库都实例化的,这个对象不是线程安全的
Transaction
l Transaction对象是对事务进行操作的,例如:事务的提交、事务的回滚、事务的开始。
Hibernate中的Session有两种获取方式:
1. 通过sessionFactory.openSession(); 每次调用此方法都创建一个新的session, 用此方法获取的session用完之后要调用session.close()方法释放资源。
2. 通过sessionFactory.getCurrentSession(); 为每个线程创建一个新的session,用此方法获取的session用完之后,只要事务提交后那个session会自释放,不用我们显示调session.close();
注意:要使用getCurrentSession()必须在配置文件中加以下配置:
<propertyname="current_session_context_class">thread</property>
Hibernate的数据懒加载
org.hibernate.LazyInitializationException
如何解决这个问题呢?(三种解决方案)
1. 在session没关闭之前,用Hibernate.initialize(懒加载的对象)进行显示初始化。(只能处理单个对象懒加载,不能处理集合)
2. 改变查询策略,也就是说用立即加载load --> get iterator -- list
*设置为立即加载lazy=false (缺点,每次查询客户,都要查询订单,性能问题)
3. OpenSessionInView (session不随事务关闭而关闭,将session生命周期延长到表现层View层)
将Session开到表现层 --------- 存在性能问题,通过配置Filter,无需编程
做法: 在struts2过滤器前,配置OpenSessionInViewFilter
HQL与SQL区别
SQL是数据库查询语言,它面向是数据库中的表与表中的列。
HQL是对象查询言,它面向的是类与类中的属性。
持久化对象的状态
* transient瞬时态(临时态、自由态) : 不存在持久化标识OID,尚未与Hibernate Session关联对象,被认为处于瞬时态,失去引用将被JVM回收
OID就是 对象中 与数据库主键 映射 属性 ,例如 Customer类 id 属性
* persistent持久态 : 存在持久化标识OID,与当前session有关联,并且相关联的session没有关闭 ,并且事务未提交
* detached脱管态(离线态、游离态) : 存在持久化标识OID,但没有与当前session关联,脱管状态改变hibernate不能检测到
Session中一级缓存
案例一: 证明一级缓存是存在的
* 生成一条SQL语句,返回同一个对象 ,第一次查询生成SQL,查询对象,将对象放入一级缓存,第二次查询,直接从一级缓存获得
Session session = HibernateUtils.getSession(); Transaction t =session.beginTransaction(); Student s1 =(Student)session.get(Student.class, 4); Students2 =(Student)session.get(Student.class, 4); Students3 =(Student)session.get(Student.class, 5); //统计一级缓存中持久化对象的数量 System.out.println(session.getStatistics().getEntityCount()); session.evict(s1); System.out.println(session.getStatistics().getEntityCount()); t.commit();
案例二 : 测试Hibernate快照 (深入理解一级缓存 内存结构原理 )
hibernate向一级缓存放入数据时,同时保存快照数据(数据库备份),当修改一级缓存数据,在flush操作时,对比缓存和快照,
如果不一致,自动更新 (将缓存的内容 同步到数据库, 更新快照)
* 快照区使用,在Session保存一份 与数据库 相同的数据 ,在session的 flush时, 通过快照区 比较得知 一级缓存数据是否改变,如果改变执行对应操作 (update)
* Hibernate中 持久态 对象具有自动更新数据库能力 (持久态对象 才保存在 Session中,才有快照 )
Session session = HibernateUtils.getSession(); Transaction t =session.beginTransaction(); Student s1 =(Student)session.get(Student.class, 4); s1.setAge(888); t.commit();
注意:使用Query查询它会只向一级缓存中放数据,不会在一级缓存中取数据。
Hibernate查询方式
1. session.get session.load 这种查询方式只能通过主键查询一条记录。
2. HQL 通过HQL查询要用到Query这个类
1. 单表查询
session.createQuery(“from Student”).list();
2. 按条件查询
Query query = session.createQuery(“from Student where name = ?”); query.setParameter(0, “zx”); Query query1 = session.createQuery("from Student where name =:name"); query1.setParameter("name", "zx");
3. 投影查询
Query query = session.createQuery("select name, age fromStudent"); List<Object[]>list = (List<Object[]>)query.list(); for(Object[] item : list){ System.out.println("姓名:" + item[0] + " 年龄" + item[1]); } Query query =session.createQuery("select new Student(name, age) from Student"); List<Student>list = (List<Student>)query.list(); for(Student item : list){ System.out.println("姓名:" + item.getName() + " 年龄" + item.getAge()); }
注意:在提供有参构造方法的同时别忘了再提供一个无参的构造方法
4. 分组查询
Query query = session.createQuery("select count(*) from Studentgroup by clazz"); List<Long> list = query.list(); for (Long item : list){ System.out.println("学生人数:" + item); }
5. 连接查询(left join, right join, inner join)
1. 迫切: 在连接关键字后面加fetch (推荐)
2. 非迫切: 不加
区别: 迫切的把查询结果封装成了主表对应的对象,通过主表的对象可以通过关联方法导航到子表的对象的数据。
非迫切的是以object数组的形式返回的,数组中的第一元素是主表中的对象,第二元素是子表中的对象。
用本地SQL查询
Session session = HibernateUtils.getSession(); Transactiont = session.beginTransaction(); List<Object[]>list =session.createSQLQuery("select *from t_student").list(); t.commit();
Hibernate的二级缓存
Hibernate的二级缓存的生命周期是和SessionFactory一样的。二缓存默认是关闭,而且二级缓存不是Hibernate实现,需要第三方的缓存插件来支持
二级缓存的开启步骤:
在hibernate.cfg.xml文件中
<!-- 开启二级缓存 --> <property name="cache.use_second_level_cache">true</property> <propertyname="cache.provider_class">org.hibernate.cache.EhCacheProvider</property> <!-- 开启hibernate的统计机制 --> <propertyname="hibernate.generate_statistics">true</property>
加入相关缓存的jar包
- Hibernate笔记
- Hibernate 笔记
- Hibernate笔记
- Hibernate笔记
- Hibernate笔记
- hibernate笔记
- Hibernate笔记
- Hibernate笔记
- hibernate笔记
- hibernate笔记
- Hibernate笔记
- hibernate 笔记
- Hibernate笔记
- Hibernate笔记
- Hibernate 笔记
- Hibernate 笔记
- Hibernate 笔记
- Hibernate笔记
- sphinx4的Microphone
- 使用cuda-gdb调试cu程序
- 1877: [SDOI2009]晨跑
- java中的反射简单理解
- bat删除指定时间之前文件
- Hibernate笔记
- 简单制作进度条,圆弧
- Java实现机器人的运动范围
- 关于Android的一些杂项
- jpg/png/psd/tiff图片格式详解
- TensorFlow实战:手写数字识别之K近邻
- 2017上半年总结
- volatile关键字解析
- PHP中String类型