Hibernate复习


Hibernate

   最近觉得有必要将以前学的框架整理和回顾一下,同时也为还未学习的小伙伴儿们做个了解,先从hibernate开始,作为SSH三大框架之一,尤其是对数据进行操作的框架,其无疑使应该被重视的。  

  一. 首先我们先创建一个持久化类所谓持久化类,即JavaBean类和映射文件的结合,持久化类有几个编写规则需要说一下:

      需要提供无参数的构造方法。
      类的属性需要私有,对私有的属性提供public的get和set方法。
      提供一个唯一标识(OID)的属性与表的主键对应。
      Java里面使用地址区分是否是同一个对象。数据库中是通过主键区分是否是同一个记录。Hibernate通过唯一标识区分是否在内存中是同一个对象。
      类不要使用final修饰。
      类中的属性尽量使用包装类类型。

  

   JavaBean就不再啰嗦了,这里说一下映射文件,映射文件命名规则为 类名.hbm.xml,放在与JavaBean同一个包下,配置如下:

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
	<!-- ORM:Object Relational Mapping,将实体类O和数据库的表R 建立映射关系 -->
	<class name="实体类全类名" table="表名">
		<!-- 类中的属性与表中的主键对应 -->
		<id name="id" column="id">
			<generator class="native"/>
		</id>
		<!-- 类中的属性与表中的字段对应 -->
		<property name="name" column="name"/>
		        ......
	</class>
</hibernate-mapping>
         
                                                                          

    

  这里约束如上,从Web App Libraries---hibernate-mapping-3.0.dtd中拷出,这里特别要说的是,实体类中必须有一个属性和表中的主键相对应,generator是主键的生成策略,identity一般用于主键自增长的数据库,如mysql,db2,Sequemce一般用于有序列的数据库,如oraclenative则是自动判断数据库用于适合的配置,所以这里我们选择native。当然也可以用注解或者自动生成的方式配置映射。

  二.接下来配置它的核心配置文件,默认文件名为hibernate.cfg.xml,放在src下,配置如下

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
	"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
	"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
	<session-factory>
		<!-- 连接数据库的信息 -->
		<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
		<property name="hibernate.connection.url">jdbc:mysql:///hibernate</property>
		<property name="hibernate.connection.username">账户</property>
		<property name="hibernate.connection.password">密码</property>
		
		<!-- 数据库的方言:根据底层的数据库生成不同的SQL -->
		<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
		<!-- 配置显示SQL -->
		<property name="hibernate.show_sql">true</property>
		<!-- 配置格式化SQL -->
		<property name="hibernate.format_sql">true</property>
		<!-- 配置hbm2ddl -->
		<property name="hibernate.hbm2ddl.auto">update</property>
		
		<!-- 加载映射文件 -->
		<mapping resource="这里是映射文件"/>
	</session-factory>
</hibernate-configuration>
  约束如图上Web App Libraries---hibernate-configuration-3.0.dtd,这里特别说一下hbm2ddl的配置,一般用crete和update,create一般用在测试的时候,意思是每次都会创建一个新的表,update表示在原表上更新,如果有小伙伴在测试的时候用create可能会导致错误,这个之后再说,还有,配置了映射文件的话别忘了加载!
同时,考虑到安全问题,还应该增加隔离级别这一条件

 

<!-- 设置事务的隔离级别 -->
<property name="hibernate.connection.isolation">4</property>

  三.hibernate的几个方法

  Configuration对象,主要作用是加载核心配置文件和加载映射文件:

Configuration cfg = new Configuration().configure();
  SessionFactory
SessionFactory用于管理session,管理二级缓存,线程安全,通常一个项目创建一个SessionFactory就行了,因为每次都会用到这些方法,所以一般将它们抽取为一个工具类HibernateUtils:

 

public class HibernateUtils {

	private static final Configuration configuration;
	private static final SessionFactory sessionFactory;
	
	static{
		configuration = new Configuration().configure();
		sessionFactory = configuration.buildSessionFactory();
	}
	
