hibernate知识点总


本文所有内容都有源码介绍,在资料中很详细

1、谈到hibernate,我们首先来看下百度百科的定义

Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,

是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。

由此我们知道hibernate是对java三层架构dao层的分装,谈到对jdbc的操作,无不就是这几个知识点,然后掌握其实现及其原理,随着经验的曾加,

对细节理解的也会越来越透彻

hibernate有哪些知识点呢首先是缓存一级缓存,二级缓存,查询缓存,懒加载。

一级缓存无需配置,通过session的Person person = (Person)session.get(Person.class, 1L);即可将数据放入到一级缓存

另外还有些方法也可以session.save(person); session.delete(person);session.update(person);等。

清空一级缓存的方法有session.clear();session.evict(person);

最后一级缓存的生命周期是session级别的,session.close(),关闭时,自然而然一级缓存不存在了。

同时我们在这里还谈到一个知识点,

持久化状态

理解 :当一个对象被持久化时,他们的状态在事务结束时同数据库进行同步,

因此当持久化对象的数据更新时,不需要调用方法保存,会自动更新到数据库。那么哪些方法可以

就对象放入持久化状态呢,无非就是操作一级缓存的方法。
2、下面我们来学习二级缓存
首先我们明白二级缓存的缓存级别是sessionfactory级别的,因此只要服务器没有关掉二级缓存就一直存在。
那么哪些方法可以将数据存放到二级缓存。
只有一个 List<Classes> classes = session.createQuery("from Classes").list(); //hql:hibernate query language
Classes classes = (Classes)session.get(Classes.class, 3L);
去二级缓存的方法又有哪些呢。
	Classes classes = (Classes)session.get(Classes.class, 3L);
	Iterator<Classes> iterator = session.createQuery("from Classes").iterate();
		System.out.println(sessionFactory.getStatistics().getEntityLoadCount());
		while(iterator.hasNext()){
			Classes classes2 = iterator.next();
			System.out.println(classes2.getName());
		}

这些方法可以读取到二级缓存中的东西,在我看来list使用二级缓存没有多大意义。
 * list方法可以让hql语句指定的对象进入了二级缓存中,
* 但是list方法不利用二级缓存查询数据,这里我想我以前一直有一个误区,以为list查询不到数据,
* list是把查询出来的数据放到二级缓存,他肯定是有数据的,但是如果我在查询的时候用list有什么意义呢
* 我每次查出来放到二级缓存,在这里我认为是没有任何意义的
/**
* iterate方法的查询策略:
*    1、先查找该表中所有的id的值
*    2、再根据id值从二级缓存中查找对象,如果有,则利用二级缓存,如果没有则根据id查询该表中的所有的属性的值
*/
/**
* session.get方法不仅要把数据放入到一级缓存,而且要放入到二级缓存
*   该方法在提取数据的时候,先从一缓存中查找,再从二级缓存中查找,如果找不到,则查询数据库
*/

3、下面我介绍下查询缓存,我想二级缓存的主要意义在于这里吧,为什么这么说呢,因为查询缓存依赖于二级缓存,

而且二级缓存解决了二级缓存数据更新无法感知的问题,那么查询缓存是如何进行缓存的呢

查询缓存

      一级缓存和二级缓存都是对象缓存:就是把该对象对应的数据库表中的所有的字段

    全部查询出来了,这种查询在某些场合下会让效率降低。例如:表中的字段特别多,

    但是程序中所需要的字段却很少。

       查询缓存也叫数据缓存:内存(页面)中需要多少数据就把多少数据放入到查询缓存

(这个很重要,查询出来的是字段,不是bean对象,不能通过 select * from classes这样查询,只能通过select id ,name form classes这样查询一个

字段),

    中。

生命周期

    只要一些数据放入到查询缓存中,该缓存会一直存在,直到缓存中的数据被修改了,该

    缓存的生命周期就结束了。

好了讲了这么多,我们来几个代码配置,掌握这些才能进入实质性的开发阶段。

下面我们来看session是如何创建的

public static SessionFactory sessionFactory;
	static{
		Configuration configuration = new Configuration();
		configuration.configure();
		sessionFactory = configuration.buildSessionFactory();
	}
