Hibernate框架第二课

封装一个方法 获取session对象

hibernate通过session对象操作数据库,封装成方法方便使用

public class HibernateUitl {
	private static SessionFactory sessionFactory;
	static {
		// 读文件
		Configuration configuration = new Configuration().configure();
		// 创建session工厂
		sessionFactory = configuration.buildSessionFactory();
	}
	// 获取session的方法
	// 创建一个全新的session
	public static Session getOpenSession() {
		return sessionFactory.openSession();
	}
	// 获取当前使用的session
	// 注意: 使用该方法 必须在主配置文件中配置一下
	public static Session getCurrentSession() {
		return sessionFactory.getCurrentSession();
	}
}

在主文件中配置getCurrentsession

<!-- 
	注意: 使用getCurrentsession方法 必须配置
	配置的是 让当前的session与线程绑定
-->
<property name="hibernate.current_session_context_class">thread</property>

Java开发中的模拟MVC的开发模式:

分层思想: 1.web层   2.逻辑层   3.数据层


使用Hibernate写项目与JDBC连接池的不同之处在于: 

1.需要搭建主配置文件 和 实体类的映射文件

2.DAO层中操作数据库sql语句的对象

  Hibernate通过获取session对象来操作数据库

  JDBC通过QueryRunner获取数据库连接对象操作数据库

Ensample:

// Hibernate插入customer到数据库
@Override
public boolean addCustomer(Customer customer) throws SQLException {
	// 获取session
	// (要获取同一个session来操作数据库)
	Session session = HibernateUitl.getCurrentSession();
	Serializable id = session.save(customer);
	if (id != null) {
		return true;
	}
	return false;
}
// JDBC插入sort到数据库
// 获取数据库连接对象
private QueryRunner queryRunner = new QueryRunner(DataSourceUtil.getDataSource());
// 添加商品
@Override
public boolean addSort(Sort sort) throws SQLException {
	String sql = "insert into sort values(null,?,?,?)";
	Object[] obj = {sort.getSname(),sort.getSprice(),sort.getSdesc()};
	int row = queryRunner.update(sql,obj);
	if (row > 0) {
		return true;
	}
	return false;
}
在Service层开启事务的方法

Ensample: 注册操作

 1.首先查询数据库中有没有这个人

 2.判断没这个人再插入数据

   这两个操作应该放入同一个事务中执行

事务中 可以包裹 多个对数据库的操作

Session在Service层开启更合适

注意: 为保证调用的方法处在同一个事务中 

需要使用getCurrentSession()方法获取session对象(Service层和DAO层都要使用)

使用getCurrentSession()方法时,事务提交后系统会自动为你释放Session

@Test
public void fun2() {
// 注意: 使用getCurrentSession()方法  session1和session2是同一个对象
Session session1 = HibernateUitl.getCurrentSession();
Session session2 = HibernateUitl.getCurrentSession();
System.out.println(session1==session2);
}

在DAO层中添加customer的方法

@Override
public boolean addCustomer(Customer customer) {
	// 应该在service层中开启事务
	// 来处理调用数据方法的逻辑
	// 注意: 保证调用的dao层中方法
	//		处在同一个事务当中
	Session session = HibernateUitl.getCurrentSession();
	Transaction transaction = session.beginTransaction();
		
	boolean isAdd = false;
	// try--catch处理异常
	// 在操作数据库失败时 来进行回滚
	try {
		isAdd = dao.addCustomer(customer);
	} catch (SQLException e) {
		// 注意: 打印出错误信息
		e.printStackTrace();
		// 失败后进行回滚
		transaction.rollback();
		isAdd = false;
	}
	transaction.commit();
	return isAdd;
}
数据库的隔离级别

在主配置文件中设置数据库的隔离级别

(etc/hibernate.properties文件)

默认的隔离级别 4 (1|2|4|8)

#hibernate.connection.isolation 4

1.脏读  一个事务读取了另一个事务的

2.不可重复读

3.幻读(虚读)

隔离级别:

READ UNCOMMITED 读未提交 1 2 3     1

READ COMMITED 读已提交     2 3     2

REPEATABLE READ 可重复读     3     4

Serializable 串行化      都能避免   8

隔离级别使用1个字节来存储的

// 设置隔离级别
<property name="hibernate.connection.isolation">4</property>
主键的分类与配置(使用Hibernate 数据库中必须要有主键)

主键的分类:

