欢迎进入Wiki » FAQ » 如何在当前的Hibernate Session中写sql,并受事务控制?

如何在当前的Hibernate Session中写sql,并受事务控制?

在2013-10-18 09:46上被李小翔修改
评论 (0) · 附件 (0) · 记录 · 信息

    Hibernate虽然好用,但是也有很多不足,比如不支持from的子查询、大批量数据插入时的性能问题,这些时候,我们通常借助于原生的sql来处理。
    在控制器、service或者domain类中,我们通常可以通过获得grails自动注册的dataSource或dataSourceUnproxied来获得jdbc数据库连接(Connection)来写sql,如
   def dataSource
   
   void test() {
        java.sql.Connection conn = dataSource.getConnection();    // 获得一个新的数据库连接。也可以使用API直接获取: DatabaseUtils.getConnection()
       try {
           ...
       } finnaly {
            conn?.close()        // 关闭连接
       }
   }
   
   void test2() {
        groovy.sql.Sql sqlInst = new Sql( dataSource );            // 获得一个groovy的sql实例。也可以使用API直接获取: DatabaseUtils.getSql()
       try {
           ...
       } finally {
            sqlInst?.close()    // 关闭连接
       }
   }

   
    但是通过这种方式获得的jdbc连接和grails自动注入的连接并不是同一个,从而导致无法受到当前事务控制,无法和其他hibernate的数据库操作一块回滚。如下面的代码所示,在事务回滚后,张三的插入操作将会被回滚,而李四却被删除了,这显然不是我们希望的结果。
   void test3() {
        Employee.withTransaction{ status ->
           // 创建员工张三
           new Employee(name: "张三").save();        
           // 删除员工李四
           groovy.sql.Sql sqlInst = new Sql( dataSource );
           try {
                sqlInst.executeUpdate("delete from brofwk_osm_employee where name='李四'");
           } finally {
                sqlInst?.close();
           }
           // 回滚事务
           status.setRollbackOnly();
       }
   }

    还好 Hibernate 通过 sessionFactory 提供了获得当前session的方法,通过下面的代码即可获得当前session的数据库连接,将其替换到上面的示例代码test3中,就可以统一控制事务回滚:
   def sessionFactory
  
   void test4() {
        groovy.sql.Sql sqlInst = new Sql( sessionFactory.currentSession.connection() )        // 也可以使用API直接获取: DatabaseUtils.getSqlCurrent()
       ....
   }

   
    此外,这样获得的数据库连接,使用完成后,可以不用加trycatch来close链接,session结束的时候,会自动释放相关资源。
    不过保持一个close的好习惯,也是不错的;)

适用于

    DatabaseUtils 是 BroToolkit 提供的一组数据库相关的API。

   

在2013-10-18 09:25上被李小翔创建

Copyright © 2013 北京博瑞开源软件有限公司
京ICP备12048974号