Session session = sessionFactory.openSession();
接着我们看下查询缓存的代码

	/**
	 * "select name from Classes"
	 * 		查询出来的数据能够放入到查询缓存中
	 *      但是不能放入到二级缓存中,因为不是对象
	 */
	@Test
	public void testList_2(){
		Session session = sessionFactory.openSession();
		Query query = session.createQuery("select name from Classes");
		query.setCacheable(true);//query要使用查询缓存了
		query.list();//把数据放入到查询缓存中
		System.out.println(sessionFactory.getStatistics().getEntityLoadCount());
		session.close();
		
		session = sessionFactory.openSession();
		query = session.createQuery("select name from Classes");
		query.setCacheable(true);
		query.list();
		session.close();
	}

下面我们来看一下如何配置查询缓存的配置环境,其实掌握了这个,也就掌握了其它的

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
	<!-- 
		一个sessionFactory代表数据库的一个连接
	-->
<session-factory>
	<!-- 链接数据库的用户名 -->
	<property name="connection.username">root</property>
	<!-- 链接数据库的密码 -->
	<property name="connection.password">123</property>
	<!-- 链接数据库的驱动 -->
	<property name="connection.driver_class">
		com.mysql.jdbc.Driver
	</property>
	<!-- 链接数据库的url -->
	<property name="connection.url">
		jdbc:mysql://localhost:3306/itheima12_hibernate
	</property>

	<!-- 
		方言
		告诉hibernate使用什么样的数据库,hibernate就会在底层拼接什么样的sql语句
	-->
	<property name="dialect">
		org.hibernate.dialect.MySQLDialect
	</property>

	<!-- 
		二级缓存的供应商
	-->
	<property name="cache.provider_class">
		org.hibernate.cache.EhCacheProvider
	</property>
	<!-- 
		开启二级缓存
	-->
	<property name="cache.use_second_level_cache">true</property>
	<!-- 
		<class-cache usage="read-only" class=""/>
	-->
	<!-- 
		根据持久化类生成表的策略
		validate   通过映射文件检查持久化类与表的匹配
		update   每次hibernate启动的时候,检查表是否存在,如果不存在,则创建,如果存在,则什么都不做了
		create   每一次hibernate启动的时候,根据持久化类和映射文件生成表
		create-drop
	-->
	<property name="hbm2ddl.auto">update</property>
	<property name="show_sql">true</property>
	<property name="current_session_context_class">thread</property>
	<property name="format_sql">true</property>
	<!-- 
		开启二级缓存的统计机制
	-->
	<property name="generate_statistics">true</property>
	<!-- 
		开启了查询缓存
	 -->
	<property name="cache.use_query_cache">true</property>

	<mapping resource="com/itheima12/hibernate/domain/Classes.hbm.xml" />
	<mapping resource="com/itheima12/hibernate/domain/Student.hbm.xml" />
</session-factory>
</hibernate-configuration>

hibernate的另外一个重点就是表与表之间的关系,无非就是一对一,多对多,多对一,一对一等,学会配置文件就可以了,在这里我就重点介绍下

下面几个知识点

inversecascade的关系

   cascade指的是级联操作,操作的是一般属性,指的是对象与对象的操作

级联操作,是指保存一方的时候,会级联保存另一方,会不会构建关系,需要由inverse确定,如果inversefalse,为维护关系,会发出update语句,将外键加入另一张表。

   inverse指的是关系操作,针对的就是外建,默认是falsetrue极为由另外一方维护关系,

取消关系实际是是设置外键为空,级联是指两个对象之间的操作,

级联删除同时会把另外一张表中的数据删除。

级联和关系并没有太多的关系。

注意删除的时候,

<!-- 
set元素针对的就是Classes类中的Set属性
cascade  级联操作
  null  默认值
  save-update
      在保存classes对象的时候,针对student进行保存或者更新的操作
      在更新classes对象的时候,针对student进行保存或者更新的操作
  all
  delete
inverse  关系操作
  default:classes维护classes与student之间的关系
  true:   classes不维护classes与student之间的关系
  false:  classes维护classes与student之间的关系
-->

