Hibernate快速入门(1)

目录

Hibernate中的实体规则
Hibernate中的对象状态
Hibernate中的一级缓存
Hibernate中的事务
Hibernate中的批量查询

Hibernate中的实体规则

实体类创建的注意事项

  1. 持久化类提供无参数构造。这个是因为Hibernate创建对象运用的是反射技术也就是我们的newInstance()方法,而该方法默认走的是空参构造。
  2. 成员变量私有,提供共有get/set方法访问。也就是说需要提供属性。这里的属性指的是get/set方法而不是成员变量,需要特别注意!
  3. 持久化类中的属性,应尽量使用包装类型。这个很容易想,使用基本类型是没办法存储null值的。
  4. 持久化类需要提供OID,与数据库中的主键列对应。因为Hibernate判断是否为同一个持久化类的依据是OID。类似于Java中通过地址判断是否为同一个对象,Hibernate就是根据OID来进行区分的,Hibernate是不允许在内存中出现两个OID相同的持久化对象的。
  5. 持久化类尽量不要使用final进行修饰。Hibernate使用cglib代理生成代理对象。代理对象是继承被代理对象。如果被final修饰,将无法生产代理,那么Hibernate的延迟加载策略(一种优化手段)就会失效。

主键类型

  • 自然主键(少见):把具有业务含义的字段作为主键,称之为自然主键。表的业务列中,有某业务列符合,必须有,并且不重复的特征时,该列可以作为主键使用.

  • 代理主键(常见):把不具备业务含义的字段作为主键,称之为代理主键。表的业务列中,没有某业务列符合,必须有,并且不重复的特征时,创建一个没有业务意义的列作为主键

主键生成策略

代理主键:

  • identity:主键自增。由数据库来维护主键值。录入时不需要指定主键。
  • sequence:Oracle中的主键生成策略。
  • increment(了解):主键自增。由Hibernate来维护。每次插入前会先查询表中id最大值。+1作为新主键值。
  • hilo(了解):高低位算法。主键自增。由Hibernate来维护。开发时不使用。
  • native:hilo+sequence+identity自动三选一策略。
  • uuid:产生随机字符串作为主键。主键类型必须为String类型。

自然主键:

  • assigned:自然主键生成策略。Hibernate不会管理主键值。由开发人员自己录入。

我们可以发现,昨天我们就使用了native代理主键生成策略。


Hibernate中的对象状态

对象的三种状态

  • 瞬时状态:不存在持久化标识OID,没有在Session缓存中。
  • 持久态:存在持久化标识OID,在Session缓存中。
  • 脱管态:存在持久化标识OID,没有在Session缓存中

我们可以写个小demo来理解持久化对象的三种状态。

        @Test
	/**
	 * 测试持久化对象的三种状态
	 */
	public void demo1(){
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		Customer customer = new Customer();//瞬时态,没有oid也没有在session缓存中
		customer.setCust_name("Dokyun");
		session.save(customer);//持久态,有oid,存在session缓存中
		tx.commit();
		session.close();
		System.out.println(customer);//脱管态,有oid,但是没有session缓存中
	}

customer对象由new关键字创建,此时还未与Session进行关联,它的状态为瞬时态;在执行了session.save(customer)操作后,customer对象纳入了Session的管理范围,这时的customer对象变成了持久态对象,此时Session的事务还没有被提交;程序执行完commit()操作并关闭了Session后,customer对象与Session的关联被关闭,此时customer对象就变成了脱管态。

三种状态的转换图

Hibernate中的一级缓存

证明一级缓存的存在

下面我们来看一个demo

	@Test
	/**
	 * 测试Hibernate一级缓存的存在
	 */
	public void demo2(){
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		Customer c1 = session.get(Customer.class, 1l);
		Customer c2 = session.get(Customer.class, 1l);
		System.out.println(c1==c2);
		tx.commit();
		session.close();
	}

控制台结果:


我们可以发现,我们调用了两次get方法,但是控制只输出了一次sql语句,并且比较c1和c2的结果为true。


在调用get方法查询时,hibernate会先从缓存中查看是否存在需要查询的对象,如果有,直接返回该对象,没有就发送sql进行数据库的查询操作。

一级缓存的内部结构:快照区

Hibernate向一级缓存放入数据时,同时复制一份数据放入到Hibernate快照中,当使用commit()方法提交事务时,同时会清理Session的一级缓存,这时会使用OID判断一级缓存中的对象和快照中的对象是否一致,如果比对不一致,则执行update语句,将缓存的内容同步到数据库,更更新快照;如果一致,则不执行update语句。Hibernate快照的作用就是确保一级缓存中的数据和数据库中的数据一致。

快照区的存在我们也可以写个demo来进行证明:


我们通过get方法拿到了customer持久化对象,先后设置了两次cust_name值,在数据库中,第一条数据的cust_name值原本为google,设置了两次之后,hibernate并没有执行update语句。

