爱上框架之Hibernate框架
程序员文章站
2022-06-11 09:54:08
...
爱上框架之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]
[/img]
上一篇: 微信墙怎么做?微信墙制作流程介绍
下一篇: c4d时间线怎么设置开始帧和结束帧?
推荐阅读
-
前端框架学习总结之Angular、React与Vue的比较详解
-
laravel框架学习记录之表单操作详解
-
.NET Core实战项目之CMS 第十章 设计篇-系统开发框架设计
-
python+unittest框架第四天unittest之断言(一)
-
SSH框架之Hibernate第二篇
-
Java框架之MyBatis框架
-
Bootstrap整体框架之JavaScript插件架构
-
零基础学习AJAX之AJAX框架
-
从零开始搭建前后端分离的NetCore2.2(EF Core CodeFirst+Autofac)+Vue的项目框架之七使用JWT生成Token(个人见解)
-
从零开始搭建前后端分离的NetCore2.2(EF Core CodeFirst+Autofac)+Vue的项目框架之十一Swagger使用一