领域类之持久化基础

来源:互联网 发布:录音笔 知乎 编辑:程序博客网 时间:2024/05/22 14:17

保存和更新

def p = Person.get(1)p.save()
不及时保存到数据库

def p = Person.get(1)try {    p.save(flush: true)}catch (org.springframework.dao.DataIntegrityViolationException e) {    // deal with exception}
及时保存到数据库

def p = Person.get(1)try {    p.save(failOnError: true)}catch (ValidationException e) {    // deal with exception}
保存时,验证出现出错,抛出异常

删除对象

def p = Person.get(1)p.delete()
def p = Person.get(1)

try { p.delete(flush: true)}catch (org.springframework.dao.DataIntegrityViolationException e) { flash.message = "Could not delete person ${p.name}" redirect(action: "show", id: p.id)}

和save一样
备注:
grails 不提供deleteAll 方法,如果想进行批量删除可以通过,如下方法
Customer.executeUpdate("delete Customer c where c.name = :oldName",                       [oldName: "Fred"])

理解级联更新和删除

在使用GORM时,理解如何级联更新和删除是很重要的.需要记住的关键是 belongsTo 的设置控制着哪个类"拥有"这个关联.

无论是一对一,一对多还是多对多,如果你定义了 belongsTo ,更新和删除将会从拥有类到被它拥有的类(关联的另一方)级联操作.

如果你 没有 定义 belongsTo 那么就不能级联操作,你将不得不手动保存每个对象.

下面是一个例子:
  1. class Airport {
  2.         String name
  3.         static hasMany = [flights:Flight]
  4. }

  5. class Flight {
  6.         String number
  7.         static belongsTo = [airport:Airport]
  8. }
复制代码
如果我现在创建一个 Airport 对象,并向它添加一些 Flight 它可以保存这个 Airport 并级联保存每个flight,因此会保存整个对象图:
  1. new Airport(name:"Gatwick")
  2. .addToFlights(new Flight(number:"BA3430"))
  3. .addToFlights(new Flight(number:"EZ0938"))
  4. .save()
复制代码
相反的,如果稍后我删除了这个 Airport 所有跟它关联的 Flight也都将会被删除:
  1. def airport = Airport.findByName("Gatwick")
  2. airport.delete()
复制代码
然而,如果我将 belongsTo 去掉的话,上面的级联删除代码就了. 不能工作. 为了更好地理解,take a look at the summaries below that describe the default behaviour of GORM
with regards to specific associations.

设置了belongsTo的双向一对多
  1. class A { static hasMany = [bees:B] }
  2. class B { static belongsTo = [a:A] }
复制代码
如果是双向一对多,在多的一端设置了belongsTo,那么级联策略将设置一的一端为"ALL",多的一端为"NONE".

单向一对多
  1. class A { static hasMany = [bees:B] }
  2. class B { }
复制代码
如果是在多的一端没有设置belongsTo单向一对多关联,那么级联策略设置将为"SAVEUPDATE".

没有设置belongsTo的双向一对多
  1. class A { static hasMany = [bees:B] }
  2. class B { A a }
复制代码
如果是在多的一端没有设置belongsTo的双向一对多关联,那么级联策略将为一的一端设置为"SAVE-UPDATE" 为多的一端设置为"NONE".

设置了belongsTo的单向一对一
  1. class A { }
  2. class B { static belongsTo = [a:A] }
复制代码
如果是设置了belongsTo的单向一对一关联,那么级联策略将为有关联的一端(A->B)设置为"ALL",定义了belongsTo的一端(B->A)设置为"NONE".

立即加载和延迟加载

class Airport {    String name    static hasMany = [flights: Flight]}
class Flight {    String number    Location destination    static belongsTo = [airport: Airport]}
class Location {    String city    String country}
grails默认是延迟加载
class Airport {    String name    static hasMany = [flights: Flight]    static mapping = {        flights lazy: false    }}
设置立即加载
class Airport {    String name    static hasMany = [flights: Flight]    static mapping = {        flights batchSize: 10    }}
class Flight {    …    static mapping = {        batchSize 10    }}
设置批量加载,比如:一个机场有30架飞机,如果没有设置批量加载,要取出1个机场3架飞机,要执行31次查询,假使按照上面批量加载配置,则需要4次查询就可以完成。

悲观锁和乐观锁

乐观锁

Grails领域类默认配置为乐观锁,通过领域类中version来实现乐观锁,领域类对应的表数据每次更新都会增加version的值。
def airport = Airport.get(10)

try { airport.name = "Heathrow" airport.save(flush: true)}catch (org.springframework.dao.OptimisticLockingFailureException e) { // deal with exception}

领域类对象更新的时候,判断对象version值是否和数据表字段version字段值相等,如果相等则通过更新,否则抛出异常。

悲观锁

def airport = Airport.get(10)airport.lock() // lock for updateairport.name = "Heathrow"airport.save()
def airport = Airport.findByName("Heathrow", [lock: true])
def airport = Airport.createCriteria().get {    eq('name', 'Heathrow')    lock true}

修改检查

情况模拟,假如有AB两个地方加载同一个领域类对象,A修改领域类对象,但是没有flush,此C地方加载该对象,他会从hibernate session里面获取到修改后的对象值。同时,B修改了改对象并且flush了。此时C加载的对象就有问题了,所以C可以通过修改检查解决此问题。
isDirty是判断数据是否修改
def airport = Airport.get(10)assert !airport.isDirty()

airport.properties = paramsif (airport.isDirty()) { // do something based on changed state}

def airport = Airport.get(10)assert !airport.isDirty()

airport.properties = paramsif (airport.isDirty('name')) { // do something based on changed name}

getDirtyPropertyNames是获取修改属性
def airport = Airport.get(10)assert !airport.isDirty()

airport.properties = paramsdef modifiedFieldNames = airport.getDirtyPropertyNames()for (fieldName in modifiedFieldNames) { // do something based on changed value}

getPersistentValue获取flush以后修改的数据
def airport = Airport.get(10)assert !airport.isDirty()

airport.properties = paramsdef modifiedFieldNames = airport.getDirtyPropertyNames()for (fieldName in modifiedFieldNames) { def currentValue = airport."$fieldName" def originalValue = airport.getPersistentValue(fieldName) if (currentValue != originalValue) { // do something based on changed value }}


原创粉丝点击