【SSH】Hibernate学习(二)主键生成策略、对象状态、一级缓存、事务、HQL

一、Hibernate中实体规则

1、实体类创建的注意事项

(1)持久化类提供无参构造

(2)成员变量私有,提供共有的get/set方法访问,需提供属性

(3)持久化类中的属性,应尽量使用包装类

(4)持久化类需要提供oid,与数据库当中的主键对应

(5)不要使用final修饰class-Hinbernate使用cglib代理生成代理对象,代理是继承被代理对象,如果被final修饰,将无法生成代理

2、主键类型

自然主键(少见):表的业务列中,有某业务符合,必须有,并且不重复的特征时,该列可以作为主键使用

代理主键(常见):表的业务列中,没有某业务符合,必须有,并且不重复的特征时,创建一个没有业务意义的列作为主键

3、主键生成策略

<!-- generator 主键生成策略
        	   1.increment 由hibernate自己维护自动增长
					底层通过先查询max值,再+1策略
					不建议使用,存在线程并发问题
			   2.identity hibernate底层采用数据库本身自动增长列(mysql)
					例如:mysql auto_increment
			   3.sequence hibernate底层采用数据库序列   ()
					例如:oracle 提供序列
			   4.hilo(了解)   底层算法生成的主键,开发时不使用
								
			   5.native 根据底层数据库的能力选择 identity、sequence 或者 hilo 中的一个。
							##以上策略使用整型,long, short 或者 int 类型
			   6.uuid 采用字符串唯一值 主键类型必须为String类型
							##以上策略 代理主键,有hibernate维护。
			   7.assigned 自然主键,由程序员自己维护。 
        	-->

二、Hibernate中的对象状态

1、对象分为三种状态




2、三种状态的转换


/**
 * 测试对象的三种状态
 * @author Administrator
 *
 */
public class Demo {
	
	@Test
	//查看三种状态
	public void fun1() {
		//1.获得Session
		Session session = HibernateUtils.openSession();
		//2.控制事务
		Transaction tx = session.beginTransaction();
		//3.执行操作
		Customer c = new Customer();//没有id,没有与session关联=>瞬时状态
		
		c.setCust_phone("联想");//瞬时状态
		
		session.save(c);//持久化状态,有id,有关联
		
		//4.提交事务,关闭资源
		tx.commit();
		session.close();//游离\托管状态 有id 没有关联
	}
	
	@Test
	/**
	 * 三种状态特点
	 * save方法:其实不能理解为保存,理解成将瞬时转态转换为持久状态
	 * 主键自增:执行save方法时,为了将对象转化为持久化状态,必须生成id值,所有需执行insert语句执行
	 * increment:执行save方法,为了生成id,会执行查询id最大的sql语句
	 */
	public void fun2() {
		//1.获得Session
		Session session = HibernateUtils.openSession();
		//2.控制事务
		Transaction tx = session.beginTransaction();
		//3.执行操作
		Customer c = new Customer();//没有id,没有与session关联=>瞬时状态
		
		c.setCust_name("联想");//瞬时状态
		
		session.save(c);//持久化状态,有id,有关联
		
		//4.提交事务,关闭资源
		tx.commit();
		session.close();//游离\托管状态 有id 没有关联
	}
	
	@Test
	/**
	 * 三种状态特点
	 * 持久化状态特点:持久化状态对象的任何变化都会同步到数据库中
	 */
	public void fun3() {
		//1.获得Session
		Session session = HibernateUtils.openSession();
		//2.控制事务
		Transaction tx = session.beginTransaction();
		//3.执行操作
		Customer c = session.get(Customer.class, 1l);
		c.setCust_name("阿里云");
		//4.提交事务,关闭资源
		tx.commit();
		session.close();//游离\托管状态 有id 没有关联
	}
}


三、Hibernate进阶-一级缓存

缓存:提高效率,Hibernate中的一级缓存也是为了提高操作数据库的效率

