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