我们已经讨论了很多finder 相关的方法,Active Record 关于更新记录的操作并不多。
如果你有一个Active Record 对象(或许表示为我们的orders 表的一行),你可以通过save()方法把它写入数据库,如果这个对象以前是从数据库中读出,这个存盘的操作将更新现有记录。否则save()将会插入一个新行。
如果一个现有记录行被更新,Active Record 将使用它的主键列匹配内存中的对象。包
含在Active Record 对象中的属性决定了被更新的列。即使列值没有改变,这个列也要在数据库中去更新。例如,在下面例子中,对于数据库表中定单为123 的行的所有值将被更新
order = Order.find(123)
order.name = "Fred"
order.save
但是,在下面例子中,Active Record 对象只包含属性id,name,和paytype,当对象
被保存时,只有这些列将被更新(注意,如果你想保存使用find_by_sql 获取的记录,你必
须包括id 列)。
orders = Order.find_by_sql("select id, name, pay_type from orders
where id=123")
first = orders[0]
first.name = "Wilma"
first.save
(update_attribute,update_attributes)
除了save()方法外,Active Record 还可以让你直接用单一的方法调用
update_attribute()改变属性值并保存model 对象。
order = Order.find(123)
order.update_attribute(:name, "Barney")
order = Order.find(321)
order.update_attributes(:name => "Barney", :email =>
"barney@bedrock.com")
(update,udpate_all)最后,我们使用update()和update_all()这两个类方法来组合读取和更新记录行的操
作。update()方法接受一个id 参数和一个属性集合。它获取相应的记录行,更新给定的属性,把结果保存回数据库,并返回model 对象。
order = Order.update(12, :name => "Barney", :email =>
"barney@bedrock.com")
你可以给update()传入一个id 数组和一个含有属性值的哈希表的数组,它将更新所有
相应的数据库中的记录行,并返回一个model 对象数组。
最后update_all()类方法允许你指定SQL 中update 语句里的set 和where 的子句。例
如,下面所有标题带有Java 字样产品的单价增加10%。
result = Product.update_all("price = 1.1*price", "title like
'%Java%'")
update_all()返回值取决于数据库的适配器,除了oracle,大部分数据库返回数据库中
被改变的记录行数。
save()andsave!()有两个版本的save 方法。如果model 对象是有效的并且能够保存的话,旧版本的save()
返回true。
if order.save
# all OK
else
# validation failed
end
上面的代码是检查save 的每个调用,看看是不是你所期望的。这样做的原因是Active
Record 比较宽松,它假定save()是在controller 的action 方法的上下文中调用,而view代码将会负责把任何错误显示给用户。对大多数应用程序来说,基本上就是这样来使用的。
然而,如果你想在需要的地方保存model 对象,又想所有的错误自动得到处理的话,你
就直接使用save!()吧。这个方法如果碰到对象不能保存,就抛出一个RecordInvalid 的异常。
begin
order.save!
rescue RecordInvalid => error
# validation failed
end
乐观锁
在一个有多进程访问同一数据库的应用程序中,可能会有这样的情况:一个进程使用的
数据正慢慢变成老数据了,而另一个进程一直想更新这个记录行。
例如,两个进程获取相应的一个特殊账号的记录行。经过几秒间隔,两个进程都要去更
新余额。每个都是以初始的记录行的内容加载一个Active Record 的model 对象。在不同的时间他们每个都使用他们各自的model 本地拷贝去更新数据库中的记录。结果就是一个“竟争条件”,最后一个更新记录行的人得到他的预期值,而第一个人的改变则丢失了。这显示
一种解决办法是锁住要更新的表或者行。为了阻止它人对它的访问和更新,使用锁来克
服并发的问题,但是这是强制性措施。它假设可能会出错于是在这种情况下就使用了锁。对
于这种原因,此途径通常被称为悲观锁。悲观锁对web 应用来说是不起作用的。因为如果你
需要确保多用户访问的一致性,而以数据库不停机的方式来管理悲观锁是非常困难的。
乐观锁并不是很直观的锁机制。相反,只在把记录行的更新写回数据库之前,它检查并
确保没有其他人仍在更改这个记录行。在rails 的实现中,每个记录行包含一个版本号。一
旦这个记录更新,版本号就会增加。当你从你的应用程序中更新时,Active Record 会检查表中这个记录行的版本号和发出更新命令的model 的版本号。如果这两个号不匹配,他就放弃更新并抛出异常。
默认情况下,乐观锁是由包含一个叫lock_version 的integer 列的表来激活的。创建一
个新记录时这个列应该被初始化为0,否则你应该让它自己来控制--Active Record 会为你打理好。
让我们看看action 内的乐观锁。我们将创建名为counters 的表,它包含一个简单的count
字段及lock_version 列。
create table counters (
id int not null auto_increment,
count int default 0,
lock_version int default 0,
primary key (id)
);
然后我们在表中创建一个记录,并把它读取到两个独立的model 对象中,然后拭着分别
更新它们。
class Counter < ActiveRecord::Base
end
Counter.delete_all
Counter.create(:count => 0)
count1 = Counter.find(:first)
count2 = Counter.find(:first)
count1.count += 3
count1.save
count2.count += 4
count2.save
当我们运行时,可以看到一个异常。rails 更新count2 失败了,因为它的值已经过时了。
/use/lib/ruby/gems/1.8/gems/activerecord-
1.9.0/lib/active_record/locking.rb:42:
in ‘update_without_timestamps':
Attempted to update a stale object (ActiveRecord::StaleObjectError)
如果你使用乐观锁,你需要在程序中捕获这些异常情况。
你也可以关闭乐观锁:
ActiveRecord::Base.lock_optimistically = false
分享到:
相关推荐
这个名为"restful-crud-实验.tar.gz"的压缩包文件显然是一个教学资源,旨在帮助学习者理解如何在SpringBoot应用中实现基于REST的创建(Create)、读取(Read)、更新(Update)和删除(Delete)功能。 首先,我们要...
Laravel CRUD Generator能够帮助开发者快速创建CRUD(Create, Read, Update, Delete)操作,极大地提高了开发效率,降低了重复劳动。 Laravel是一个基于PHP的优雅且强大的Web应用开发框架,它的核心理念是"简洁、...
CRUD(Create, Read, Update, Delete)是数据库操作的核心概念,代表了创建、读取、更新和删除数据的基本操作。在IT行业中,尤其是Web开发领域,CRUD接口设计是构建任何应用程序的基础,用于与数据库进行交互。"crud...
PHP文件(get_users.php, update_user.php, save_user.php, remove_user.php)负责处理来自前端的请求,进行数据的CRUD操作。例如,"get_users.php" 可能会使用SQL查询语句从数据库中获取用户信息,而"save_user....
"laravel-crud-generator"是Laravel生态系统中的一个工具,用于自动化CRUD(Create, Read, Update, Delete)操作的生成,极大地提高了开发效率。在本篇文章中,我们将深入探讨Laravel开发以及laravel-crud-generator...
groovy-cli-maven-mongo-crud-update 描述 创建具有凭据的用户并列出收集test 。 科技栈 时髦 专家mongo连接器 蒙哥 Docker堆栈 mongodb:最新 openjdk11 笔记 跑步 sudo ./install.sh -u 停止 sudo ./install.sh -...
kotlin-cli-maven-mongo-crud-update描述创建具有凭据的用户并列出收集test 。科技栈Kotlin专家mongo连接器蒙哥Docker堆栈mongodb:最新openjdk11笔记跑步sudo ./install.sh -u 停止sudo ./install.sh -d 求助sudo ....
java-cli-gradle-mongo-crud-update 描述 创建具有凭据的用户并列出收集test 。 科技栈 Java 摇动mongo连接器 蒙哥 Docker堆栈 mongodb:最新 gradle:jdk11 笔记 跑步 sudo ./install.sh -u 停止 sudo ./install....
在本文中,我们将深入探讨如何使用Laravel框架开发CRUD(Create, Read, Update, Delete)API。Laravel是一款流行的PHP框架,它以其优雅的语法和丰富的功能集为Web开发提供了强大的工具。当我们谈论CRUD API时,我们...
在结合MySQL数据库进行CRUD(Create、Read、Update、Delete)操作时,SpringBoot提供了非常方便的集成方案,让我们无需像使用MyBatis那样手动编写大量的SQL映射文件和DAO层代码。 本项目"springboot-mysql-crud-...
CRUD是Create(创建)、Read(读取)、Update(更新)和Delete(删除)四种基本数据库操作的缩写,是数据库管理的核心。 在avue中,"数据字典"通常用来表示一组固定的选项或者枚举值,例如性别、状态、级别等,这些...
【标题】"crud-demo_easyui增删查改_zip_" 指的是一个使用EasyUI框架实现的CRUD(Create, Read, Update, Delete)操作演示项目,被压缩为ZIP格式的文件。CRUD是数据库操作的基本功能,代表创建、读取、更新和删除...
CRUD(Create, Read, Update, Delete)是数据库操作的核心概念,代表了创建、读取、更新和删除数据的基本操作。在IT行业中,尤其是软件开发领域,熟练掌握CRUD操作对于构建任何数据驱动的应用程序都是至关重要的。...
在本文中,我们将深入探讨基于Laravel框架的CRUD(Create, Read, Update, Delete)生成器,特别是在Laravel 5版本中的应用。Laravel是一个优雅且强大的PHP框架,它为开发者提供了许多便利,使他们能够快速构建高质量...
tgext.crud库主要提供了一套用于创建CRUD(Create, Read, Update, Delete)操作的工具,对于Web应用开发而言,这是一个非常实用的功能。 CRUD是数据库操作的基础,通常用于构建应用程序的后台逻辑。tgext.crud库...