Hibernate是一个开源的对象关系映射框架,它对JDBC进行了轻量级的对象封装,使Java程序员可以随心所欲的使用对象编程思维来操纵数据库。
提供了从java类到数据库表之间的映射,也提供了数据查询和恢复机制。相对于使用JDBC和SQL来手工操作数据库,Hibernate可以大大减少
2. Hibernate原理:
Hibernate技术本质上是一个提供数据库服务的中间件。Hibernate的工作原理,他是利用数据库以及其他一些配置文件如:hibernate.cfg.xml,
xxx.hbm.xml等来为应用程序提供数据持久化服务的。
- Configuration来读取hibernate.cfg.xml文件
- 使用Configuration对象创建SessionFactory
- 用SessionFactory来打开一个Session
- 创建事务Transaction
- begin事务
- 使用Session进行数据库操作
- 关闭或回滚事务
- 关闭Session
3.2 先创建一个User实体
package com.a_helloworld;
2
3 public class User {
4
5 private int id;
6 private String name;
7 public int getId() {
8 return id;
9 }
10 public void setId(int id) {
11 this.id = id;
12 }
24 略
25
26 }
3.4 简单配置hibernate.cfg.xml配置文件,这个文件名可以随便修改(xxx.cfg.xml),但是没多大意义,一般不建议修改。配置的信息如下:
1 <!DOCTYPE hibernate-configuration PUBLIC 2 "-//Hibernate/Hibernate Configuration DTD 3.0//EN" 3 "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> 4 5 <hibernate-configuration> 6 <session-factory name="foo"> 7 8 <property name="connection.driver_class">com.mysql.jdbc.Driver</property> 9 <property name="connection.username">root</property> 10 <property name="connection.password">123456</property> 11 <property name="connection.url">jdbc:mysql:///user</property> 12 13 <!-- 要根据自己使用的数据库来配置相对应的属性,也成方言,针对不同数据库 14 关于怎么配置可以查看HibernateAPI 15 --> 16 <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> 17 18 <!-- Hibernate 創建的SQL語句会显示在控制台 --> 19 <property name="hibernate.show_sql">true</property> 20 21 <!-- 选择方案,常用值:validate | update | create | create-drop --> 22 <property name="hbm2ddl.auto">update</property> 23 24 <mapping resource="com/a_helloworld/user.hbm.xml"/> -- 导入实体映射配置,程序每次启动都会自动检索 25 26 </session-factory> 27 </hibernate-configuration>
Hibernate get和load区别
get和load方式是根据id取得一个记录下边详细说一下get和load的不同,因为有些时候为了对比也会把find加进来。
1.从返回结果上对比:
load方式检索不到的话会抛出org.hibernate.ObjectNotFoundException异常
get方法检索不到的话会返回null
2.从检索执行机制上对比:
get方法和find方法都是直接从数据库中检索,而load方法执行比较复杂先查找session的persistent Context 中是否有缓存,如果有则直接
返回,如果没有判断是够shilazy,如果不是直接访问数据库检索,查询记录返回,查不到,如果是lazy则需要建立代理对象,对象的initiaized
属性为false,target属性为null,在范文获得的代理了对象的属性时,检索数据库,如果找到记录则吧记录的对象复制到代理对象的target上,
并将initialized=true,如果找不到就跑出异常。
3.根本区别说明
如果你使用load方法,hibernate认为该id对应的对象(数据库记录)在数据库中是一定存在的,所以它可以放心的使用,它可以放心的使用代理来 延迟加载该对象。数据库中不存在该数据时抛异常,而不是在创建这个对象时(注意:这就是由于“延迟加载”在作怪)。
对于get方法,hibernate会确认一下该id对应的数据是否存在,首先在session缓存中查找,然后在二级缓存中查找,还没有就查数据库,数据库中没有就返回null。
4.简单总结
总之对于get和load的根本区别,一句话,hibernate对于load方法认为该数据在数据库中一定存在,可以放心的使用代理来延迟加载,如果在使用过程中发现了问题,只能抛异常;而对于get方法,hibernate一定要获取到真实的数据,否则返回null。
Hibernate的一级和二级缓存
1. 管理sessionsession对象的生命周期与本地线程绑定
<!-- 配置session对象的生命周期和本地线程绑定 -->
<property name=”hibernate.current_session_context_class”>thread</property>
2. hibernate缓存机制
Hibernate中提供了两个级别的缓存
第一级别的缓存是 Session的缓存,它是属于线程范围的缓存。这一级别的缓存由 hibernate 管理的,我们无需干预
第二级别的缓存是 SessionFactory的缓存,它是属于进程范围的缓存
缓存的作用主要用来提高性能,可以简单的理解成一个Map
使用缓存涉及到三个操作:把数据放入缓存、从缓存中获取数据、删除缓存中的无效数据
一级缓存:
一级缓存指的是session对象的一个hashMap(session的实现类是:sessionImpl)
用户不需要做任何配置就可以使用,他的生命周期小只要session关闭,缓存就消失每个session拥有自己的缓存去执行session.save()
操作的时候,会先放到一级缓存----》放到的对象成为持久化对象
* 执行查询的时候,会先到session的一级缓存中查找
* 如果找到,直接从缓存中获取该对象,这时不再查询数据库
* 如果没有找到,此时查询数据库,产生select语句,并把查询到的对象放入缓存
Customer c1 = (Customer) session.get(Customer.class, 1);
// 根据id查询一个Customer对象
// 根据业务来编写代码
// Customer c = session.get(Customer.class, 1);
Customer c = session.load(Customer.class, 1);
OID检索方式:
- Customer customer = session.load(Customer.class, 1L);
- transaction.commit();
- // 输出1和报错could not initialize proxy - no Session
- // 当<class name="Customer" table="cst_customer" lazy="false">时
- // 该方法正确,因为这时候已经不延迟加载了
- System.out.println(customer.getCustId());
对象导航查询:
对象图导航检索方式是根据己经加载的对象,导航到他的关联对象 。它利用类与类之间的关系来检索对象 。
譬如要查找一个联系人对应的客户,就可以由联系人对象自动导航找到联系人所属的客户对象。
当然,前提是必须在对象关系映射文件上配置了多对一的关系
- /**
- * 根据客户id查询联系人信息
- * @param custId
- * @return
- */
- public List<LinkMan> findLinkManByCid(Long custId){
- Session s = HibernateUtils.getCurrentSession();
- Transaction tx = s.beginTransaction();
- SQLQuery query = s.createSQLQuery("select * from cst_linkman where lkm_cust_id = ? ");
- query.setLong(0, custId);
- query.addEntity(LinkMan.class);
- @SuppressWarnings("unchecked")
- List<LinkMan> mans = query.list();
- tx.commit();
- return mans;
- }
- /**
- * 需求:
- * 查询id为1的客户下的所有联系人
- */
- @Test
- public void test1(){
- // 传统的使用方式
- List<LinkMan> list = findLinkManByCid(1L);
- System.out.println(list);
- Customer c = findById(1L);
- //对象导航查询
- // 需要将Customer上对应于LinkMan的关系检索策略的懒加载关闭
- Set<LinkMan> linkmans = c.getLinkMans();
- for(LinkMan linkMan : linkmans){
- System.out.println(linkMan);
- }
- }
HQL查询
HQL (Hibernate Query Language ) 是面向对象的查询语言,它和 SQL 查询语言有些相似 ,
但它使用的是类、对象和属性的概念 ,而没有表和字段的概念 。
在Hibernate提供的各种检索方式中 ,HQL是官方推荐的查询语言,也是使用最广泛的一种检索 方式。
- /**
- * 条件查询:
- * 需求:
- * 查询客户级别是23的,客户名称带有 集 字的
- * 给HQL语句加条件用where
- * HQL语句的参数占位符也可以使用?
- * hibernate中,参数占位符是从0开始的。
- */
- @Test
- public void test2(){
- Session session = HibernateUtils.openSession();
- Transaction transaction = session.beginTransaction();
- // 查询客户级别是23的,客户名称带有 集 字的
- Query query = session.createQuery("from Customer where custLevel = ? and custName like ?");
- query.setString(0, "23");
- query.setString(1, "%集%");
- @SuppressWarnings("unchecked")
- List<Customer> customers = query.list();
- transaction.commit();
- for (Customer customer : customers) {
- System.out.println(customer);
- }
- }
- /**
- * 投影查询:
- * 当我们查询实体对象时,并不需要所有字段信息,只查询部分,但是还想让他成为一个实体对象。其实就是用部分字段来投影出整个实体对象。
- * 使用要求:
- * HQL语句:
- * 写法必须是 new 实体类名称(查询的字段)
- * select new Customer(custId,custName) from Customer
- * 注意:如果你的实体类在工程中唯一,则可以直接写类名。如果实体类在工程中不唯一,需要写全限定类名。
- * 实体类要求:
- * 必须在实体类中提供一个相同参数列表的构造函数。
- *
- */
- @Test
- public void test71(){
- Session session = HibernateUtils.getCurrentSession();
- Transaction transaction = session.beginTransaction();
- // 只获取客户的ID和名字,并封装成客户对象
- Query query = session.createQuery("select new Customer(custId, custName) from Customer");
- @SuppressWarnings("unchecked")
- List<Customer> customers = query.list();
- transaction.commit();
- for (Customer customer : customers) {
- System.out.println(customer.getCustId() + " " + customer.getCustName());
- }
- }
- /**
- * 左外连接查询和迫切左外连接查询的区别
- * 区别:
- * 返回的结果集不一样。在实际开发中用的不多,此处讲解就是为了说明他们之间的区别
- * 注意:
- * Hibernate中没有右外连接
- *
- * Hibernate左外连接返回的数据:
- * 返回的是一个有Object数组组成的List集合,该数组中有两个对象。一个是主表实体,一个是从表实体。
- * 主表实体有可能重复
- */
- //左外连接查询
- @Test
- public void test81(){
- Session session = HibernateUtils.getCurrentSession();
- Transaction transaction = session.beginTransaction();
- //1.获取Query对象
- //sql语句的左外:select * from cst_customer c left outer join cst_linkman l on c.cust_id = l.lkm_cust_id;
- Query query = session.createQuery("from Customer c left join c.linkMans");
- //2.执行query对象的方法
- @SuppressWarnings("unchecked")
- List<Object[]> list = query.list();
- transaction.commit();
- for (Object[] objects : list) {
- System.out.println("------一组对象-------");
- for (Object object : objects) {
- System.out.println(object);
- }
- }
- }
QBC查询
QBC(Query By Criteria)是Hibernate提供的另一种检索对象的方式,它主要由Criteria 接口、Criterion接口和Expression类组成 。
Criteria接口是Hibernate API中的一个查询接口,它需要由session进行创建。Criterion是Criteria的查询条件,
在Criteria中提供了add(Criterion criterion)方法来添加查询条件。
方法名
|
说明
|
Restrictions.eq
|
等于
|
Restrictions. allEq
|
使用 Map ,使用key/value进行多个等于的比较
|
Restrictions.gt
|
大于>
|
Restrictions.ge
|
大于等于>=
|
Restrictions.lt
|
小于
|
Restrictions.le
|
小于等于<=
|
Restrictions.between
|
对应 SQL 的 between 子句
|
Restrictions.like
|
对应 SQL 的 like 子句
|
Restrictions.in
|
对应 SQL 的 IN 子句
|
Restrictions.and
|
and 关系
|
Restrictions.or
|
or 关系
|
Restrictions.sqlRestriction
|
SQL 限定查询
|
- Hibernate中的查询方式:
- * QBC查询:
- * Query By Criteria 它是一种更加面向对象的查询方式。
- * 它把查询条件都用方法封装了。里面的参数全都需要使用实体类的属性名称。
- * 涉及的对象:
- * Criteria
- * DetachedCriteria
- * 获取的方式:
- * session.createCriteria(Class clazz);参数指的是要查询的字节码
- * 添加条件的方法:
- * Criteria的add方法。
- * 添加条件涉及的对象:
- * Restrictions
- /**
- * 条件查询
- * 需求:查询客户级别是23的,客户名称带有集字的
- */
- @Test
- public void test2(){
- Session session = HibernateUtils.getCurrentSession();
- Transaction tx = session.beginTransaction();
- //1.获取Criteria对象
- Criteria criteria = session.createCriteria(Customer.class);
- // 添加条件
- criteria.add(Restrictions.eq("custLevel", "23"));
- criteria.add(Restrictions.like("custName", "%集%"));
- //2.执行list方法,得到结果集
- @SuppressWarnings("unchecked")
- List<Customer> customers = criteria.list();
- tx.commit();
- for (Customer customer : customers) {
- System.out.println(customer);
- }
- }
- /**
- * 离线查询:
- * 在线对象:
- * Criteria对象。它的获取必须要一个可用的Session来创建。如果Session不能用,则不能创建Criteria。
- * 我们使用Criteria进行的查询就是在线查询。
- * 离线对象:
- * 创建DetachedCriteria不需要一个可用的Session。
- * 用DetachedCriteria进行的查询就叫做离线查询
- * 涉及的对象
- * DetachedCriteria
- * 如何获取
- * DetachedCriteria.forClass(Class clazz);参数的含义:要查询的实体类
- * 如何设置查询条件:
- * 和Criteria是一样的
- *
- * 在实际开发中:多条件查询用此种方式
- */
- //Servlet的方法
- @Test
- public void doGet(){
- //1.获取请求参数
- String custLevel = "23";
- String custName = "集";
- //2.查询所有客户
- DetachedCriteria dCriteria = DetachedCriteria.forClass(Customer.class);
- dCriteria.add(Restrictions.eq("custLevel", custLevel));
- dCriteria.add(Restrictions.like("custName", "%"+custName+"%"));
- List<Customer> cs = servicefindAllCustomer(dCriteria);
- for(Customer c : cs){
- //3.存入请求域中
- //4.转向列表页面
- System.out.println(c);
- }
- }
- //Service的方法
- public List<Customer> servicefindAllCustomer(DetachedCriteria dCriteria){
- return daofindAllCustomer(dCriteria);
- }
- //Dao中的方法
- public List<Customer> daofindAllCustomer(DetachedCriteria dCriteria){
- Session s = HibernateUtils.getCurrentSession();
- Transaction tx = s.beginTransaction();
- //1.把离线对象激活
- Criteria c = dCriteria.getExecutableCriteria(s);
- //3.执行list方法,得到结果集
- @SuppressWarnings("unchecked")
- List<Customer> list = c.list();
- tx.commit();
- return list;
- }
- }