	public static Session openSession(){
		return sessionFactory.openSession();
	}
}
  但是因为会进行事务的管理,为了避免代码入侵并且保证方法都在一个事务中,一般会将session绑定到当前线程,所以将工具类改造如下

 

package com.wkesi.utils;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtils {
  private static final Configuration configuration;
  private static final SessionFactory sessionFactory;
  
  static{
	  configuration=new Configuration().configure();
	  sessionFactory=configuration.buildSessionFactory();
  }
  //获取当前线程绑定的会话
  public static Session getCurrentSession(){
	  return sessionFactory.getCurrentSession();
  }
  
  public static Session openSession(){
	  return sessionFactory.openSession();
  }
	
}
  那同时要在核心配置文件hibernate.cfg.xml中增加一条

<!-- 配置session绑定本地线程 -->
<property name="hibernate.current_session_context_class">thread</property>

  四,一些定义

  既然说到了session,那么session又是什么东西呢?其实小伙伴儿不妨把它理解为JDBC中的connection,它是hibernate框架中代码和数据库的桥梁,维护了hibernate的一级缓存,那么缓存又是什么呢?官方一点就是介于应用程序和永久性数据存储源之间,其作用是降低程序直接读取数据库的频率,通俗一点就是一块空间与应用程序和数据库相连,在用hibernate查询对象的时候,会先从缓存中查找属性的OID,如果找到了就会直接从缓存中取出,不会再查询数据库了,这样就减少了查询数据库的次数,提升了性能,响应的,如果找不到就会从数据库中获取,并且将本条对象存入一级缓存以便下次获取。

  快照,提到缓存就不得不说快照,这是持久态对象自动更新的原因,首先普及一下hiberbate中对象的三种状态

  1)瞬时态,是直接用实体类new出来的对象,不存在持久化标识OID,且未被session管理;
  2)持久态,存在持久化表识,并被session管理,如直接查询出来的对象;
  3)脱管态,存在持久化表识OID,但未被session管理
接下来给出hibernate的一个测试代码,并解释三种状态

  

  持久态在被存入数据库的时候,一级缓存和快照区都会有记录,一旦其被查询到且改变,在事务提交的时候tx.commit(),会更新缓存中的记录,然后缓存区记录与快照区比对,若比对结果一样就不更新数据库,若比对结果不一样就会自动更新数据库,这就是持久态对象自动更新数据库的原因。
接下来给出几个简单的案例来操作hibernate更新数据库:

  Session保存某个对象

  public void demo1(){
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		
		Customer customer = new Customer();
		customer.setCust_name("名字");
		
		session.save(customer);// 保存对象
		
		tx.commit();
		session.close();
	}
  Session中修改某个对象的方法

public void demo3(){
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();		
		先查询再修改.
		Customer customer = session.get(实体类的字节码文件, 4l);
		customer.setCust_name("名字");
		
		瞬时态对象自动更新!!!!!!
		
		tx.commit();
		session.close();
	}

 Session删除某个对象的方法

public void demo4(){
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
	先查询,在删除
		Customer customer = session.get(Customer.class, 3l);
		session.delete(customer);		
		tx.commit();
		session.close();
	}
  Session查询某个对象
  这里有两种方法,get和load
Customer customer = session.get(Customer.class, 100l)
Customer customer = session.load(Customer.class, 300l)

 那么它们又有什么区别了,这就说到hibernate自带的一种优化机制了!延迟加载!Load方式就应用了这一机制,那么它和普通get方法有什么区别呢?
  get方法采用的是立即加载,执行到该行代码的时候,马上发送SQL语句进行查询。查询之后返回的是真实对象本身,查询一个找不到的对象返回null.
load方法采用的是延迟加载(lazy),执行到改行的代码的时候,不会马上发送SQL语句,只有真正使用这个对象的时候(使用这个对象的普通属性的时候)才会发送SQL语句。比如使用customer对象的cust_name属性的时候,才会真正查询,load方法返回的是代理对象。(产生的是Customer的子类对象,这也就解释了为什么实体类的修饰不能为final),查询一个找不到的对象抛出异常:ObjectNotFoundException

 五.hibernate中实体类一对一,多对多的配置

 一般我们会遇到这么一种情况,一个客户有多人在维护关系,所以对应关系是一个客户对应很多联系人,将客户和联系人分别创建实体类并建表,这就是典型的一对多关系,建表如下:
