欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

爱上框架之Hibernate框架

程序员文章站 2022-06-11 09:45:56
...
爱上框架之hibernate框架

一、使用hibernate开发的步骤:
1.创建工程
2.导入jar包
3.创建hibernate核心配置文件 hibernate.cfg.xml
路径:hibernate-release-5.2.10.Final\project\etc,放在src中。

二、hibernate对象的三种状态:
1.瞬时对象 当对象被new出来时候,此对象为瞬时对象。超过作用域会被JVM垃圾回收器回收。
数据库中没有此对象对应的记录。
2.持久对象:数据库中存在数据与对象一一对应,但是此对象必须是与session相关联的
并且此session没有关闭。
3.脱管状态,数据库中存在此对象,但是此时session已经关闭了,但是此对象还存在。
此对象发生改变,hibernate检测不到。

三、hibernate的get和load方法的区别:
1.对于get方法,hibernate会确认一下该id对应的数据是否存在,
首先在session缓存中查找,然后在二级缓存中查找,
还没有就查询数据库,数据库中没有就返回null。这个相对比较简单,也没有太大的争议。
主要要说明的一点就是在这个版本中get方法也会查找二级缓存!
2.load方法加载实体对象的时候,根据映射文件上类级别的lazy属性的配置(默认为true),
分情况讨论:
(1)若为true,则首先在Session缓存中查找,看看该id对应的对象是否存在,不存在则使用延迟加载,返回实体的代理类对象(该代理类为实体类的子类,由CGLIB动态生成)。等到具体使用该对象(除获取OID以外)的时候,再查询二级缓存和数据库,若仍没发现符合条件的记录,则会抛出一个ObjectNotFoundException。
(2)若为false,就跟get方法查找顺序一样,只是最终若没发现符合条件的记录,则会抛出一个ObjectNotFoundException。

四、save()方法和persist()方法的区别:
1.save()方法不提交事务,都会插入数据到数据库,但是没有提交,数据会进行回滚。
2.persist()如果不添加事务,则根本不会提交数据到数据库中。

五、hibernate查询
1.Get/load主键查询
Dept dept =  (Dept) session.get(Dept.class, 10);
Dept dept =  (Dept) session.load(Dept.class, 10); (支持懒加载)


2.对象导航查询
Dept dept =  (Dept) session.get(Dept.class, 10);
	System.out.println(dept.getDname());
	System.out.println(dept.getEmps());


3.HQL查询,  Hibernate Query language  hibernate 提供的面向对象的查询语言。
注意点:此时的sql中的表必须要替换成为类,而表的列名必须要对应类的属性名。
注意:使用hql查询的时候 auto-import="true" 要设置true,如果是false,写hql的时候,要指定类的全名
        Query q = session.createQuery("from Dept");
     	System.out.println(q.list());


4.Criteria 查询,   完全面向对象的查询(Query By Criteria  ,QBC)
        Criteria criteria = session.createCriteria(Emp.class);
	criteria.add(Restrictions.eq("empNo", 12));


5.SQLQuery, 本地SQL查询
缺.点:不能跨数据库平台: 如果该了数据库,sql语句有肯能要改
使用场景: 对于复杂sql,hql实现不了的情况,可以使用本地sql查询。
SQLQuery q = session.createSQLQuery("select * from Dept where deptno = 20 ")	 	System.out.println(q.list());


例:分页查询:先查询总记录数,再分页查询。
@Test
	public void all() {
		Session session = HibernateSessionFactory.getSession();
		Transaction tr = session.beginTransaction();
		 Query q = session.createQuery("from Emp");
		
		 ScrollableResults scroll = q.scroll();  // 得到滚动的结果集
		 scroll.last();							//  滚动到最后一行
		 int totalCount = scroll.getRowNumber() + 1;// 得到滚到的记录数,即总记录数 
		 // 设置分页参数
		 q.setFirstResult(0);
		 q.setMaxResults(5);
		 System.out.println(q.list()); // 查询
		 System.out.println("总记录数:" + totalCount);
		 tr.commit();
		 HibernateSessionFactory.closeSession();
	}


六、hibernate C3P0连接池的配置:
为什么不使用hibernate自带的连接池,而去使用C3P0连接池?
C3P0是一款流行的开源的数据库连接池,使用此连接池,可以提高对数据库的访问和使用的效率。
C3P0的配置,配置在hibernate.cfg.xml文件中
<!-- hibernate连接池的供应类 -->
<property name="connection.provider_class">
	org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider
</property>
<!-- hibernate连接池的最小个数 -->
<property name="c3p0.min_size">3</property>
<!-- hibernate连接池中的最大个数 -->
<property name="c3p0.max_size">20</property>
<!-- 连接池中执行sql语句的最大个数,同时执行50条sql语句 -->
<property name="c3p0.max_statements">50</property>
<!-- 连接超时数,单位为毫秒 -->
<property name="c3p0.timeout">1800</property>
<!-- 连接自动增长的个数 -->
<property name="c3p0.acquire_increment">2</property>




七、hibernate的主键生成策略:
1.assigned:
特点:可以跨数据库,人为控制主键生成,。Hibernate不负责维护主键生成。
与Hibernate和底层数据库都无关,应尽量避免。
语法:
<id name="id" column="id">
<generator class="assigned" />
</id>

2.increment:
由Hibernate从数据库中取出主键的最大值(每个session只取1次),
以该值为基础,每次增量为1,在内存中生成主键,不依赖于底层的数据库。
<id name="id" column="id">
<generator class="increment" />
</id>
Hibernate调用org.hibernate.id.IncrementGenerator类里面的generate()方法,
使用select max(idColumnName) from tableName语句获取主键最大值。
特点:跨数据库,不适合多进程并发更新数据库,适合单一进程访问数据库,不能用于群集环境。

3.hilo:
特点:跨数据库,hilo算法生成的标志只能在一个数据库中保证唯一。

4.seqhilo
与hilo类似,通过hi/lo算法实现的主键生成机制,
只是将hilo中的数据表换成了序列sequence,
需要数据库中先创建sequence,适用于支持sequence的数据库,如Oracle。
<id name="id" column="id">
<generator class="seqhilo">
<param name="sequence">hibernate_seq</param>
<param name="max_lo">100</param>
</generator>
</id>

5.sequence
采用数据库提供的sequence机制生成主键,需要数据库支持sequence。
如oralce、DB、SAP DB、PostgerSQL、McKoi中的sequence。
MySQL这种不支持sequence的数据库则不行(可以使用identity)。
<generator class="sequence">
<param name="sequence">hibernate_id</param>
</generator>
hibernate_id 指定sequence的名称
特点:只能在支持序列的数据库中使用,如Oracle。

八、hibernate的关联关系
在一对多与多对一的关联关系中,保存数据最好的通过多的一方来维护关系,这样可以减少update语句的生成,从而提高hibernate的执行效率!
配置一对多与多对一,这种叫“双向关联”
只配置一对多,           叫“单项一对多”
只配置多对一,           叫“单项多对一”
注意:配置了哪一方,哪一方才有维护关联关系的权限!

1、Inverse属性
是在维护关联关系的时候起作用的。
    表示控制权是否转移。(在一的一方起作用)
Inverse , 控制反转。
Inverse = false  不反转;   当前方有控制权
True  控制反转; 当前方没有控制权

2、cascade  表示级联操作  【可以设置到一的一方或多的一方】
none          不级联操作, 默认值
save-update     级联保存或更新
delete   级联删除
save-update,delete    级联保存、更新、删除
all                 同上。级联保存、更新、删除

九、hibernate延迟加载
hibernate为了提高程序的效率,优化访问数据的数据,默认加载数据的时候设置了延迟加载。
延迟加载一般使用在one对多或者多对多的关系上面。
但是有时候延迟加载当我们关闭Session的时候会抛出异常,所以解决延迟加载有如下方法:
1.查询的方法当中即时打印数据。
2.使用hibernate.initlize(代理对象);初始化代理对象
3.在*.hbm.xml中配置延迟加载的数据 lasy=false false代表取消延迟加载。

十、Hibernate的缓存
1、Hibernate的一级缓存(Session级别的缓存)
缓存容器Map:save(),get(),load()
第一个用户:Object ->Map容器中 key,value (class,id)
第二个用户:先去容器中去取(如果容器中存在,则直接提取,如果不存在,查询数据库,查询到数据存在容器中)
Session:clear();close();s.evict(Object);清除单个对象
缺点:声明周期短,数据存储在内容中,如果数据量过大,很容易导致内存溢出

2、二级缓存:SessionFactory:
1).在项目的src文件下面创建ehcache.xml
2).修改hibernate.cfg.xml,
在此配置文件中加上二级缓存的相关配置
               <!-- 二级缓存供应工厂 -->
		<property name="cache.region.factory_class">
			org.hibernate.cache.ehcache.EhCacheRegionFactory
		</property>
		<!-- 是否使用二级缓存,默认为true:使用。可设置为false不启用 -->
		<property name="cache.use_second_level_cache">true</property>
		<!-- 查询时应用缓存 -->
		<property name="cache.use_query_cache">true</property>


