持久化基础
关于Grails要记住一个关键点,就是在底层Grails使用 Hibernate 进行持久化。假如你是使用 ActiveRecord 或者 iBatis/MyBatis背景,对Hibernate's"session" 模式可能会感到一点奇怪。
Grails为当前正在执行的请求自动绑定一个Hibernate session。这让你可以使用save an和 delete 方法,以及透明使用 GORM其他方法。
后写事务
Hibernate的一个有用功能通过直接调用 JDBC 甚至其他的框架来帮你执行save 或者 delete操作,在这一点上它不一定执行任何SQL 操作。Hibernate 将 SQL 语句分批并尽可能晚地执行。通常在清空或关闭session时才结束请求。这是Grils帮你管理Hibernate session自动为你做的。
Hibernate 尽可能缓存数据库更新,当它知道需要一个刷新或者以编程方式触发刷新时,只刷新实际改变的内容。通常Hibernate执行缓存刷新是在执行查询的时候,因为缓存的信息可能包含在查询结果中。但是,只要你执行保存、更新、删除不冲突,他们会被分批执行直到session被刷新。这可能是为大量数据写入数据库所做的尽可能大的性能提升工作。
注意,刷新和提交事务是不一样的。如果你的actions是一个事务,刷新将执行SQL 更新,但数据库在事务序列存储的改变,只到事务提交,确认事务结束时才更新。
保存和更新
一个使用 save 方法的例子看起来像这样:
def p = Person.get(1)
p.save()
这个保存并没有被立即推进数据库- 当下一个刷新发生时才被推进数据库。但有的时候你想控制某些语句的执行,用Hibernate语言来说,当 session 被刷新时,你可以在执行save方法时使用flush参数:
def p = Person.get(1)
p.save(flush: true)
请注意,在这种情况下,以往所有缓存等待的SQL 语句包括保存和删除等等,将于数据库同步。这要让你捕获任何异常,在高并发的情况下使用乐观锁:
def p = Person.get(1)
try {
p.save(flush: true)
}
catch (org.springframework.dao.DataIntegrityViolationException e) {
// deal with exception
}
要记住的另一件事是,每一次Grails验证一个域的实例你都要保存。假如验证失败,域实例不会被持久化到数据库。默认情况下, save()在这里简单返回一个 null ,但是你要让她抛出一个异常,可以使用 failOnError 参数:
def p = Person.get(1)
try {
p.save(failOnError: true)
}
catch (ValidationException e) {
// deal with exception
}
你甚至可以更改 Config.groovy配置文件中的默认配置。要记住,当你保存已经与用户数据绑定的域实体时,发生验证异常的可能性是很高的,你可能不想将这些异常传播给最终用户。
删除对象
一个 delete 方法的例子看起来像这样:
def p = Person.get(1)
p.delete()
就像保存一样,Hibernate 会使用后写事务的方法去定义删除;定义立即删除你可以使用 flush 参数:
def p = Person.get(1)
p.delete(flush: true)
使用flush参数在发生一个删除是让你可以捕捉到任何错误。一个可能发生的常见错误是你违反了数据库约束,虽然这通常是编程和模式的错误。下面的例子展示如何捕捉一个DataIntegrityViolationException 异常,这是你违反数据库约束时抛出的:
def p = Person.get(1)
try {
p.delete(flush: true)
}
catch (org.springframework.dao.DataIntegrityViolationException e) {
flash.message = "Could notdelete person ${p.name}"
redirect(action: "show", id: p.id)
}
注意,Grails 没有提供 deleteAll方法来删除所有数据。通常可以通过布尔值来批量删除数据。
如果你真的需要批量删除数据,你可以使用executeUpdate法来执行批量的DML语句:
Customer.executeUpdate("delete Customer c where c.name = :oldName",
[oldName: "Fred"])