1.自然主键

   表里面有一个字段符合主键的规则  就直接用这个字段作为主键

2.代理主键

   表里面没有一个字段符合主键的规则  可以自己创建一个id作为主键 这个键就叫代理主键

主键生成策略(7种)

identity
主键自增 使用数据库当中的主键自增
插入时 打印sql 不会插入id 
				
increment
主键自增 由hibernate来管理
插入数据时 会先去数据库中查询当前的最大id
然后 把查出来的id+1 在插入数据
				
guid
全球不重复的唯一标识32位的字符串
注意: id必须使用字符串类型
				
native(最常用 三合一)
根据你使用的数据库类型 来选择使用
下面三个策略之一:
所有数据库不是支持identity
就是支持 序列
identity + 序列 + hilo
				
hilo(高低位算法)
将主键交给hibernate处理  
使用自己的算法 帮你维护主键
				
assigned
由你自己维护主键 插入数据时需要有主键
使用的是代理主键
				
sequence序列   oracle数据库默认使用

配置主键

<generator class="native"></generator>
hibernate操作对象的三种状态

1.瞬时态    没有id  与session没有产生关系(还没有调用session方法)

2.持久态    有id    已跟session产生关系

3.游离态    有id    与session没有产生关系

User user = new User(); // 瞬时态(创建对象)
user.setUsername("wanglong");
user.setPassword("66666");
		
session.save(user);  // 持久态(按id存的 已有id) 调用方法	
		
transaction.commit();
session.close();  // 游离态(session释放)

注意: hibernate会在提交事务之后 把持久态的对象 同步到数据库中

@Test
public void fun3() {
	// 保存一个用户
	Session session = HibernateUitl.getOpenSession();
	Transaction transaction = session.beginTransaction();
	
	User user1 = session.get(User.class, 1);
	User user2 = session.get(User.class, 1);
	User user3 = session.get(User.class, 1);
	User user4 = session.get(User.class, 1);
	User user5 = session.get(User.class, 1);
	// 思考: 打印几条sql语句? 为什么?
	System.out.println(user2 == user5);
		
	transaction.commit();
	session.close();  
}

打印结果 只有一条sel查询语句(可自行测试)

原因:

当调用get方法去数据库查询时

数据库返回的结果集 会被hibernate封装成对象

并且保存一份在缓存当中,还会将对象保存到快照中一份,返回缓存中的对象

再次查询get方法时 

hibernate会先到缓存中查找有没有该id的对象(通过id比对)

有就直接返回缓存中的对象(不会去数据库中查询,没有使用sql语句)

没有 就用sql去查询数据库

@Test
public void fun2() {
	Session session = HibernateUitl.getOpenSession();
	Transaction transaction = session.beginTransaction();
	// 总结: hibernate会在你提交事务之后 把持久态的对象 同步到数据库中
	// 使用get方法查询一个对象
	User user = session.get(User.class, 1);
	user.setUsername("kunner");
		
	transaction.commit();
	session.close();  
}

会打印两条sql语句 get方法时运行了一次select语句

                commit提交时 运行了一次update语句(setUsername)

/*
* 快照
* get方法查询时
* hibernate会把返回的结果集 保存到缓存中一份 快照中一份
* 当你最终提交事务操作数据库的时候
* hibernate会对比缓存与快照中的数据
* 一样就不存 反之 同步到数据库
*/
@Test
public void fun4() {
	Session session = HibernateUitl.getOpenSession();
	Transaction transaction = session.beginTransaction();
		
	User user = session.get(User.class, 1);
	user.setUsername("penger11");
	user.setUsername("ruier11");
	session.update(user);
	// 最终同步到数据库时 会将缓存中的对象 和 快照中的对象进行对比 一样 就不同步到数据库中,反之同步缓存中的到数据库
	transaction.commit();
	session.close();  
}

同样打印了两条sql语句   get方法时的select 和 提交时的update语句

// 测试 new对象  瞬时态 -> 游离态->持久态
@Test
public void fun5() {
	Session session = HibernateUitl.getOpenSession();
	Transaction transaction = session.beginTransaction();
		
	User user = new User();  // 瞬时态
	user.setId(1);  // 游离态
	user.setUsername("haier");
	// update方法 hibernate会把该对象 保存到缓存中
	session.update(user);  // 持久态	
	User user2 = session.get(User.class, 1);	
	transaction.commit();
	session.close();  
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值