Web开发 | Hibernate - 09.Hibernate中的事务

1. 事务相关的概念

1、什么是事务
  • 事务就是逻辑上的一组操作,组成事务的各个执行单元,操作要么全都成功,要么全都失败.
  • 转账的例子:用户1给用户2转钱,包含了扣钱,加钱两个操作,这两个操作组成了一个事情!
2、事务的特性
  • 原子性 – 事务不可分割.
  • 一致性 – 事务执行的前后数据的完整性保持一致.
      即:用户1给用户2转钱,用户1必须扣钱,用户2必须加钱,是对等的。
  • 隔离性 – 一个事务执行的过程中,不应该受到其他的事务的干扰.
  • 持久性 – 事务一旦提交,数据就永久保持到数据库中.
3、如果不考虑隔离性,会引发一些读的问题
  • 脏读 – 一个事务读到了另一个事务未提交的数据
      即:用户1给用户2转钱,用户1扣钱动作修改了(update)但还未提交(commit),而用户2尝试读取(get)该数据。
  • 不可重复读 – 一个事务读到了另一个事务已经提交的 update 数据,导致多次查询结果不一致.
      即:用户1给用户2转钱,用户1扣钱动作已经提交了,用户2也读取(get)该数据一次,接着用户1又执行第二次转钱,第二次扣钱动作已经提交了,用户2第二次读取(get)该数据,从而两次读取的数据不一样。
  • 虚读 – 一个事务读到了另一个事务已经提交的 insert 数据,导致多次查询结构不一致.
      即:假设一张数据表中原有14条记录,用户查询第10条记录的过程中,数据表又插入了一条数据,导致用户查询的第10条记录与预想的不匹配。
4、通过设置数据库的隔离级别来解决上述读的问题
  • 未提交读:以上的读的问题都有可能发生
  • 已提交读:避免脏读,但是不可重复读,虚读都有可能发生
  • 可重复读:避免脏读,不可重复读.但是虚读是有可能发生
  • 串行化:以上读的情况都可以避免(在读取表的时候,锁定表数据,不允许插入,但是就会变成单线程操作,最耗资源)
5、如果想在 Hibernate 的框架中来设置隔离级别,需要在hibernate.cfg.xml的配置文件中通过标签来配置
    通过:hibernate.connection.isolation = 4 来配置
    1Read uncommitted isolation
    2Read committed isolation
    4 — Repeatable read isolation
    8 — Serializable isolation

2. 绑定本地的Session

1、 JavaWEB 事务中,需要在业务层使用 Connection 来开启事务
  • 第一种是通过参数的方式传递下去
  • 第二种是把 Connection 绑定到 ThreadLocal 对象中
2、现在的 Hibernate 框架中,使用 session 对象开启事务,所以需要来传递session 对象,框架提供了 ThreadLocal 的方式
  • 需要在 hibernate.cfg.xml 的配置文件中提供配置
      <property name="hibernate.current_session_context_class">thread</property>
ThreadLocal方法:创建一个线程本地变量,是一个键值对结构类型的数据:<k,v>

set(v)放入一个值进去

k:当前线程名称
v:session
  • 修改 HibernateUtil 的工具类, 使用 SessionFactory 的getCurrentSession()方法,获取当前的 Session 对象。并且该 Session 对象不用手动关闭, 线程结束了,会自动关闭。
public static Session getCurrentSession(){ 
    return factory.getCurrentSession();
}
//注意:想使用 getCurrentSession()方法,必须要先配置才能使用

事务图解


3. 绑定本地 session 示例

新建项目(Hibernate5_d02_c04)
基于Hibernate5_d02_c03项目选取必要文件

1、修改配置文件
  /Hibernate5_d02_c04/src/hibernate.cfg.xml
程序代码如下:

<?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-configuration>
    ...
                <!-- 把session绑定到当前线程中,使用getCurrentSession()获取当前session -->
        <property name="hibernate.current_session_context_class">thread</property>

        <!-- 映射文件 -->
        <mapping resource="/hibernate/domain/User.hbm.xml"/>
    </session-factory>
</hibernate-configuration>

2、修改 HibernateUtil 的工具类,使用 SessionFactory 的 getCurrentSession()方法,获取当前的 Session 对象。
  /Hibernate5_d02_c04/src/hibernate/util/HibernateUtils.java
程序代码如下:

...
public class HibernateUtils {
    ...

    //session绑定到线程
    //这种方式获取的session不用手动关闭,线程结束了会自动关闭
    public static Session getCurrentSession(){
        return FACTORY.getCurrentSession();
    }
}

3、新建UserDao类
  /Hibernate5_d02_c04/src/hibernate/dao/UserDao.java
程序代码如下:

package hibernate.dao;

import org.hibernate.Session;

import hibernate.domain.User;
import hibernate.util.HibernateUtils;

public class UserDao {
    public void save1(User user1){
        //获取 session 对象
        Session session = HibernateUtils.getCurrentSession();
        //不需要开启事务,事务在sevice层开启
        session.save(user1);
    }

    public void save2(User user2){
        //获取 session 对象
        Session session = HibernateUtils.getCurrentSession();
        //不需要开启事务,事务在sevice层开启
        session.save(user2);
    }
}

4、新建UserServicer类
  /Hibernate5_d02_c04/src/hibernate/service/UserService.java
程序代码如下:

package hibernate.service;

import org.hibernate.Session;
import org.hibernate.Transaction;

import hibernate.dao.UserDao;
import hibernate.domain.User;
import hibernate.util.HibernateUtils;

public class UserService {
    /*
     * 使用事务的方式
     */
    public void save(User user1,User user2){

        //先获取到 session 对象,session 会创建,会把 session 绑定到当前线程上
        Session session = HibernateUtils.getCurrentSession();
        //开启事务
        Transaction tr  = session.beginTransaction();
        try {
            //调用 dao 层
            UserDao dao = new UserDao();
            dao.save1(user1);
            dao.save2(user2);
            //提交事务
            tr.commit();
        } catch (Exception e) {
            //回滚事务
            tr.rollback();
        }finally {
            //释放资源,当前代码完成后,当前线程结束,session会自动关闭,不要手动close
        }
    }
}

5、新建TestUser类
  /Hibernate5_d02_c04/src/hibernate/test/UserTest.java
程序代码如下:

package hibernate.test;

import org.junit.Test;

import hibernate.domain.User;
import hibernate.service.UserService;

public class UserTest {
    @Test
    public void testUser(){
        User u1 = new User();
        User u2 = new User();
        u1.setName("熊大");
        u2.setName("熊二");
        UserService us = new UserService();
        us.save(u1, u2);
    }
}

6、测试查看效果

运行效果
运行效果

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值