一般动作
    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。