hibernate 之 session在service层实现事务管理

Hibernate session在service实现事务

         当我们在使用Hibernate作为数据库操作的类库时,我们一般在DAO层里与数据库相关的操作,把业务逻辑写在service层里。但是如果我们的项目比较小,那么直接在dao层里写事务也是可以的,这个就是看个人了,没有什么特别的规定。但是如果项目比较大,那么DAO应该只做单纯的数据库的操作,service写事务的操作,即整个业务逻辑。

例如:业务逻辑要求向数据库中的用户表增加一个用户,同时向日志表中加入一条日志,而这需要调用DAO的两个方法(UserDaosaveUserLogDaosaveLog)。这显然是一个事务,也就是如果一个操作出现了问题,就要回滚到初始的状态。那么如何在Service层控制事务呢,本文就以此例的代码说明。

在DAO进行Session事务出现的问题

我们先看看在DAO层里写Hibernatesession的事务。

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

package com.xxg;

 

import org.hibernate.SessionFactory;

import org.hibernate.cfg.Configuration;

 

public class HibernateUtil {

 

    private static final SessionFactory sessionFactory = buildSessionFactory();

    private static SessionFactory buildSessionFactory() {

        try {

            // Create the SessionFactory from hibernate.cfg.xml

            return new Configuration().configure().buildSessionFactory();

        }

        catch (Throwable ex) {

            // Make sure you log the exception, as it might be swallowed

            System.err.println("Initial SessionFactory creation failed." + ex);

            throw new ExceptionInInitializerError(ex);

        }

    }

    public static SessionFactory getSessionFactory() {

        return sessionFactory;

    }

}

创建用户表T_userid,username)和日志表T_log(id,content),以及它们对应的实体类UserLog及映射文件,这里就不一一贴出代码。

01

02

03

04

05

06

07

08

09

10

11

12

13

public class UserDao {

 

    public void saveUser(User user){

        SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); //获取SessionFactory

        Session session = sessionFactory.openSession();// openSession

        session.beginTransaction(); //开始事务

 

        session.save(user);

 

        session.getTransaction().commit(); //事务提交

        session.close(); //关闭session

    }

}

01

02

03

04

05

06

07

08

09

10

11

12

13

14

public class LogDao {

 

    public void saveLog(Log log){

        SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); //获取SessionFactory

        Session session = sessionFactory.openSession();// openSession

        session.beginTransaction(); //开始事务

 

        session.save(log);

 

        session.getTransaction().commit(); //事务提交

        session.close(); //关闭session

    }

 

}

接下来我们看看在service中写一个业务逻辑

01

02

03

04

05

06

07

08

09

10

11

12

13

public class TestService {

 

    public void save(User user){

        UserDao userDao = new UserDao();

        userDao.saveUser(user);

 

        LogDao logDao = new LogDao();

        Log log = new Log();

        log.setContent("插入一个用户");

        logDao.saveLog(log);

    }

 

}

可以看到,我们在两个DAO里写了数据库的事务,session.beginTransaction()显示声明事务的开始。

这样写是不对的,因为这两个事情作为一个事务来进行的,会出现一个事务成功提交,而另外一个可能提交失败,导致不一致的情况,这样这两个操作不算是一个事务transaction,所以这么写就是一个失败的事务。

因此,我们要将事务在service中进行声明。

在service层写session的数据库事务

 

       为了将事务控制在service层,我们不能够在dao中打开关闭各自的事务。而是在service层打开、关闭事务,然后在每一个dao中利用sessionFactotrygetCurrentSession方法获取当前线程的session,且每一个dao中只负责操作数据而不用操作事务的打开和关闭,这样就实现了service涉及的dao共用同一个session且每一个dao操作都处在同一个事务管理中。service层可以显示的打开关闭事务,也可以通过spring的事务管理器利用aop切面生成代理类原理智能的打开关闭事务。

 

      

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

public class HibernateUtil {

    public static final ThreadLocal session = new ThreadLocal();

 

    public static final SessionFactory sessionFactory;

    static {

        try {

            sessionFactory = new Configuration().configure().buildSessionFactory();

        } catch ( Throwable ex ) {

            throw new ExceptionInInitializerError( ex );

        }

    }

 

    public static Session currentSession() throws HibernateException

    {

        Session s = session.get();

        if ( s == null )

        {

            s = sessionFactory.openSession();

            session.set( s );

        }

        return(s);

    }

 

    public static void closeSession() throws HibernateException

    {

        Session s = session.get();

        if ( s != null )

        {

            s.close();

        }

        session.set( null );

    }

}

接下来,我们将事务放在service中。看代码:

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

public class TestService {

 

    public void save(User user){

 

        SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); //获取SessionFactory

        Session session = sessionFactory.getCurrentSession();//getCurrentSession

        session.beginTransaction();//事务开始

 

        UserDao userDao = new UserDao();

        userDao.saveUser(user);

 

        LogDao logDao = new LogDao();

        Log log = new Log();

        log.setContent("插入一个用户");

        logDao.saveLog(log);

        session.getTransaction().commit();//事务提交

    }

 

}

 

01

02

03

04

05

06

07

08

09

10

11

public class LogDao {

 

    public void saveLog(Log log) throws RuntimeException{

        SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); //获取SessionFactory

        Session session = sessionFactory.getCurrentSession(); //getCurrentSession

 

        session.save(log);

 

        throw new RuntimeException();

    }

}

 

01

02

03

04

05

06

07

08

09

10

11

public class UserDao {

 

    public void saveUser(User user){

        SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); //获取SessionFactory

        Session session = sessionFactory.getCurrentSession();//getCurrentSession

 

        session.save(user);

 

    }

 

}

通过getCurrentSession()可以获得当前线程的session对象,通过它来进行共享session。这样事务就从service开始,然后再service结束。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值