Hibernate学习笔记二(持久化类与一级缓存)

  • 注:这是笔者在学习时的小小记录,只是为了对自己的知识查缺补漏,有可能有些地方写错,仅供参考

持久化类

  • 持久化类的简介

一般当一个类有与之对应的映射文件,那么该类就是就是一个持久化类

  • 持久化类的编写规范
  1. 持久化类必须满足javabean的编写规范,注意一定要有空构造
  2. 持久化类要有一个OID(标识属性)
    原因:OID是识别不同对象的依据
  3. 持久化类最好不要使用final修饰
    原因:final修饰的类无法被继承,但是load返回的是持久化类的子类的代理对象,如果使用final修饰,那么延迟加载就会失效
  • OID的增长方式

最常用的是native和uuid
native会根据使用的数据库选择其数据库的自增长方式,适用于数值型的主键
uuid是随机生成字符串,适用于字符串型的主键

  • 核心配置文件模板
<?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的核心配置 -->
<hibernate-configuration>
	<!-- 配置session工厂,用于生产session
			session类似于数据库的connection
			此处以MySQL为例
			配置参数可在配置文件hibernate-release-5.0.7.Final\project\etc\hibernate.properties中查找
	 -->
	<session-factory>
		<!-- 配置MySQL的连接驱动 -->
		<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
		<!-- 配置MySQL数据库的连接地址 -->
		<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate</property>
		<!-- 配置连接数据库的用户名 -->
		<property name="hibernate.connection.username">root</property>
		<!-- 配置连接数据库的密码 -->
		<property name="hibernate.connection.password">123456</property>
		<!-- 配置连接数据库的方言
			相当于告诉hibernate生产的SQL语句要符合MySQL的编写规范
		 -->
		<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
		<!-- 配置让hiebernate使用哪种数据库连接池
				此处使用c3p0
		 -->
		<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
		<!-- 配置控制台显示生成的SQL语句 -->
		<property name="hibernate.show_sql">true</property>
		<!-- 配置显示的SQL语句是否格式化
				作用:打印好看
		 -->
		<property name="hibernate.format_sql">true</property>
		<!-- 配置是否自动创建表
				create-drop:没表自动创建,有表删除后创建,最后全删除
				create:没表自动创建,有表删除后创建
				update:没表自动创建,有表直接使用
				validate:默认值,不会自动创建表
		 -->
		<property name="hibernate.hbm2ddl.auto">update</property>
		<!-- 使用currentSession所需要的配置 -->
		<property name="hibernate.current_session_context_class">thread</property>
		<!-- 加载java类与表字段的映射文件
				resource:映射文件的位置,使用src下全路径
		 -->
		<mapping resource="com/wzm/entity/Customer.hbm.xml"/>
		<mapping resource="com/wzm/entity/User.hbm.xml"/>
	</session-factory>
</hibernate-configuration>
  • 持久化类的对象的状态

由持久化类实例化的对象有三种状态:瞬时态、持久态、脱管态

瞬时态:对象既没有设置OID的值,也没有被session管理,说白了就是一个刚刚new出来的对象

持久态:对象既有OID值,也被session管理,简单来说就是从数据库查询出来的初始对象或者保存到数据库中的对象都是持久态

脱管态:就是脱离session管理的对象,只有OID值,比如从数据库查询得到对象后关闭session,该对象就是脱管态

一级缓存

  • 一级缓存简介

在hibernate中提供了许多优化性能的机制,其中一级缓存就是一个优秀的优化机制,一级缓存就是在hibernate进行增改查操作时,都会先和一级缓存打交道,如果在一级缓存中得不到自己想要的才会去和数据库打交道,这样的机制降低了对数据库的访问,减少数据库的压力。

  • 一级缓存的一个底层实现

当我们直接修改查询数据库返回的对象时,当事务提交就会直接执行更新操作,而不需要我们再写更新语句,这是因为在一级缓存中有两个区,一个是存储区,一个是快照区,当我们从数据库中查询得到对象时,hibernate会把这个对象复制放在存储区一份,快照区一份,当我们直接修改这个对象时,hibernate会把修改后的对象放在存储区中,快照区不变,一旦事务提交,hibernate会比较存储区和快照区是否一致,不一致就执行更新操作。

  • 一级缓存的关闭方式
  1. session.close()—当session关闭,一级缓存也会跟着关闭
  2. session.clear()—这是清除一级缓存的内容
  3. session.evict(Object object)—这是指定清除一级缓存中的某各对象
  • 一级缓存的代码实例