提高效率手段1:提高查询效率


提高效率手段2:减少不必要的修改语句的发送


public class Demo {
	
	@Test
	//证明一级缓存存在
	public void fun1() {
		//1.获得Session
		Session session = HibernateUtils.openSession();
		//2.控制事务
		Transaction tx = session.beginTransaction();
		//3.执行操作
		Customer c1 = session.get(Customer.class, 1L);
		Customer c2 = session.get(Customer.class, 1L);
		Customer c3 = session.get(Customer.class, 1L);
		Customer c4 = session.get(Customer.class, 1L);
		Customer c5 = session.get(Customer.class, 1L);
		
		//4.提交事务,关闭资源
		tx.commit();
		session.close();//游离\托管状态 有id 没有关联
	}
	
	@Test
	//
	public void fun2() {
		//1.获得Session
		Session session = HibernateUtils.openSession();
		//2.控制事务
		Transaction tx = session.beginTransaction();
		//3.执行操作
		Customer c1 = session.get(Customer.class, 1L);
		c1.setCust_name("网易");
		
		//4.提交事务,关闭资源
		tx.commit();
		session.close();//游离\托管状态 有id 没有关联
	}
	
	
	@Test
	//持久化状态对象就是放入session中的对象
	public void fun3() {
		//1.获得Session
		Session session = HibernateUtils.openSession();
		//2.控制事务
		Transaction tx = session.beginTransaction();
		//3.执行操作
		Customer c1 = new Customer();
		c1.setCust_id(1l);
		
		session.update(c1);//将c1放入session
		
		Customer C2 = session.get(Customer.class, 1l);
		
		//4.提交事务,关闭资源
		tx.commit();
		session.close();//游离\托管状态 有id 没有关联
	}
}

四、Hibernate中的事务

1、什么是事务

逻辑上的一组操作,组成这组操作的各个单元,要么一起成功,要么一起失败

2、事务的特性(ACID)


3、事务的并发问题


4、事务的隔离级别



5、如何在Hibernate中配置指定数据库的隔离级别?

在hibernate.cfg.xml中配置:

<!-- 指定Hibernate操作数据库时的隔离级别
			## specify a JDBC isolation level
			#hibernate.connection.isolation 1|2|4|8
			0001 1  读未提交
			0010 2  读已提交
			0100 4 可重重复读
			1000 8 串行化
		 -->
		<property name="hibernate.connection.isolation">4</property>


6、在项目中如何管理事务

业务开始之前打开事务 ,业务执行之后提交事务,执行过程中出现异常,回滚事务

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

在Hibernate中,确保同一个session的问题,Hibernate已经帮我们解决了,我们只需要调用sf.getCurrentSessin方法即可获得当前线程绑定的session对象

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

<!-- 指定session与当前线程绑定 -->
		<property name="hibernate.current_session_context_class">thread</property>

注意2:通过getCurrentSession方法获得的session对象当事务提交时,session会自动关闭,不要手动关闭

7、丢失更新的问题

1. 如果不考虑隔离性,也会产生写入数据的问题,这一类的问题叫丢失更新的问题。
2. 例如:两个事务同时对某一条记录做修改,就会引发丢失更新的问题。
* A事务和B事务同时获取到一条数据,同时再做修改
* 如果A事务修改完成后,提交了事务
* B事务修改完成后,不管是提交还是回滚,如果不做处理,都会对数据产生影响
解决方案有两种
* 悲观锁
* 采用的是数据库提供的一种锁机制,如果采用做了这种机制,在SQL语句的后面添加 for update 子句
* 当A事务在操作该条记录时,会把该条记录锁起来,其他事务是不能操作这条记录的。
* 只有当A事务提交后,锁释放了,其他事务才能操作该条记录

