一、事务相关概念
1. 什么是事务
数据库事务是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。
2. 事务特性
一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性、一致性、隔离性和持久性)属性。
原子性:事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。通常,与某个事务关联的操作具有共同的目标,并且是相互依赖的。
一致性:事务在完成时,必须使所有的数据都保持一致状态。
隔离性:由并发事务所作的修改必须与任何其它并发事务所作的修改隔离。
持久性:事务完成之后,它对于系统的影响是永久性的。该修改即使出现致命的系统故障也将一直保持。
3. 不考虑隔离性产生问题
(1)脏读
(2)不可重复读
(3)虚读
4. 设置事务隔离级别
mysql默认隔离级别 repeatable read
5. Hibernate 也可以在核心配置文件中配置事务隔离级别
1. 代码结构
try{
开启事务
提交事务
}catch(){
回滚事务
}finally{
关闭
1. 什么是事务
数据库事务是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。
2. 事务特性
一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性、一致性、隔离性和持久性)属性。
原子性:事务必须是原子工作单元;对于其数据修改,要么全都执行,要么全都不执行。通常,与某个事务关联的操作具有共同的目标,并且是相互依赖的。
一致性:事务在完成时,必须使所有的数据都保持一致状态。
隔离性:由并发事务所作的修改必须与任何其它并发事务所作的修改隔离。
持久性:事务完成之后,它对于系统的影响是永久性的。该修改即使出现致命的系统故障也将一直保持。
3. 不考虑隔离性产生问题
(1)脏读
(2)不可重复读
(3)虚读
4. 设置事务隔离级别
mysql默认隔离级别 repeatable read
5. Hibernate 也可以在核心配置文件中配置事务隔离级别
<!--
事务隔离级别:
hibernate.connection.isolation = 4
1 - Read uncommitted isolation(未提交读:脏读、不可重复读、幻读均可能发生)
2 - Read committed isolation(已提交读:防止脏读发生,不可重复读、幻读均可能发生)
4 - Repeatable read isolation(可重复读:防止脏读、不可重复读发生,幻读可能发生)
8 - Serializable isolation(可串行化:防止脏读、不可重复读、幻读发生)
-->
<propertyname="hibernate.connection.isolation">4</property>
二、hibernate事务规范写法
1. 代码结构
try{
开启事务
提交事务
}catch(){
回滚事务
}finally{
关闭
}
2. 代码示范
@Test
public void testTs() {
Session session = null;
Transaction ts = null;
try {
session = HibernateUtils.getSessionFactory().openSession();
ts = session.beginTransaction();
User user = new User();
user.setUserName("小明");
user.setPassword("8888");
user.setAddress("中国");
session.save(user);
int i = 10/0;
//提交事务
ts.commit();
}catch(Exception e) {
e.printStackTrace();
//回滚事务
ts.rollback();
}finally {
//关闭资源
session.close();
}
}
三、hibernate绑定session
1. 为什么要把Session与本地线程绑定??
openSession():
- 总是创建一个新的session对象
- 你需要去明确的关闭session对象
- 在单线程环境它比getCurrentSession()更慢
- 你也不需要去配置任何属性,你就能够使用这个方法
getCurrentSession():
- 如果session不存在,它将创建一个新的session,否则在当前hibernate环境中使用同一个session
- 你不需要去关闭session对象,它将自动被hibernate内部机制关闭
- 在单线程环境它比opensession更快
- 你需要去配置中附加hibernate.current_session_context_class这个属性,才能够调用getCurrentSession()方法否则将会抛出异常
所以在这里openSession()和getCurrentSession()的主要区别就是快和慢的区别。开启事务,还是用getCurrentSession()比较好,因为方便且快。
2. 我们怎样获取与本地线程绑定的session
注:Hibernate已经帮我们实现了session与本地线程绑定
(1)首先在hibernate核心配置文件中配置---hibernate.cfg.xml
在第二部分配置<property name="hibernate.current_session_context_class">thread</property>
//其中,上面的值一共有三个,但是我们一般只用thread,即Session对象与本地线程进行绑定。
- thread:Session对象的生命周期与本地线程绑定
- jta:Session对象的生命周期与JTA事务绑定
- managed:Hibernate委托程序来管理Session对象的生命周期
(2)java代码
- 在Utils工具类中获取session
public class HibernateUtils {
private static final Configuration cfg;
private static final SessionFactory sessionFactory;
//静态代码块实现
static {
cfg = new Configuration().configure();
sessionFactory =cfg.buildSessionFactory();
}
//提供返回与本地线程帮的session的方法
public static Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}
//使用静态方法返回SessionFactory对象
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
- 测试代码
因为我们这里的session是绑定了本地线程的session,当本地线程被关闭后,session也就自然而然的被关闭了。就像是同一根绳子上面的蚂蚱。这样也就不用我们去关闭session了。@Test public void testTs() { Session session = null; Transaction ts = null; try { //与本地线程绑定的session session = HibernateUtils.getCurrentSession(); ts = session.beginTransaction(); User user = new User(); user.setUserName("小明"); user.setPassword("8888"); user.setAddress("中国"); session.save(user); ts.commit(); }catch(Exception e) { e.printStackTrace(); //回滚事务 ts.rollback(); }finally { //关闭资源 //session.close(); } }