/**
* 	一级缓存对插入和查询的作用
 */
@Test
public void test5() {
	//获取session,HibernateUtil是自己写的工具类,详情可看笔记一
	Session session = HibernateUtil.openSession();
	//开启事务
	Transaction transaction = session.beginTransaction();
	//创建一个对象
	User user = new User();
	user.setUname("小明");
	user.setAge(18);
	//保存对象到数据库
	Serializable uid = session.save(user);
	/*
	 * hibernate有一个优化机制为一级缓存,在做增加操作时,在保存到数据库时同时会复制一份放到一级缓存中
	 * 	增加保存操作会用多态方式返回一个OID
	 * 	进行查询会先去一级缓存中查询,查不到才到数据库查找
	 * 	根据控制台可以发现在插入之后查询,只会生成一条插入的SQL语句,说明查询在一级缓存中查询到了
	 * 	一级缓存不仅在增加操作起作用,在查询和更新操作时都起作用
	 */
	//利用保存操作返回的OID进行查询对象
	User user2 = session.get(User.class, uid);
	System.out.println(user2.getUname());
	//提交事务
	transaction.commit();
	//关闭资源
	HibernateUtil.close(session);
}

/**
 * 	一级缓存对更新操作的作用
 */
@Test
public void test6() {
	//获取session,HibernateUtil是自己写的工具类,详情可看笔记一
	Session session = HibernateUtil.openSession();
	//开启事务
	Transaction transaction = session.beginTransaction();
	//从数据库获取对象
	User user = session.get(User.class, 1L);
	//对对象进行更新
	user.setAge(88);
	/*
	 * 	当我们通过get或者load获取到对象后,通过对对象进行属性的更新操作之后,不需要在update更新代码
	 * 	session.update(user);
	 * 	只要我们提交事务之后,hibernate会自动生成更新的SQL语句
	 */
	//提交事务
	transaction.commit();
	//关闭资源
	session.close();
}

对事务语句的优化

  • getCurrentSession()方法介绍

由于hibernate中除了查询都需要进行事务操作,在之间事务都写在了Dao层,这样不利于后期业务处理,后期可能一个事务中要包含很多对数据库的操作,因此我们应该将事务写到service层,但是写到service中,我们需要保证Dao层使用的session都是同一个session,在这里需要使用到currentSeesion,这是由sessionFactory工厂对象通过getCurrentSession获取到的,它的底层实现是LocalThread,LocalThread实际上就是一个Map对象,里边键就是当前的线程对象,这样就保证每一个线程都对应着同一个session对象。

  • 使用方法

要使用currentSession需要在核心配置文件中添加一条配置
currentsession需要的配置参数

  • 代码案例
import org.hibernate.Session;
import org.hibernate.Transaction;

import com.wzm.entity.User;
import com.wzm.util.HibernateUtil;

/**
 * 	currentSession的作用
 * 	currentSession底层是用LocalThread实现的,即一个线程对应一个session对象,这样能够保证
 * 	service层和dao层之间在开启事务时使用的是同一个session
 * 	这样就可以将事务写在service,而不用放在dao层
 */

/**
 * 	Service层
 * @author WZM
 *
 */
public class Service {
	
	//主方法
	public static void main(String[] args) {
		Service service = new Service();
		service.test();
	}
	void test() {
		/*
		 * 	通过自定义的工具类获取currentSession,
		 * 	currentSession是有sessionFactory对象的getCurrentSession获取的
		 * 	注意:如果currentSession不是同一个sessionFactory获取到的会报错:
		 * 	save is not valid without active transaction
		 * 	因此可以将获取session工厂的方法抽取成工具类
		 * */
		Session session = HibernateUtil.getCurrentSession();
		//service层开启事务
		Transaction transaction = session.beginTransaction();
		//调用Dao层的方法
		Dao dao = new Dao();
		dao.test();
		//提交事务
		transaction.commit();
		//无需手动关闭session,currentSession会在结束后自动关闭
	}
}

/**
 * 	Dao层
 * @author WZM
 *
 */
class Dao {
	
	void test() {
		//获取currentSession
		Session session = HibernateUtil.getCurrentSession();
		//事务开启交于service层,无需开启事务,直接进行保存操作
		User user = new User();
		session.save(user);
		//无需手动关闭session,currentSession会在结束后自动关闭
	}
}

总结

Hibernate为我们提供了许多优化机制,如延迟加载,一级缓存,currentSession,还有二级缓存等,这些机制都帮助我们更好的对数据库进行访问,同时也提高了代码的效率。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值