Hibernate学习笔记8,session管理,事务控制

简介: Hibernate学习笔记8,session管理,事务控制 Hibernate的事务管理 事务(Transaction)是工作中的基本逻辑单位,可以用于确保数据库能够被正确修改,避免数据只修改了一部分而导致数据不完整,或者在修改时受到用户干扰。

Hibernate学习笔记8,session管理,事务控制

Hibernate的事务管理

事务(Transaction)是工作中的基本逻辑单位,可以用于确保数据库能够被正确修改,避免数据只修改了一部分而导致数据不完整,或者在修改时受到用户干扰。作为一名软件设计师,必须了解事务并合理利用,以确保数据库保存正确、完整的数据。数据库向用户提供保存当前程序状态的方法,叫事务提交(commit);当事务执行过程中,使数据库忽略当前的状态并回到前面保存的状态的方法叫事务回滚(rollback)。

1 事务的特性

事务具备原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)4个属性,简称ACID。下面对这4个特性分别进行说明。

原子性:将事务中所做的操作捆绑成一个原子单元,即对于事务所进行的数据修改等操作,要么全部执行,要么全部不执行。

一致性:事务在完成时,必须使所有的数据都保持一致状态,而且在相关数据中,所有规则都必须应用于事务的修改,以保持所有数据的完整性。事务结束时,所有的内部数据结构都应该是正确的。

隔离性:由并发事务所做的修改必须与任何其他事务所做的修改相隔离。事务查看数据时数据所处的状态,要么是被另一并发事务修改之前的状态,要么是被另一并发事务修改之后的状态,即事务不会查看由另一个并发事务正在修改的数据。这种隔离方式也叫可串行性。

持久性:事务完成之后,它对系统的影响是永久的,即使出现系统故障也是如此。

2 事务隔离

事务隔离意味着对于某一个正在运行的事务来说,好像系统中只有这一个事务,其他并发的事务都不存在一样。在大部分情况下,很少使用完全隔离的事务。但不完全隔离的事务会带来如下一些问题。
更新丢失(Lost Update):两个事务都企图去更新一行数据,导致事务抛出异常退出,两个事务的更新都白费了。 脏数据(Dirty Read):如果第二个应用程序使用了第一个应用程序修改过的数据,而这个数据处于未提交状态,这时就会发生脏读。第一个应用程序随后可能会请求回滚被修改的数据,从而导致第二个事务使用的数据被损坏,即所谓的“变脏”。 不可重读(Unrepeatable Read):一个事务两次读同一行数据,可是这两次读到的数据不一样,就叫不可重读。如果一个事务在提交数据之前,另一个事务可以修改和删除这些数据,就会发生不可重读。 幻读(Phantom Read):一个事务执行了两次查询,发现第二次查询结果比第一次查询多出了一行,这可能是因为另一个事务在这两次查询之间插入了新行。针对由事务的不完全隔离所引起的上述问题,提出了一些隔离级别,用来防范这些问题。 读操作未提交(Read Uncommitted):说明一个事务在提交前,其变化对于其他事务来说是可见的。这样脏读、不可重读和幻读都是允许的。当一个事务已经写入一行数据但未提交,其他事务都不能再写入此行数据;但是,任何事务都可以读任何数据。这个隔离级别使用排写锁实现。 读操作已提交(Read Committed):读取未提交的数据是不允许的,它使用临时的共读锁和排写锁实现。这种隔离级别不允许脏读,但不可重读和幻读是允许的。 可重读(Repeatable Read):说明事务保证能够再次读取相同的数据而不会失败。此隔离级别不允许脏读和不可重读,但幻读会出现。 可串行化(Serializable):提供最严格的事务隔离。这个隔离级别不允许事务并行执行,只允许串行执行。这样,脏读、不可重读或幻读都可发生。
事务隔离与隔离级别的关系如表1所示。
表1 事务隔离与隔离级别的关系
这里写图片描述
在一个实际应用中,开发者经常不能确定使用什么样的隔离级别。太严厉的级别将降低并发事务的性能,但是不足够的隔离级别又会产生一些小的Bug,而这些Bug只会在系统重负荷(也就是并发严重时)的情况下才会出现。
一般来说,读操作未提交(Read Uncommitted)是很危险的。一个事务的回滚或失败都会影响到另一个并行的事务,或者说在内存中留下和数据库中不一致的数据。这些数据可能会被另一个事务读取并提交到数据库中。这是完全不允许的。
另外,大部分程序并不需要可串行化隔离(Serializable Isolation)。虽然,它不允许幻读,但一般来说,幻读并不是一个大问题。可串行化隔离需要很大的系统开支,很少有人在实际开发中使用这种事务隔离模式。
现在留下来的可选的隔离级别是读操作已提交(Read Committed)和可重读(Repeatable Read)。Hibernate可以很好地支持可重读(Repeatable Read)隔离级别。
3 在Hibernate配置文件中设置隔离级别
JDBC连接数据库使用的是默认隔离级别,即读操作已提交(Read Committed)和可重读(Repeatable Read)。在Hibernate的配置文件hibernate.properties中,可以修改隔离级别:

#hibernate.connection.isolation 4

在上一行代码中,Hibernate事务的隔离级别是4,这是什么意思呢?级别的数字意义如下。

1:读操作未提交(Read Uncommitted) 2:读操作已提交(Read Committed) 4:可重读(Repeatable Read) 8:可串行化(Serializable)

因此,数字4表示“可重读”隔离级别。如果要使以上语句有效,应把此语句行前的注释符“#”去掉:

hibernate.connection.isolation 4

也可以在配置文件hibernate.cfg.xml中加入以下代码:

<session-factory>
//把隔离级别设置为4
<property name= hibernate.connection.isolation”>4</property>
</session-factory>