【客户的实体】

public class Customer {
	private Long cust_id;
	private String cust_name;
	private String cust_source;
	private String cust_industry;
	private String cust_level;
	private String cust_phone;
	private String cust_mobile; 
	
	// 联系人的集合:
	private Set<LinkMan> linkMans = new HashSet<LinkMan>();
}

【联系人的实体】

public class LinkMan {
	private Long lkm_id;
	private String lkm_name;
	private String lkm_gender;
	private String lkm_phone;
	private String lkm_mobile;
	private String lkm_email;
	private String lkm_qq;
	private String lkm_position;
	private String lkm_memo;
	
	// private Long lkm_cust_id;
	private Customer customer;// 联系人对应的客户的对象
}
  注意,这里客户对应很多联系人,所以用set对象表示,而每一个联系人对应一个客户,所以创建一个属性表示。
联系人的映射,其它不变,额外配置多对一映射 
<!-- 在多的一方配置many-to-one -->
		<!-- 
			many-to-one标签:用来描述多对一的关系配置。
				* name		:一的一方的对象的属性名称。
				* class		:一的一方的类的全路径
				* column	:外键的名称
		 -->
		<many-to-one name="customer" class="com.itheima.hibernate.domain.Customer" column="lkm_cust_id"/>
 客户的映射,其它不变,额外配置一对多映射

<!-- 配置一对多的关联映射 -->
		<!-- 
			set标签:用来描述一的一方存放的多的一方的集合
				* name:多的一方的集合属性名称
		-->
		<set name="linkMans">
			<!--
				key标签:
					* column多的一方的外键的名称
			-->
			<key column="lkm_cust_id"/>
			<!-- 
				one-to-many标签:描述一对多的关系
					* class:多的一方的类的全路径
			 -->
			<one-to-many class="com.itheima.hibernate.domain.LinkMan"/>
		</set>
  此时为了更好的表示关系和操作数据,我们再添加级联属性,对客户,在<set>标签上配置cascade="save-update,delete",对于联系人,在在<many-to-one>标签上配置cascade="save-update,delete",那么在进行添加或者删除的时候,就会级联添加和删除,大家有没有想到省市联动呢?确实很像哦~那么如果是多对多的话,只要同时在实体类中添加set字并在映射文件中配置set属性就行了哦

 六.语句

  这里单说查询语句,hibernate共有五种查询方式,分别是对象图导航查询,OID检索查询,HQL查询,QBC查询,SQL检索查询,这里每种查询都会涉及到简单的一部分,更加复杂的限于篇幅还要小伙伴儿们多多学习了

  首先来看对象图导航查询

 

@Test
	public void demo1(){
		Session session = HibernateUtils.getthreadSession();
		Transaction tx=session.beginTransaction();
		
		//对象图导航检索是根据已经加载的对象,导航到他的关联对象,前提必须配置了多对一的映射关系
		LinkMan linkMan = session.get(LinkMan.class, 1l);
		Customer customer = linkMan.getCustomer();
		
		System.out.println(customer);
		tx.commit();
		 
	}

  OID检索查询

 

@Test
	public void demo2(){
		Session session = HibernateUtils.getthreadSession();
		Transaction tx=session.beginTransaction();
		//通过查询OID索引
		Customer customer1 = session.get(Customer.class, 1l);
		Customer customer2 = session.load(Customer.class, 1l);
		
		System.out.println(customer1);
		System.out.println(customer2);
		
		tx.commit();
	}

 HQL查询,这里列举几个比较常用的

 

