提交 a471e6b4 编写于 作者: M Michael Koziarski

allow the 'lock_version' column to be configured with set_locking_column. Closes #3402


git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@3422 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
上级 62d749ab
*SVN*
* Allow configuration of the column used for optimistic locking [wilsonb@gmail.com]
* Don't hardcode 'id' in acts as list. [ror@philippeapril.com]
* Fix date errors for SQLServer in association tests. #3406 [kevin.clark@gmal.com]
......
......@@ -18,6 +18,8 @@ module ActiveRecord
# You must ensure that your database schema defaults the lock_version column to 0.
#
# This behavior can be turned off by setting <tt>ActiveRecord::Base.lock_optimistically = false</tt>.
# To override the name of the lock_version column, invoke the <tt>set_locking_column</tt> method.
# This method uses the same syntax as <tt>set_table_name</tt>
module Locking
def self.append_features(base) #:nodoc:
super
......@@ -29,13 +31,15 @@ def self.append_features(base) #:nodoc:
def update_with_lock #:nodoc:
if locking_enabled?
previous_value = self.lock_version
self.lock_version = previous_value + 1
lock_col = self.class.locking_column
previous_value = send(lock_col)
send(lock_col + '=', previous_value + 1)
affected_rows = connection.update(<<-end_sql, "#{self.class.name} Update with optimistic locking")
UPDATE #{self.class.table_name}
SET #{quoted_comma_pair_list(connection, attributes_with_quotes(false))}
WHERE #{self.class.primary_key} = #{quote(id)} AND lock_version = #{quote(previous_value)}
WHERE #{self.class.primary_key} = #{quote(id)}
AND #{lock_col} = #{quote(previous_value)}
end_sql
unless affected_rows == 1
......@@ -52,7 +56,24 @@ class Base
cattr_accessor :lock_optimistically
def locking_enabled? #:nodoc:
lock_optimistically && respond_to?(:lock_version)
lock_optimistically && respond_to?(self.class.locking_column)
end
class << self
def set_locking_column( value=nil, &block )
define_attr_method :locking_column, value, &block
end
def locking_column
reset_locking_column
end
def reset_locking_column
default = 'lock_version'
set_locking_column(default)
default
end
end
end
end
......@@ -25,3 +25,4 @@ DROP TABLE categories_posts;
DROP TABLE fk_test_has_pk;
DROP TABLE fk_test_has_fk;
DROP TABLE keyboards;
DROP TABLE legacy_things;
......@@ -194,3 +194,11 @@ CREATE TABLE fk_test_has_fk (
FOREIGN KEY (fk_id) REFERENCES fk_test_has_pk(id)
);
--This table has an altered lock_version column name
CREATE TABLE legacy_things (
id INT GENERATED BY DEFAULT AS IDENTITY (START WITH 10000),
tps_report_number INT DEFAULT NULL,
version INT DEFAULT 0,
PRIMARY KEY (id)
);
......@@ -26,6 +26,7 @@ DROP TABLE fk_test_has_fk;
DROP TABLE fk_test_has_pk;
DROP TABLE keyboards;
DROP TABLE defaults;
DROP TABLE legacy_things;
DROP DOMAIN D_BOOLEAN;
......
......@@ -257,3 +257,12 @@ CREATE TABLE defaults (
);
CREATE GENERATOR defaults_seq;
SET GENERATOR defaults_seq TO 10000;
CREATE TABLE legacy_things (
id BIGINT NOT NULL,
tps_report_number INTEGER,
version INTEGER DEFAULT 0 NOT NULL,
PRIMARY KEY (id)
);
CREATE GENERATOR legacy_things_seq;
SET GENERATOR legacy_things_seq TO 10000;
......@@ -25,3 +25,4 @@ DROP TABLE categories_posts;
DROP TABLE fk_test_has_fk;
DROP TABLE fk_test_has_pk;
DROP TABLE keyboards;
DROP TABLE legacy_things;
......@@ -197,3 +197,11 @@ CREATE TABLE `keyboards` (
`key_number` int(11) NOT NULL auto_increment primary key,
`name` varchar(50) default NULL
);
--Altered lock_version column name.
CREATE TABLE `legacy_things` (
`id` int(11) NOT NULL auto_increment,
`tps_report_number` int(11) default NULL,
`version` int(11) NOT NULL default 0,
PRIMARY KEY (`id`)
) TYPE=InnoDB;
......@@ -26,6 +26,8 @@ drop table posts;
drop table fk_test_has_pk;
drop table fk_test_has_fk;
drop table keyboards;
drop table legacy_things;
drop sequence accounts_seq;
drop sequence companies_nonstd_seq;
drop sequence topics_seq;
......@@ -53,3 +55,4 @@ drop sequence categories_posts_seq;
drop sequence fk_test_has_pk_seq;
drop sequence fk_test_has_fk_seq;
drop sequence keyboards_seq;
drop sequence legacy_things_seq;
......@@ -269,3 +269,10 @@ create table test_oci_defaults (
);
create sequence test_oci_defaults_seq minvalue 10000;
--This table has an altered lock_version column name.
create table legacy_things (
id integer not null primary key,
tps_report_number integer default null,
version integer default 0
);
create sequence legacy_things_seq minvalue 10000;
......@@ -28,3 +28,4 @@ DROP TABLE fk_test_has_fk;
DROP TABLE fk_test_has_pk;
DROP TABLE geometrics;
DROP TABLE keyboards;
DROP TABLE legacy_things;
......@@ -225,3 +225,10 @@ CREATE TABLE keyboards (
key_number serial primary key,
"name" character varying(50)
);
--Altered lock_version column name.
CREATE TABLE legacy_things (
id serial primary key,
tps_report_number integer,
version integer default 0
);
......@@ -25,3 +25,4 @@ DROP TABLE categories_posts;
DROP TABLE fk_test_has_fk;
DROP TABLE fk_test_has_pk;
DROP TABLE keyboards;
DROP TABLE legacy_things;
......@@ -181,3 +181,10 @@ CREATE TABLE 'keyboards' (
'key_number' INTEGER PRIMARY KEY NOT NULL,
'name' VARCHAR(255) DEFAULT NULL
);
--Altered lock_version column name.
CREATE TABLE 'legacy_things' (
'id' INTEGER NOT NULL PRIMARY KEY,
'tps_report_number' INTEGER DEFAULT NULL,
'version' INTEGER NOT NULL DEFAULT 0
)
......@@ -25,3 +25,4 @@ DROP TABLE categories_posts;
DROP TABLE fk_test_has_fk;
DROP TABLE fk_test_has_pk;
DROP TABLE keyboards;
DROP TABLE legacy_things;
......@@ -181,3 +181,11 @@ CREATE TABLE keyboards (
key_number int NOT NULL IDENTITY(1, 1) PRIMARY KEY,
name varchar(50) default NULL
);
--This table has an altered lock_version column name.
CREATE TABLE legacy_things (
id int NOT NULL IDENTITY(1, 1),
tps_report_number int default NULL,
version int default 0,
PRIMARY KEY (id)
);
class LegacyThing < ActiveRecord::Base
set_locking_column :version
end
obtuse:
id: 1
tps_report_number: 500
require 'abstract_unit'
require 'fixtures/person'
require 'fixtures/legacy_thing'
class LockingTest < Test::Unit::TestCase
fixtures :people
fixtures :people, :legacy_things
def test_lock_existing
p1 = Person.find(1)
......@@ -28,5 +29,18 @@ def test_lock_new
p2.first_name = "should fail"
p2.save
}
end
def test_lock_column_name_existing
t1 = LegacyThing.find(1)
t2 = LegacyThing.find(1)
t1.tps_report_number = 400
t1.save
assert_raises(ActiveRecord::StaleObjectError) {
t2.tps_report_number = 300
t2.save
}
end
end
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册