在开始一个事务之前,Hibernate从配置文件中获得隔离级别的值。


事务控制在哪里进行?

在service()里执行:

service(){
    session.beginTransaction;//开启事务
    try{
    调用dao方法1
    调用dao方法2
    .....
    session.getTransaction().commit();//提交事务
    }catch(Exception ex){
        session.getTransaction().rollback();//回滚事务
    }
}

session如何管理

在service接口中,每个dao请求中使用同一个session即使用同一个数据库连接,保证多个dao调用在一个事务中。

在service执行开始处开启一个新session,将session和当前线程绑定,在每个dao调用中获取当前线程绑定的session,实现每个dao获取到的session是同一个session。
这里写图片描述


4.2获取当前线程绑定的session


在工具类中手动编写code

这里写图片描述
(code)

    //定义一个treadLocal,存储当前线程绑定的session
    private static ThreadLocal<Session> session_threadLocal = new ThreadLocal<Session>();
    //获取当前线程绑定的session
    public static Session getCurrentSession() {

        Session session = session_threadLocal.get();

        if(session == null) {
            //开启一个新的session
            session = sessionFactory.openSession();
            //将新开启的session和当前线程绑定
            session_threadLocal.set(session);
            return session;
        }
        return session;
    }

    //关闭当前线程绑定的session
    public static void closeCurrentSession() {

        Session session = session_threadLocal.get();

        if(session != null) {
            session.close();
            session_threadLocal.set(null); 
        }
    }

对dao和service进行修改(修改前内容看学习笔记6)


dao修改

CstCustomerDaoImpl类(code)

    public void insert(CstCustomer customer) {

        //获取当前线程绑定的session
        Session session = HibernateUtil.getCurrentSession();
        session.save(customer);
    }

CstCustomerDetailDaoImpl类(code)

    public void insert(CstCustomerDetail customerDetail) {
        //获取当前线程绑定的session
        Session session = HibernateUtil.getCurrentSession();
        session.save(customerDetail);
    }
}

Session 对象的生命周期与本地线程绑定

在hibernate.cfg.xml添加配置如下:

    <!-- 配置session绑定本地线程 -->
    <property name="hibernate.current_session_context_class">thread</property>

service修改(重点实现事务Transaction的控制)

CustomerServiceImpl类(code)

    //实现事务控制
    @Override
    public void insertCustomer(CstCustomer cstCustomer, CstCustomerDetail cstCustomerDetail) {

        //开启session与当前线程绑定
        Session session = HibernateUtil.getCurrentSession();
        //开事务
        session.beginTransaction();

        try {
            //执行单元
            CstCustomerDao CstCustomerDao = new CstCustomerDaoImpl();
            CstCustomerDetailDao CstCustomerDeatailDao = new CstCustomerDetailDaoImpl();
            //插入基本信息
            CstCustomerDao.insert(cstCustomer);
            //基本信息和详细信息的主键保持一致
            cstCustomerDetail.setCustId(cstCustomer.getCustId());
            //插入详细信息
            CstCustomerDeatailDao.insert(cstCustomerDetail);
            //提交事务
            session.getTransaction().commit();
        } catch (Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        } finally {
            //关闭当前线程的session
            HibernateUtil.closeCurrentSession();
        }
    }

hibernate对事务管理支持

Hibernate 5 自身提供了三种管理 Session 对象的方法
Session 对象的生命周期与本地线程绑定
Session 对象的生命周期与 JTA 事务绑定
Hibernate 委托程序管理 Session 对象的生命周期


Hibernate框架本身也有对事务控制管理的功能,所以可以将以上工具类的手动编写线程绑定方法改用Hibernate的sessionFactory内置的方法,修改如下:
(code)

    //获取当前线程绑定的session
    public static Session getCurrentSession() {
        return sessionFactory.getCurrentSession();
    }

    //关闭当前线程绑定的session
    public static void closeCurrentSession() {

        sessionFactory.getCurrentSession().close();
    }
}

将session线程进行管理,可以在多个表同时操作的时候,让它们共用同一个session,可以提高对数据库表操作的整体性,中途若出错,则整个过程将会停止,避免操作表中途的出现错误而导致对其他表操作的遗漏。

原文地址http://www.bieryun.com/3553.html

相关文章
|
2月前
|
Java 关系型数据库 数据库连接
Hibernate学习笔记(一)快速入门
Hibernate学习笔记(一)快速入门
|
10月前
|
SQL Java 数据库连接
Hibernate_学习笔记
Hibernate_学习笔记
|
SQL Java 数据库连接
hibernate入门学习笔记
hibernate入门学习笔记
64 0
|
存储 SQL Java
hibernate学习笔记之二(映射关系与懒加载)
hibernate学习笔记之二(映射关系与懒加载)
hibernate学习笔记之二(映射关系与懒加载)
|
SQL 存储 缓存
hibernate学习笔记之一(下)
hibernate学习笔记之一(下)
hibernate学习笔记之一(下)
|
SQL XML 安全
hibernate学习笔记之一(上)
hibernate学习笔记之一(上)
hibernate学习笔记之一(上)
|
SQL JSON Java
SpringBoot 整合 JPA-Hibernate|学习笔记
快速学习 SpringBoot 整合 JPA-Hibernate
138 0
SpringBoot 整合 JPA-Hibernate|学习笔记
|
Oracle 安全 Java
Hibernate的事务的隔离性
Hibernate的事务的隔离性
116 0
|
Java 数据库连接 开发工具
Hibernate 控制反转|学习笔记
快速学习 Hibernate 控制反转
|
缓存 Java 数据库连接
Hibernate Session 生命周期|学习笔记
快速学习 Hibernate Session 生命周期
160 0