/**
	 * HQL基本查询
	 */
	@Test
	public void demo3(){
		Session session = HibernateUtils.getthreadSession();
		Transaction tx=session.beginTransaction();
		//查询全部
		Query query = session.createQuery("from Customer");
		List<Customer> list = query.list();
		for (Customer customer : list) {
			System.out.println(customer);
		}
		tx.commit();
	}
	
	/**
	 * HQL起别名查询
	 */
	@Test
	public void demo4(){
		Session session = HibernateUtils.getthreadSession();
		Transaction tx=session.beginTransaction();
		
		/*Query query = session.createQuery("from Customer c");
		List<Customer> list = query.list();
		for (Customer customer : list) {
			System.out.println(customer);
		}*/
		
		Query query = session.createQuery("select c from Customer c");
		List<Customer> list = query.list();
		
		for (Customer customer : list) {
			System.out.println(customer);
		}
		
		
		tx.commit();
	}
	
	/**
	 * HQL排序检索
	 */
	@Test
	public void demo5(){
		Session session = HibernateUtils.getthreadSession();
		Transaction tx=session.beginTransaction();
		
		Query query = session.createQuery("from Customer order by cust_id");
		List<Customer> list = query.list();
		
		for (Customer customer : list) {
			System.out.println(customer);
		}
		
		tx.commit();
	}
	
	/**
	 * HQL条件检索
	 */
	@Test
	public void demo6(){
		Session session = HibernateUtils.getthreadSession();
		Transaction tx=session.beginTransaction();
		
		Query query = session.createQuery("from Cudtomer where cust_name=?");
		query.setParameter(0, "小明");
		List<Customer> list = query.list();
		for (Customer customer : list) {
			System.out.println(customer);
		}
		
		tx.commit();
	}
	
	/**
	 * HQL按名称绑定参数查询
	 */
	@Test
	public void demo7(){
		Session session = HibernateUtils.getthreadSession();
		Transaction tx=session.beginTransaction();
		
		Query query = session.createQuery("from Cudtomer where cust_name=:aaa");
		query.setParameter("aaa", "小明");
		List<Customer> list = query.list();
		for (Customer customer : list) {
			System.out.println(customer);
		}
		
		tx.commit();
	}
	
	/**
	 * HQL的分组统计查询
	 */
	@Test
	public void demo8(){
		Session session = HibernateUtils.getthreadSession();
		Transaction tx=session.beginTransaction();
		//聚集函数的使用
		/*Query query = session.createQuery("select count(*) from Customer");
		Long result = (Long) query.uniqueResult();
		System.out.println(result);*/
		
		//分组
		
		tx.commit();
	}

 QBC检索

  排序

@Test
	/**
	 * 排序查询
	 */
	public void demo2(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		
		Criteria criteria = session.createCriteria(Customer.class);
		// 设置排序:
		//criteria.addOrder(Order.asc("cust_id"));// 升序
		criteria.addOrder(Order.desc("cust_id"));// 降序
		List<Customer> list = criteria.list();
		
		for (Customer customer : list) {
			System.out.println(customer);
		}
		tx.commit();
	}

  条件

@Test
	/**
	 * 条件查询
	 */
	public void demo3(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		
		Criteria criteria = session.createCriteria(Customer.class);
		// criteria.add(Restrictions.like("cust_name", "%%"));
		criteria.add(Restrictions.like("cust_name", "", MatchMode.ANYWHERE));
		criteria.add(Restrictions.eq("cust_source", "互联网"));
		List<Customer> list = criteria.list();
		for (Customer customer : list) {
			System.out.println(customer);
		}
		tx.commit();
	}

  分页

@Test
	/**
	 * 分页查询
	 */
	public void demo4(){
		Session session = HibernateUtils.getCurrentSession();
		Transaction tx = session.beginTransaction();
		
		Criteria criteria = session.createCriteria(LinkMan.class);
		criteria.setFirstResult(10);
		criteria.setMaxResults(10);
		List<LinkMan> list = criteria.list();
		for (LinkMan linkMan : list) {
			System.out.println(linkMan);
		}
		tx.commit();
	}
  hibernate就到这里吧,要想掌握hibernate还需要小伙伴儿们更深入的学习,请期待下一个框架.....下期见


 

 


 







     







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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值