结论:快照区的作用减少了不必要的修改语句发送,提高了效率。

进阶知识,学有余力的同学可以看。

下面我们来看一个例子, 

        @Test
	/**
	 * 证明持久化状态,就是持久化对象进入到了session缓存中
	 */
	public void demo4(){
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		Customer c1 = new Customer();
		c1.setCust_id(1l);//设置c1对象的主键,将其变成脱管态
		session.update(c1);//通过update方法,将c1的状态由脱管态变为持久态,也就是说c1进入到了session缓存中
		Customer c2 = session.get(Customer.class, 1l);
		/*
		这个时候执行get方法查询,会先在session缓存中查看是否有主键为1的对象,所以直接就拿到了c1对象,
		注意,从session缓存中取到的c1对象,是没有快照的,因为没有经过数据库。
		*/
		tx.commit();//这个时候进行事务提交,会比对快照和缓存中的对象是否一致,但是快照中根本就没有c1对象,所以每次都会执行update方法
		session.close();
	}

Hibernate中的事务

事务

事务特性

  • 原子性:将事务看作物理上不可分割的原子,事务中所包裹的操作,要么全执行,要么全都不执行。
  • 一致性:在事务提交之前和提交之后,所有的数据总量保持一致。
  • 隔离性:提供隔离级别,解决事务并发产生的问题。
  • 持久性:事务提交之后,保证数据提交到持久化存储设备中例如硬盘。
事务并发问题

  1. 脏读:读到了一个人正在操作还未提交的数据。
  2. 不可重复读:两次连续的读取,数据不一致。
  3. 幻/虚读:往往针对的是整表的操作,比如让你把整个表删除,结果有其他人在你删除的期间,加了一条数据。结果一查,以为是空的,结果还有一条。好像出现了幻觉。

事务隔离级别

  1. 读未提交:可能出现上面1、2、3的问题
  2. 读已提交(Oracle默认几倍):可能出现上面2、3的问题
  3. 可重复读(MySql默认级别):可能出现3的问题
  4. 串行化:没有问题,但是效率极低。

如何在Hibernate中指定数据库的隔离级别


在项目中如何管理事务

总原则:业务开始之前打开事务,业务执行之后提交事务。执行过程中如果出现异常,回滚事务。

在dao层操作数据库需要用到session对象.在service控制事务也是使用session对象完成. 我们要确保dao层和service层使用的使用同一个session对象。

在hibernate中,确保使用同一个session的问题,hibernate已经帮我们解决了. 我们开发人员只需要调用sf.getCurrentSession()方法即可获得与当前线程绑定的session对象。

注意1:调用getCurrentSession方法必须配合主配置文件中的一段配置


注意2:通过getCurrentSession方法获得的session对象。当事务提交时。session会自动关闭。不要手动调用close关闭,否则会抛异常。


在我们实际的项目中的话,可以这样操作。

service层


dao层



Hibernate中的批量查询

HQL查询-hibernate Query Language(多表查询,但不复杂时使用)

HQL查询,是面向对象的查询,属于Hibernate独家查询语言

基本查询

	@Test
	/**
	 * HQL语句基本查询
	 */
	public void demo6(){
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		//1.书写HQL语句
		String hql =" from Customer "; 
		//2.根据HQL语句创建查询对象
		Query query = session.createQuery(hql);
		//3.根据查询对象获得查询结果
		List<Customer> list = query.list();
		System.out.println(list);
		
		tx.commit();
		session.close();
	}

条件查询

	@Test
	/**
	 * HQL语句条件查询
	 */
	public void demo7(){
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		//1.书写HQL语句
		String hql =" from Customer where cust_id = 1"; 
		//2.根据HQL语句创建查询对象
		Query query = session.createQuery(hql);
		//3.根据查询对象获得查询结果
		Customer c = (Customer) query.uniqueResult();
		System.out.println(c);
		
		tx.commit();
		session.close();
	}
	@Test
	/**
	 * HQL语句条件查询,通过问号,占位符的方式
	 */
	public void demo8(){
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		//1.书写HQL语句
		String hql =" from Customer where cust_id =?"; 
		//2.根据HQL语句创建查询对象
		Query query = session.createQuery(hql);
		//3.设置参数
		query.setParameter(0, 1l);
		//4.根据查询对象获得查询结果
		Customer c = (Customer) query.uniqueResult();
		System.out.println(c);
		
		tx.commit();
		session.close();
	}

这里的setParameter方法是相当方便的,它不需要去思考这个的类型,无论是long,int都可以设置。