* 乐观锁
* 采用版本号的机制来解决的。会给表结构添加一个字段version=0,默认值是0
* 当A事务在操作完该条记录,提交事务时,会先检查版本号,如果发生版本号的值相同时,才可以提交事务。同时会更新版本号version=1.
* 当B事务操作完该条记录时,提交事务时,会先检查版本号,如果发现版本不同时,程序会出现错误。

4. 使用Hibernate框架解决丢失更新的问题
* 悲观锁(少)
* 使用session.get(Customer.class, 1,LockMode.UPGRADE); 方法

* 乐观锁(比较多)
* 1.在对应的JavaBean中添加一个属性,名称可以是任意的。例如:private Integer version; 提供get和set方法
* 2.在映射的配置文件中,提供<version name="version"/>标签即可。

四、Hibernate中的批量查询

1、HQL查询(Hibernate Query Language)

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

/**
 * hql查询
 * 
 * @author Administrator
 *
 */
public class Demo {

	@Test
	// 基本查询
	public void fun1() {
		// 1.获得Session
		Session session = HibernateUtils.openSession();
		// 2.控制事务
		Transaction tx = session.beginTransaction();
		// 3.执行操作
		
		//hql操作-------------------------------
		
		//1>书写hql语句
		//String hql = "from com.sh.domain.Customer";
		String hql = "from Customer";
		//2>根据hql语句创建查询对象
		Query query = session.createQuery(hql);
		//3>根据查询对象获得查询结果
		List<Customer> list = query.list();
		//Object uniqueResult = query.uniqueResult();
		//Object result = query.getSingleResult();
		System.out.println(list);
		//-------------------------------------
		
		// 4.提交事务,关闭资源
		tx.commit();
		session.close();// 游离\托管状态 有id 没有关联
	}
	
	@Test
	// 条件查询
	//hql语句,不可能出现任何数据库相关的信息的
	public void fun2() {
		// 1.获得Session
		Session session = HibernateUtils.openSession();
		// 2.控制事务
		Transaction tx = session.beginTransaction();
		// 3.执行操作
		
		//hql操作-------------------------------
		
		//1>书写hql语句
		//String hql = "from com.sh.domain.Customer";
		String hql = "from Customer where cust_id=1";
		//2>根据hql语句创建查询对象
		Query query = session.createQuery(hql);
		//3>根据查询对象获得查询结果
		Customer result = (Customer) query.getSingleResult();
		System.out.println(result);
		//-------------------------------------
		
		// 4.提交事务,关闭资源
		tx.commit();
		session.close();// 游离\托管状态 有id 没有关联
	}

	@Test
	// 条件查询
	// 问号占位符的使用
	public void fun3() {
		// 1.获得Session
		Session session = HibernateUtils.openSession();
		// 2.控制事务
		Transaction tx = session.beginTransaction();
		// 3.执行操作
		//hql操作-------------------------------
		
		//1>书写hql语句
		//String hql = "from com.sh.domain.Customer";
		String hql = "from Customer where cust_id=?";
		//2>根据hql语句创建查询对象
		Query query = session.createQuery(hql);
		//设置参数
		query.setParameter(0,1l);
		//3>根据查询对象获得查询结果
		Customer result = (Customer) query.getSingleResult();
		System.out.println(result);
		//-------------------------------------
		
		// 4.提交事务,关闭资源
		tx.commit();
		session.close();// 游离\托管状态 有id 没有关联
	}
	
	@Test
	// 条件查询
	// 命名占位符的使用
	public void fun4() {
		// 1.获得Session
		Session session = HibernateUtils.openSession();
		// 2.控制事务
		Transaction tx = session.beginTransaction();
		// 3.执行操作
		//hql操作-------------------------------
		
		//1>书写hql语句
		//String hql = "from com.sh.domain.Customer";
		String hql = "from Customer where cust_id=:cust_id";
		//2>根据hql语句创建查询对象
		Query query = session.createQuery(hql);
		//设置参数
		query.setParameter("cust_id",1l);
		//3>根据查询对象获得查询结果
		Customer result = (Customer) query.getSingleResult();
		System.out.println(result);
		//-------------------------------------
		
		// 4.提交事务,关闭资源
		tx.commit();
		session.close();// 游离\托管状态 有id 没有关联
	}