3).配置需要查询的对象的映射文件*.hbm.xml
<!-- 缓存的策略
    1.read-only 只读
    2.read-write 允许读取或者更新数据 推荐使用
    3.nonstrict-read-write 脏读,不严格的读写
    4.transactional 支持事务,如果读取或者更新数据时报错,可以回滚。
    -->
   <cache usage="read-only"/>
用户查询数据的顺序:效率从高到低。
session(以及缓存)->cache(二级缓存)->db(数据库中去取)

二级缓存使用的注意事项:
1.一般适用于查询的数据,数据量处于中等。(10W下)
2.如果使用多个dao层的框架,hibernate在某些情况下不能检测到数据的一些更新状态时,则不推荐使用二级缓存
3.如果长期进行一些增删改的操作,也不推荐使用二级缓存。

MVC各层所对应框架
M - 模型层
dao -> hibernate,mybits,dbutils 基于orm的框架,推荐只使用一种
service -> spring ,springmvc
pojo
controll -> struts2,springmvc
view -> jsp

hibernate使用在dao层:
/**
 * 封装对数据库中的表的操作 (新增 / 修改 / 删除 / 根据id查询)
 * 
 */
public class HibernateDao<T> {
  public T find(Class<T> classz, Serializable id) {
    Session session = HibernateSessionFactory.getSession();
    T t = session.get(classz, id);
    HibernateSessionFactory.closeSession();
    return t;
  }

  public void add(T t) {
    Session session = HibernateSessionFactory.getSession();
    Transaction tx = session.beginTransaction();
    session.save(t);
    tx.commit();
    HibernateSessionFactory.closeSession();
  }

  public void modify(T t) {
    Session session = HibernateSessionFactory.getSession();
    Transaction tx = session.beginTransaction();
    session.update(t);
    tx.commit();
    HibernateSessionFactory.closeSession();
  }

  public void remove(T t) {
    Session session = HibernateSessionFactory.getSession();
    Transaction tx = session.beginTransaction();
    session.delete(t);
    tx.commit();
    HibernateSessionFactory.closeSession();
  }
}



查询所有的方法:(对emp表进行查询,可实现根据雇员名称和薪水进行模糊查询)
public class EmpDao extends HibernateDao<Emp> {
   /**
   * 多条件查询
   * @param ename
   * @param sal
   * @return
   */
  @SuppressWarnings("unchecked")
  public List<Emp> find(String ename, Double sal) {
Session session = HibernateSessionFactory.getSession();
Transaction tr = session.beginTransaction();

    String hql = "from Emp where 1=1 ";
    if (ename != null && ename.trim().length() > 0) {
      hql += " and ename like :ename ";
    }
    if (sal != null && sal > 0D) {
      hql += " and sal > :sal ";
}

Query query = session.createQuery(hql);

    if (ename != null && ename.trim().length() > 0) {
      query.setString("ename", "%" + ename.toUpperCase() + "%");
    }
    if (sal != null && sal > 0D) {
      query.setDouble("sal", sal);
}

ScrollableResults scroll = query.scroll();//得到滚动结果集
scroll.last();						//滚动到最后一条记录
int totalCont = scroll.getRowNumber()+1;	//得到总记录数
query.setFirstResult(0);					// 设置分页参数
query.setMaxResults(10);

List<Emp> emps = query.list();

//强制加载关联的数据、得到dept表中的数据
for(Emp emp:emps){
	Hibernate.initialize(emp.getDept());
}

tr.commit();
    HibernateSessionFactory.closeSession();
    return emps;
  }
}



四种查询结果的hql语句分解:
1.hql:from Emp where 1=1//查询所有雇员信息
2. hql:from Emp where 1=1 and ename like :ename//根据雇员名称模糊查询雇员信息
3.hql:from Emp where 1=1 and sal > :sal//根据雇员薪水模糊查询雇员信息
4.hql:from Emp where 1=1 and ename like :ename and sal > :sal//根据雇员名称和薪水模糊查询雇员信息

查询结果如下图所示:
[img]
爱上框架之Hibernate框架
            
    
    博客分类: 框架 框架hibernate 
[/img]
  • 爱上框架之Hibernate框架
            
    
    博客分类: 框架 框架hibernate 
  • 大小: 49.3 KB
相关标签: 框架 hibernate