最后还有一种命名站位符,这种方式的好处是不需要数是第几个占位符。

	@Test
	/**
	 * HQL语句条件查询,通过命名占位符的方式
	 */
	public void demo9(){
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		//1.书写HQL语句
		String hql =" from Customer where cust_id = :cust_id"; 
		//2.根据HQL语句创建查询对象
		Query query = session.createQuery(hql);
		//3.设置参数
		query.setLong("cust_id", 1l);
		//4.根据查询对象获得查询结果
		Customer c = (Customer) query.uniqueResult();
		System.out.println(c);
		
		tx.commit();
		session.close();
	}

分页查询

	@Test
	/**
	 * HQL语句分页查询
	 */
	public void demo10(){
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		//1.书写HQL语句
		String hql =" from Customer "; 
		//2.根据HQL语句创建查询对象
		Query query = session.createQuery(hql);
		//3.设置参数,limit ?,?
		query.setFirstResult(1);//从第几条开始抓
		query.setMaxResults(3);//抓多少数据
		//4.根据查询对象获得查询结果
		List<Customer> list = query.list();
		System.out.println(list);
		
		tx.commit();
		session.close();
	}

Criteria查询(适用于单表条件查询)

Hibernate自创的无语句面向对象查询

基本查询

	@Test
	/**
	 * criteria基本查询
	 */
	public void demo1(){
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		Criteria criteria = session.createCriteria(Customer.class);//查询所有customer对象
		List<Customer> list = criteria.list();
		System.out.println(list);
		tx.commit();
		session.close();
	}

条件查询

	@Test
	/**
	 * criteria条件查询// > 				gt
	// >=				ge
	// <				lt
	// <=				le
	// ==				eq
	// !=				ne
	// in				in
	// between and		between
	// like 			like
	// is not null 		isNotNull
	// is null			isNull
	// or				or
	// and				and
	 */
	public void demo2(){
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		//创建criteria对象
		Criteria criteria = session.createCriteria(Customer.class);//查询所有customer对象
		criteria.add(Restrictions.eq("cust_id", 1l));
		Customer customer = (Customer) criteria.uniqueResult();
		System.out.println(customer);
		tx.commit();
		session.close();
	}
分页查询
	@Test
	/**
	 * criteria分页查询
	 */
	public void demo3(){
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		//创建criteria对象
		Criteria criteria = session.createCriteria(Customer.class);//查询所有customer对象
		criteria.setFirstResult(0);
		criteria.setMaxResults(3);
		List<Customer> list = criteria.list();
		System.out.println(list);
		tx.commit();
		session.close();
	}

查询总条数

	@Test
	/**
	 * criteria查询总条数
	 */
	public void demo4(){
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		//创建criteria对象
		Criteria criteria = session.createCriteria(Customer.class);//查询所有customer对象
		criteria.setProjection(Projections.rowCount());
		long count = (Long) criteria.uniqueResult();
		System.out.println(count);
		tx.commit();
		session.close();
	}

原生SQL查询(适用于复杂业务查询)

基本查询

	@Test
	/**
	 * 返回数组List
	 */
	public void demo1(){
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		
		//1.写sql语句
		String sql = "select* from cst_customer";
		//2.创建sql查询对象
		SQLQuery query = session.createSQLQuery(sql);
		//3.调用方法查询结果
		List<Object[]> list = query.list();
		for (Object[] objects : list) {
			System.out.println(Arrays.toString(objects));
		}
		tx.commit();
		session.close();
	}
	@Test
	/**
	 * 返回对象List
	 */
	public void demo2(){
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		
		//1.写sql语句
		String sql = "select* from cst_customer";
		//2.创建sql查询对象
		SQLQuery query = session.createSQLQuery(sql);
		//指定将结果集封装到哪个对象中
		query.addEntity(Customer.class);
		//3.调用方法查询结果
		List<Customer> list = query.list();
		System.out.println(list);
		tx.commit();
		session.close();
	}

条件查询

	@Test
	/**
	 * 条件查询
	 */
	public void demo3(){
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		
		//1.写sql语句
		String sql = "select* from cst_customer where cust_id = ?";
		//2.创建sql查询对象
		SQLQuery query = session.createSQLQuery(sql);

		query.setParameter(0, 1l);
		query.addEntity(Customer.class);
		//3.调用方法查询结果
		
		Customer c = (Customer) query.uniqueResult();
		System.out.println(c);
		tx.commit();
		session.close();
	}

分页查询

	@Test
	/**
	 * 分页查询
	 */
	public void demo4(){
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		
		//1.写sql语句
		String sql = "select* from cst_customer limit ?,?";
		//2.创建sql查询对象
		SQLQuery query = session.createSQLQuery(sql);

		query.setParameter(0, 0);
		query.setParameter(1, 3);
		//将指定结果集封装到哪个对象中
		query.addEntity(Customer.class);
		//3.调用方法查询结果
		List<Customer> list = query.list();
		System.out.println(list);
		tx.commit();
		session.close();
	}


猜你喜欢

转载自blog.csdn.net/u013780676/article/details/80618024
今日推荐