	@Test
	// 分页查询
	// 命名占位符的使用
	public void fun5() {
		// 1.获得Session
		Session session = HibernateUtils.openSession();
		// 2.控制事务
		Transaction tx = session.beginTransaction();
		// 3.执行操作
		//hql操作-------------------------------
		
		//1>书写hql语句
		//String hql = "from com.sh.domain.Customer";
		String hql = "from Customer";
		//2>根据hql语句创建查询对象
		Query query = session.createQuery(hql);
		//设置分页信息
		query.setFirstResult(0);
		query.setMaxResults(1);
		//3>根据查询对象获得查询结果
		List<Customer> list = query.list();
		System.out.println(list);
		//-------------------------------------
		
		// 4.提交事务,关闭资源
		tx.commit();
		session.close();// 游离\托管状态 有id 没有关联
	}
}

2、原生SQL查询

/**
 * 原生sql查询
 * 
 * @author Administrator
 *
 */
public class Demo {

	@Test
	// 基本查询
	public void fun1() {
		// 1.获得Session
		Session session = HibernateUtils.openSession();
		// 2.控制事务
		Transaction tx = session.beginTransaction();
		// 3.执行操作

		// sql操作-------------------------------

		// 1>书写sql语句
		String sql = "select * from cst_customer";
		// 2>根据sql语句创建查询对象
		NativeQuery query = session.createNativeQuery(sql, Customer.class);
		// 3>根据查询对象获得查询结果
		List<Customer> list = query.list();
		// Object uniqueResult = query.uniqueResult();
		// Object result = query.getSingleResult();
		System.out.println(list);
		// -------------------------------------

		// 4.提交事务,关闭资源
		tx.commit();
		session.close();// 游离\托管状态 有id 没有关联
	}

	@Test
	// 条件查询
	public void fun2() {
		// 1.获得Session
		Session session = HibernateUtils.openSession();
		// 2.控制事务
		Transaction tx = session.beginTransaction();
		// 3.执行操作

		// sql操作-------------------------------

		// 1>书写sql语句
		String sql = "select * from cst_customer where cust_id=?";
		// 2>根据sql语句创建查询对象
		NativeQuery query = session.createNativeQuery(sql, Customer.class);
		//设置参数
		query.setParameter(1,1);
		// 3>根据查询对象获得查询结果
		List<Customer> list = query.list();
		// Object uniqueResult = query.uniqueResult();
		// Object result = query.getSingleResult();
		System.out.println(list);
		// -------------------------------------

		// 4.提交事务,关闭资源
		tx.commit();
		session.close();// 游离\托管状态 有id 没有关联
	}

	@Test
	// 分页查询
	public void fun3() {
		// 1.获得Session
		Session session = HibernateUtils.openSession();
		// 2.控制事务
		Transaction tx = session.beginTransaction();
		// 3.执行操作
		// hql操作-------------------------------

		// 1>书写hql语句
		// String hql = "from com.sh.domain.Customer";
		String sql = "select * from cst_customer limit ?,?";
		// 2>根据sql语句创建查询对象
		NativeQuery query = session.createNativeQuery(sql, Customer.class);
		//设置分页信息
		query.setParameter(1, 1);
		query.setParameter(2, 1);
		// 3>根据查询对象获得查询结果
		List<Customer> list = query.list();
		System.out.println(list);
		// -------------------------------------

		// 4.提交事务,关闭资源
		tx.commit();
		session.close();// 游离\托管状态 有id 没有关联
	}
}

Don't make promises you can't keep.But those are the best kind. 

不轻许做不到的承诺,但做不到的承诺往往最美好。



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

麦客子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值