一对多的双向

   当多的一方维护关系时,不会发出更新关系的update语句,(原因列子,再插入学生的时候,级联插入一个班级,如果是维护关系,会同时插入外键,所以不会发出update语句

而且多的一方没有 inverse 者一属性,因为你在构建关系,或者解除关系时,都是会对,本表中的外键进行操作。所以有无inverse都没关系。

 

而一的一方维护关系时,需要发出维护关系的update语句,因为它会首先插入对象,而后跟新外键。,所以在这里,一般情况下,多的一方维护关系效率

比较高。

具体参数配置看笔记,这里不一一介绍了


介绍下懒加载,就是用到的时候才加载,

类的懒加载

Classes classes = (Classes)session.load(Classes.class, 1L);

集合需要配置文件

<set name="students" cascade="save-update" inverse="true" lazy="extra">
<cache usage="read-write"/>

具体看源码案例吧,这里也不介绍了

这里设计到级联查询,级联查询有个抓取策略,如下

<set name="students" cascade="save-update" inverse="true" lazy="extra" fetch="join">
<cache usage="read-write"/>

抓取策略

   join:左外连接

   select:默认的值

   subselect:子查询

下面将hibernate的hql查询,直接上代码吧,在这里我们会发现查询出来的都是对象,非常的方便好用,hql的对象关系映射在这里可谓是运用的

凌厉之境

public class OneToManyTest extends HibernateUtils{
	/**
	 * 实现classes与student的内连接
	 * 		select s.*,c.*
			from student s inner join classes c on(s.cid=c.cid)
	 */
	@Test
	public void testInnerJoin(){
		Session session = sessionFactory.openSession();
		List list = session.createQuery("from Classes c inner join c.students").list();
		session.close();
	}
	
	/**
	 * 迫切内连接
	 */
	@Test
	public void testInnerJoin_fetch(){
		Session session = sessionFactory.openSession();
		List list = session.createQuery("from Classes c inner join fetch c.students").list();
		session.close();
	}
	
	/*
	 * 左外连接
	 * select c.*,s.*
			from classes c left outer join student s on(s.cid=c.cid)
	 */
	@Test
	public void testLeftJoin(){
		Session session = sessionFactory.openSession();
		List list = session.createQuery("from Classes c left outer join c.students").list();
		session.close();
	}
	
	/**
	 * 迫切左外连接
	 */
	@Test
	public void testLeftJoin_fetch(){
		Session session = sessionFactory.openSession();
		List list = session.createQuery("from Classes c left outer join fetch c.students").list();
		session.close();
	}
	
	/**
	 * 要查询的属性来自于两个持久化类
	 *    带构造函数的查询和fetch的查询不能同时存在
	 */
	@Test
	public void testQueryPropertiesFromClassesAndStudent(){
		Session session = sessionFactory.openSession();
		List<ClassesView> classesViews = session.createQuery("select new com.itheima12.hibernate.domain.ClassesView" +
				                                                  "(c.name,s.name) from Classes c " +
				                                                   "inner join c.students s").list();
		session.close();
	}
}
看一个设置参数的案例

	@Test
	public void testQueryPrepare_2(){
		Session session = sessionFactory.openSession();
		Query query = session.createQuery("from Classes where cid=:cid and name=:name");
		query.setParameter("cid", 1L);
		query.setParameter("name", "adsfasfd");
		Classes classes = (Classes)query.uniqueResult();
		System.out.println(classes.getName());
		session.close();
	}

还有分页参数的设置

query.setFirstResult(3);//表示在集合中索引的位置
query.setMaxResults(3);//表示设置一页显示多少个


最后hibernate也能通过sql查询,这里sql查询出来的就没有对象关系映射了,是数据

      List list = session.createSQLQuery(sql). 
                    addScalar("person_id",StandardBasicTypes.INTEGER). 
                    addScalar("name", StandardBasicTypes.STRING). 
                    addScalar("age",StandardBasicTypes.INTEGER).list(); 
        for(Iterator iterator = list.iterator();iterator.hasNext();){ 
            //每个集合元素都是一个数组,数组元素师person_id,person_name,person_age三列值 
            Object[] objects = (Object[]) iterator.next(); 
            System.out.println("id="+objects[0]); 
            System.out.println("name="+objects[1]); 
            System.out.println("age="+objects[2]); 
            System.out.println("----------------------------"); 
        } 





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值