- 浏览: 118418 次
- 性别:
- 来自: 火星
文章分类
最新评论
-
hexawing:
相当好的入门级文章,收藏学习了!
rake任務詳解 -
minn84:
...
2012目标 -
luopeng_sg:
请问LZ这用的是JRuby还是CRuby呢?
验证码生成插件simple_captcha -
orcl_zhang:
2套?有钱人。100本,貌似有点多。
2012目标 -
keating:
来捣乱
要有梦
1.當你在開發模式下運行Rails服務器時,通過Web瀏覽器對數據表結構的改動會立即在ActiveRecord對象中反映出來.然而,如果你運行著Rails的控制臺,那么對數據表結構的改動并不會自動反映到ActiveRecord對象.當然,你可以通過手動的方式將這些改動反映出來,在控制臺輸入Dispatcher.reset_application!即可.
2.遷移是Rails提供的一種幫助你更新應用程序的數據表結構(也就是熟悉的數據描述語言========DDL)的方式,通過它,在每次改變應用程序代碼的時候,你不需要刪除或者重新創建數據表,這就意味著你不會丟失開發數據.在執行遷移的時候,唯一改變的事將數據表結構從一個版本改為另一個版本,不管這個改動是版本更新還是回退.
3.Rails針對創建遷移提供了一個生成器.我們可以通過命令行查看幫助文本,如下所示:
從上可知,你只需要為遷移提供一個駝峰式的描述性名字,生成器就能完成余下的工作.在需要改變現有表的屬性時,我們只要直接調用生成器即可.(備注:諸如數據庫模型生成器等其他的生成器同樣為你創建遷移腳本,除非你特別指定了----skip-migration選項)
4.所有列選項都接受下面三個選項,
6.別用浮點數來存儲貨幣值,或者說,別用浮點數來存儲需要固定精度的所有類型的數據.
7.ActiveRecord有一個attributes方法,它返回一個散列,包括所有屬性和相應的值(通過read_attribute方法返回的值).如果使用自定義的屬性讀寫器,那么attributes方法被調用的時候,它并不會使用自定義的屬性讀取器來訪問屬性值,但是attributes= (在其中進行大量賦值操作)確實會調用自定義的屬性寫入器.(備注,通過attributes方法返回的散列并不是ActiveRecord對象內部結構的引用,而是一個副本,這意味著改變它的值并不會對原對象造成影響.)
8.對于許多程序而言,最常見的操作就是基于一個或兩個列進行簡單的查詢.因此Rails提供了一種簡單而有效的方式來進行這些查詢,并且不需要通過find方法的條件參數.這種方式能夠實現,有賴于Ruby那充滿魔力的method_missing回調,每當你調用了還沒有定義的方法的時候,這個回調就會被調用.
9.find_or_create_by_:如果對象存在,那么查找器就會返回它,否則會創建一個并且返回創建的對象.(備注:如果你不想一開始就保存創建的對象,可以使用find_or_initialize_by_查找器)
10.find_by_sql這個類方法可以直接使用SQL的Select查詢,并且給予查詢結果,返回ActiveRecord對象的數組.
eg:
備注:你應該慎用此方法,除非是在不得不用的時候.
(1)這個方法減少了數據庫的可移植性,如果使用了ActiveRecord正規的find方法,那么Rails會在底層為你處理好不同數據庫之間的差異.
(2)ActiveRecord已經擁有了一堆內建的函數,用于抽象select語句,因此,重新發明新的方式來實現同樣的功能是不明智的.
11.update_all,它與使用update..where這樣的SQL語句進行更新是緊密對應的.update_all方法可以接受兩個參數,一個對應于SQL語句的SET部分,而另一個則對應于WHERE子句,也就是條件.這個方法返回了更新記錄的數目.
eg:
12.在ActiveRecord中的屬性,在你需要防止一時疏忽以及大量賦值操作的時候,你可以使用下面兩個類方法來控制對屬性的訪問.
(1)attr_accessible方法以屬性列表為參數,這個列表指明了能夠用于大量賦值的可訪問屬性.(這是用于大量賦值的一種更保守的做法)
(2)如果在默認的情況下,大部分屬性都是開放的,而只有在需要的時候才會被限制某些屬性訪問時,你應該使用attr_protected方法.傳遞給這個方法的屬性將會受到保護,不能用于大量賦值.在大量賦值過程中,這些屬性的賦值會簡單地被忽略,你只能通過直接復制到方法來為這些屬性賦值,如下eg所示:
13.刪除和銷毀
如果你需要從數據庫中移除某個記錄,那么你有兩種選擇:
(1)destroy方法不僅將記錄從數據庫中移除,還會凍結它(將其設為只讀),這樣你就不能再次保存它.
(2)另一種可選的方法是可以將destroy和delete方法作為類方法進行調用,只需要傳遞所刪除的id即可.兩個方法都能接受單個id或者id數組作為參數.
方法的命名看起來有些前后矛盾,事實上并非如此.delete方法直接使用SQL語句,并且不會裝載任何實例(因此會更快).destroy方法會裝載ActiveRecord對象實例,并且通過實例來調用destroy方法.兩者的語義差別是非常細微的,不過,如果你在before_destroy回調中進行了賦值或者擁有依賴關聯的時候,差別就會凸現了.在有依賴關聯的情況下,調用destroy方法會使得子對象和父對象一起被刪除.
14.數據庫鎖定
"鎖定"是一個專業術語,它是指用于防止應用程序的并發用戶復寫各操作結果的技術.從數據庫裝載數據模型數據的時候,ActiveRecord通常都不會使用任何類型的鎖,如果某個特定的Rails應用程序在同一時間只有一個用戶在更新數據,那么你并不需要擔心鎖的問題.
當多于一個的用戶同時訪問并且更新相同數據的時候,你作為開發人員務必要考慮并發性的問題,這是非常重要的.自我提問一下,如果兩個用戶同時嘗試更新某個特定的數據模型,會發生什么類型的沖突(collision)或者競爭條件(race collision)呢?
在數據庫支撐的應用程序中,有很多方法可以處理并發性問題,而ActiveRecord支持中的兩種方式:樂觀鎖定(optimistic locking)和悲觀鎖定(pessimistic locking).
(1)樂觀鎖定
是指在沖突發生的時候用于檢測并且解決沖突的策略.在多用戶并且沖突發生較少的情況下,樂觀鎖定是受推崇的.在使用樂觀鎖定的時候,數據記錄并不會真正被鎖定,因此"樂觀鎖定"這個術語多少有點用詞不當.
樂觀鎖定是個非常常用的策略,因為對于絕大多數應用程序的設計而言,某個特定用戶主要還是更新屬于它自己的數據,而不是別人的,所有兩個用戶搶著更新同一個數據的可能性極少.樂觀鎖定潛在的意圖是既然沖突很少發生,那么只有它們真的發生的時候,我們才去處理它.
如果你控制數據庫表結構,那么樂觀鎖定是很容易實現的.對于某個特定的表,你只需要增加一個lock_version、默認值為零點整數列即可
增加了lock_version之后,ActiveRecord的功能就會改變.如果兩個不同的數據模型實例被裝載并且被不同用戶保存,那么第一個實例將會成功保存,而第二個實例將會導致ActiveRecord::StaleObjectError異常拋出.
我們可以通過一個簡單的單元測試來說明樂觀鎖定的功能:
測試通過了,因為調用第二個實例的save方法會引發ActiveRecord::StaleObjectError異常,這是我們期待的效果.
(備注:
a.要使用其它數據列代替lock_version,那么你可以使用set_locking_column來改變這個設置.要讓這個改動應用于整個應用程序,則需要在enviroment,rb中增加以下代碼:
ActiveRecord::Base.set_locking_column 'alternate_lock_version'
與其它ActiveRecord設置類似,你可以在數據模型類中增加一個生命,從而改變單個數據模型的設置.
b.處理StaleObjectError
在設置了樂觀鎖定之后,我們需要得體的處理StaleObjectError.根據更新數據不同的關鍵性,你可能需要花費很多時間去構建對用戶友好的解決方案,以便保存更新失敗的用戶所提交的數據.即使是在更新數據很容易再創建的情況下,只要要通過一些控制器代碼讓用戶知道為什么更新失敗,如下所示:
)
樂觀鎖定有很多優勢,它不需要數據庫提供特殊的支持,而且容易實現,正如你從代碼中看到的,處理StaleObjectError只需要很少的代碼.而樂觀鎖定的缺點主要集中在更新操作會慢一些,因為應用程序會檢查鎖定版本.除此以外,它可能會造成糟糕的用戶體驗,因為在更新提交之前,用戶無法知道更新能否成功.如果更新數據丟失,那么用戶會感到非常憤怒...(這才是他媽的用戶體驗...設身處地的想,我要提交了一次,然后無端端失敗,并且數據也沒了,比如寫了Blog,我肯定是沒興趣再玩下去,并且會對這個網站產生厭煩的感覺,并告知所有我知道的人....或者直接找站長理論去...)
(2)悲觀鎖定
它需要特所的數據庫支持(大型數據類都內嵌了這樣的支持),并且在更新操作發生的時候鎖定特定的數據行.這樣防止了其他用戶讀取將要更新的數據,從而避免用戶操作已經失效的數據.
對于Rails而言,悲觀鎖定是非常新的附加特性.在下面的例子中,悲觀鎖定與事務一起配合工作.
eg:
對于一個存在的數據模型實例調用lock!方法也是可行的,這個方法在底層只是簡單地調用"reload(:lock => true)".對于一個底層包含屬性更改的實例,你則不應該這樣,因為重新載入的操作會丟失屬性的更改.
悲觀鎖定在數據庫的層面上起作用.油ActiveRecord生成的SELECT語句會包含FOR UPDATE(或者類似的內容)子句,這樣就使得其他所有鏈接都無法訪問由該SELETE語句返回的數據行.只有在事務提交之后,鎖才會被釋放.從理論上說,假如Rails進程在數據事務操作完成之前結束,那么在連接被終止或者超時之前,鎖都不會被釋放
(3)需要考慮到問題
使用樂觀鎖定的Web應用程序會獲得最佳的伸縮性,因為它不使用特定的數據庫所提供的鎖定功能,這在前文已經討論過了.不過,你不得不為應用程序增加相應的邏輯,以便處理更新失敗的情況.悲觀鎖定會實現得更容易一些,但是又會引發以下的問題:在一個Rails進程等待另外一個Rails進程釋放數據鎖定的時候,它只是在等待,也就無法為其它進入的需求提供服務了.(請記住:Rails是單線程的)
作者說:既然在Rails中,數據庫事務的持久化并不會跨越多個HTTP請求,而悲觀鎖定又在另一個平臺上,所以它并不危險.事實上,可以確定,在這樣一個無分享(shared-nothing)架構中,跨越多個HTTP請求的數據庫事務的持久化是不可能實現的.
另外一個需要留意到情況是許多用戶爭相訪問某個特定的記錄,而更新這個特定記錄又需要很長的時間.為了實現最佳的效果,要讓使用悲觀鎖定的事務保持足夠小,并且確定它們能夠很快的執行.
15.高級查找
我們通常都需要通過某些條件(對應WHERE子句)對查找操作(底層就是一個SELECT的SQL語句)獲得的結果集進行篩選.ActiveRecord為你提供許多方式來實現這個功能,也就是將散列傳遞給find方法.
2.遷移是Rails提供的一種幫助你更新應用程序的數據表結構(也就是熟悉的數據描述語言========DDL)的方式,通過它,在每次改變應用程序代碼的時候,你不需要刪除或者重新創建數據表,這就意味著你不會丟失開發數據.在執行遷移的時候,唯一改變的事將數據表結構從一個版本改為另一個版本,不管這個改動是版本更新還是回退.
3.Rails針對創建遷移提供了一個生成器.我們可以通過命令行查看幫助文本,如下所示:
$ script/generate migration Usage: script/generate migration MigrationName [options] Rails Info: -v, --version Show the Rails version and quit. -h, --help Show this help message and quit. General Options: -p, --pretend Run but do not make any changes. -f, --force Overwrite files that already exist. -s, --skip Skip files that already exist. -q, --quiet Suppress normal output. -t, --backtrace Debugging: show backtrace on errors. -c, --svn Modify files with subversion. (Note: svn must be in path) Description: The migration generator creates a stub for a new database migration. The generator takes a migration name as its argument. The migration name may be given in CamelCase or under_score. The generator creates a migration class in db/migrate prefixed by its number in the queue. Example: ./script/generate migration AddSslFlag With 4 existing migrations, this will create an AddSslFlag migration in the file db/migrate/005_add_ssl_flag.rb
從上可知,你只需要為遷移提供一個駝峰式的描述性名字,生成器就能完成余下的工作.在需要改變現有表的屬性時,我們只要直接調用生成器即可.(備注:諸如數據庫模型生成器等其他的生成器同樣為你創建遷移腳本,除非你特別指定了----skip-migration選項)
4.所有列選項都接受下面三個選項,
引用
(1):default => value
設置默認值.在創建數據行的時候,該默認值將作為該列的初始值.如果你希望值為null,那么你并不需要進行顯式的設置,只要不設置該項即可.
(2)limit => size
為字符串、文本、二進制或者整數列增加一個范圍大小的參數.根據列類型不同,這個參數的含義也會相應不同.一般來說,對于字符串類型的限制是指字符的個數,而對于其他類型,大小規則是指在數據庫中存儲相應值所需的字節數
(3):null => true
通過增加not null的約束到數據庫的級別上,將某個列設為必須的.
5.小數精度
聲明為:decimal的列接受以下兩個選項:
(1):precision = > number
精度(precision)是指數字的總位數
(2):scale => number
而數值范圍(scale)則是小數點后面數字的總位數.
eg: 123.45的精度為5,而數值范圍是2(自從加入火星后,現在對這個數字很敏感.....)
設置默認值.在創建數據行的時候,該默認值將作為該列的初始值.如果你希望值為null,那么你并不需要進行顯式的設置,只要不設置該項即可.
(2)limit => size
為字符串、文本、二進制或者整數列增加一個范圍大小的參數.根據列類型不同,這個參數的含義也會相應不同.一般來說,對于字符串類型的限制是指字符的個數,而對于其他類型,大小規則是指在數據庫中存儲相應值所需的字節數
(3):null => true
通過增加not null的約束到數據庫的級別上,將某個列設為必須的.
5.小數精度
聲明為:decimal的列接受以下兩個選項:
(1):precision = > number
精度(precision)是指數字的總位數
(2):scale => number
而數值范圍(scale)則是小數點后面數字的總位數.
eg: 123.45的精度為5,而數值范圍是2(自從加入火星后,現在對這個數字很敏感.....)
6.別用浮點數來存儲貨幣值,或者說,別用浮點數來存儲需要固定精度的所有類型的數據.
7.ActiveRecord有一個attributes方法,它返回一個散列,包括所有屬性和相應的值(通過read_attribute方法返回的值).如果使用自定義的屬性讀寫器,那么attributes方法被調用的時候,它并不會使用自定義的屬性讀取器來訪問屬性值,但是attributes= (在其中進行大量賦值操作)確實會調用自定義的屬性寫入器.(備注,通過attributes方法返回的散列并不是ActiveRecord對象內部結構的引用,而是一個副本,這意味著改變它的值并不會對原對象造成影響.)
8.對于許多程序而言,最常見的操作就是基于一個或兩個列進行簡單的查詢.因此Rails提供了一種簡單而有效的方式來進行這些查詢,并且不需要通過find方法的條件參數.這種方式能夠實現,有賴于Ruby那充滿魔力的method_missing回調,每當你調用了還沒有定義的方法的時候,這個回調就會被調用.
9.find_or_create_by_:如果對象存在,那么查找器就會返回它,否則會創建一個并且返回創建的對象.(備注:如果你不想一開始就保存創建的對象,可以使用find_or_initialize_by_查找器)
10.find_by_sql這個類方法可以直接使用SQL的Select查詢,并且給予查詢結果,返回ActiveRecord對象的數組.
eg:
>>Client.find_by_sql("select * from clients")
備注:你應該慎用此方法,除非是在不得不用的時候.
(1)這個方法減少了數據庫的可移植性,如果使用了ActiveRecord正規的find方法,那么Rails會在底層為你處理好不同數據庫之間的差異.
(2)ActiveRecord已經擁有了一堆內建的函數,用于抽象select語句,因此,重新發明新的方式來實現同樣的功能是不明智的.
>>Client.find_by_sql("select * from clients where code like 'A%'") ==> >> param = "A" >>Clinent.find(:all, :coditions => ["code like?", "#{param}%"])
11.update_all,它與使用update..where這樣的SQL語句進行更新是緊密對應的.update_all方法可以接受兩個參數,一個對應于SQL語句的SET部分,而另一個則對應于WHERE子句,也就是條件.這個方法返回了更新記錄的數目.
eg:
Order.update_all("name = 'Yang'", "pay_type= 'cc'")
12.在ActiveRecord中的屬性,在你需要防止一時疏忽以及大量賦值操作的時候,你可以使用下面兩個類方法來控制對屬性的訪問.
(1)attr_accessible方法以屬性列表為參數,這個列表指明了能夠用于大量賦值的可訪問屬性.(這是用于大量賦值的一種更保守的做法)
(2)如果在默認的情況下,大部分屬性都是開放的,而只有在需要的時候才會被限制某些屬性訪問時,你應該使用attr_protected方法.傳遞給這個方法的屬性將會受到保護,不能用于大量賦值.在大量賦值過程中,這些屬性的賦值會簡單地被忽略,你只能通過直接復制到方法來為這些屬性賦值,如下eg所示:
class Customer < ActiveRecord::Base attr_protected :credit_rating end customer = Customer.new(:name => “Abe”, :credit_rating => “Excellent”) customer.credit_rating # => nil customer.attributes = { “credit_rating” => “Excellent” } customer.credit_rating # => nil # and now, the allowed way to set a credit_rating customer.credit_rating = “Average” customer.credit_rating # => “Average”
13.刪除和銷毀
如果你需要從數據庫中移除某個記錄,那么你有兩種選擇:
(1)destroy方法不僅將記錄從數據庫中移除,還會凍結它(將其設為只讀),這樣你就不能再次保存它.
>> bad_timesheet = Timesheet.find(1) >> bad_timesheet.destroy => #<Timesheet:0x2481d70 @attributes={“updated_at”=>”2006-11-21 05:40:27”, “id”=>”1”, “user_id”=>”1”, “submitted”=>nil, “created_at”=> “2006-11-21 05:40:27”}> >> bad_timesheet.save TypeError: can’t modify frozen hash from activerecord/lib/active_record/base.rb:1965:in `[]=’
(2)另一種可選的方法是可以將destroy和delete方法作為類方法進行調用,只需要傳遞所刪除的id即可.兩個方法都能接受單個id或者id數組作為參數.
Timesheet.delete(1) Timesheet.destroy([2, 3])
方法的命名看起來有些前后矛盾,事實上并非如此.delete方法直接使用SQL語句,并且不會裝載任何實例(因此會更快).destroy方法會裝載ActiveRecord對象實例,并且通過實例來調用destroy方法.兩者的語義差別是非常細微的,不過,如果你在before_destroy回調中進行了賦值或者擁有依賴關聯的時候,差別就會凸現了.在有依賴關聯的情況下,調用destroy方法會使得子對象和父對象一起被刪除.
14.數據庫鎖定
"鎖定"是一個專業術語,它是指用于防止應用程序的并發用戶復寫各操作結果的技術.從數據庫裝載數據模型數據的時候,ActiveRecord通常都不會使用任何類型的鎖,如果某個特定的Rails應用程序在同一時間只有一個用戶在更新數據,那么你并不需要擔心鎖的問題.
當多于一個的用戶同時訪問并且更新相同數據的時候,你作為開發人員務必要考慮并發性的問題,這是非常重要的.自我提問一下,如果兩個用戶同時嘗試更新某個特定的數據模型,會發生什么類型的沖突(collision)或者競爭條件(race collision)呢?
在數據庫支撐的應用程序中,有很多方法可以處理并發性問題,而ActiveRecord支持中的兩種方式:樂觀鎖定(optimistic locking)和悲觀鎖定(pessimistic locking).
(1)樂觀鎖定
是指在沖突發生的時候用于檢測并且解決沖突的策略.在多用戶并且沖突發生較少的情況下,樂觀鎖定是受推崇的.在使用樂觀鎖定的時候,數據記錄并不會真正被鎖定,因此"樂觀鎖定"這個術語多少有點用詞不當.
樂觀鎖定是個非常常用的策略,因為對于絕大多數應用程序的設計而言,某個特定用戶主要還是更新屬于它自己的數據,而不是別人的,所有兩個用戶搶著更新同一個數據的可能性極少.樂觀鎖定潛在的意圖是既然沖突很少發生,那么只有它們真的發生的時候,我們才去處理它.
如果你控制數據庫表結構,那么樂觀鎖定是很容易實現的.對于某個特定的表,你只需要增加一個lock_version、默認值為零點整數列即可
class AddLockVersionToTimesheets < ActiveRecord::Migration def self.up add_column :timesheets, :lock_version, :integer, :default => 0 end def self.down remove_column :timesheets, :lock_version end end
增加了lock_version之后,ActiveRecord的功能就會改變.如果兩個不同的數據模型實例被裝載并且被不同用戶保存,那么第一個實例將會成功保存,而第二個實例將會導致ActiveRecord::StaleObjectError異常拋出.
我們可以通過一個簡單的單元測試來說明樂觀鎖定的功能:
class TimesheetTest < Test::Unit::TestCase fixtures :timesheets, :users def test_optimistic_locking_behavior first_instance = Timesheet.find(1) second_instance = Timesheet.find(1) first_instance.approver = users(:approver) second_instance.approver = users(:approver2) assert first_instance.save, "First instance save succeeded" assert_raises ActiveRecord::StaleObjectError do second_instance.save end end end
測試通過了,因為調用第二個實例的save方法會引發ActiveRecord::StaleObjectError異常,這是我們期待的效果.
(備注:
a.要使用其它數據列代替lock_version,那么你可以使用set_locking_column來改變這個設置.要讓這個改動應用于整個應用程序,則需要在enviroment,rb中增加以下代碼:
ActiveRecord::Base.set_locking_column 'alternate_lock_version'
與其它ActiveRecord設置類似,你可以在數據模型類中增加一個生命,從而改變單個數據模型的設置.
class Timesheet < ActiveRecord::Base set_locking_column ‘alternate_lock_version’ end
b.處理StaleObjectError
在設置了樂觀鎖定之后,我們需要得體的處理StaleObjectError.根據更新數據不同的關鍵性,你可能需要花費很多時間去構建對用戶友好的解決方案,以便保存更新失敗的用戶所提交的數據.即使是在更新數據很容易再創建的情況下,只要要通過一些控制器代碼讓用戶知道為什么更新失敗,如下所示:
def update begin @timesheet = Timesheet.find(params[:id]) @timesheet.update_attributes(params[:timesheet]) # redirect somewhere rescue ActiveRecord::StaleObjectError flash[:error] = "Timesheet was modified while you were editing it." redirect_to :action => ‘edit’, :id => @timesheet end end
)
樂觀鎖定有很多優勢,它不需要數據庫提供特殊的支持,而且容易實現,正如你從代碼中看到的,處理StaleObjectError只需要很少的代碼.而樂觀鎖定的缺點主要集中在更新操作會慢一些,因為應用程序會檢查鎖定版本.除此以外,它可能會造成糟糕的用戶體驗,因為在更新提交之前,用戶無法知道更新能否成功.如果更新數據丟失,那么用戶會感到非常憤怒...(這才是他媽的用戶體驗...設身處地的想,我要提交了一次,然后無端端失敗,并且數據也沒了,比如寫了Blog,我肯定是沒興趣再玩下去,并且會對這個網站產生厭煩的感覺,并告知所有我知道的人....或者直接找站長理論去...)
(2)悲觀鎖定
它需要特所的數據庫支持(大型數據類都內嵌了這樣的支持),并且在更新操作發生的時候鎖定特定的數據行.這樣防止了其他用戶讀取將要更新的數據,從而避免用戶操作已經失效的數據.
對于Rails而言,悲觀鎖定是非常新的附加特性.在下面的例子中,悲觀鎖定與事務一起配合工作.
eg:
Timesheet.transaction do t = Timesheet.find(1, :lock=> true) t.approved = true t.save! end
對于一個存在的數據模型實例調用lock!方法也是可行的,這個方法在底層只是簡單地調用"reload(:lock => true)".對于一個底層包含屬性更改的實例,你則不應該這樣,因為重新載入的操作會丟失屬性的更改.
悲觀鎖定在數據庫的層面上起作用.油ActiveRecord生成的SELECT語句會包含FOR UPDATE(或者類似的內容)子句,這樣就使得其他所有鏈接都無法訪問由該SELETE語句返回的數據行.只有在事務提交之后,鎖才會被釋放.從理論上說,假如Rails進程在數據事務操作完成之前結束,那么在連接被終止或者超時之前,鎖都不會被釋放
(3)需要考慮到問題
使用樂觀鎖定的Web應用程序會獲得最佳的伸縮性,因為它不使用特定的數據庫所提供的鎖定功能,這在前文已經討論過了.不過,你不得不為應用程序增加相應的邏輯,以便處理更新失敗的情況.悲觀鎖定會實現得更容易一些,但是又會引發以下的問題:在一個Rails進程等待另外一個Rails進程釋放數據鎖定的時候,它只是在等待,也就無法為其它進入的需求提供服務了.(請記住:Rails是單線程的)
作者說:既然在Rails中,數據庫事務的持久化并不會跨越多個HTTP請求,而悲觀鎖定又在另一個平臺上,所以它并不危險.事實上,可以確定,在這樣一個無分享(shared-nothing)架構中,跨越多個HTTP請求的數據庫事務的持久化是不可能實現的.
另外一個需要留意到情況是許多用戶爭相訪問某個特定的記錄,而更新這個特定記錄又需要很長的時間.為了實現最佳的效果,要讓使用悲觀鎖定的事務保持足夠小,并且確定它們能夠很快的執行.
15.高級查找
我們通常都需要通過某些條件(對應WHERE子句)對查找操作(底層就是一個SELECT的SQL語句)獲得的結果集進行篩選.ActiveRecord為你提供許多方式來實現這個功能,也就是將散列傳遞給find方法.
引用
(1):conditions 參數指定了查詢條件,而它可以被指定為字符串、數組或者散列,代表著SQL語句的WHERE部分.如果輸入數據源自外部,那么數組形式的參數就會被使用.
如果你指定的條件包含布爾值,那么你就需要特別留意.不同的數據庫有多種不同的方式表達布爾值.有的是"1"和"0",而有的是"T"和"F".
如果你使用數組或者散列作為條件并且使用Ruby布爾值作為參數,那么Rails會為你處理數據轉換的問題,這對用戶來說是透明的.
(2):order選項能通過SQL子句來指定數據列的排序.
(備注:SQL規范制定:在省略ascending/descending)選項的情況下,默認排序是升序的.
隨機排序
Rails并不會對:order選項的值進行校驗,這意味著你可以傳遞任何值,而不只是排序的列或升降序,只要底層數據庫能夠理解該值即可.在需要獲取一個隨機值的時候,該特性十分有用,以下例子說明了這一點:
(ff:請記住,對大型的數據集進行隨機排序會造成嚴重的性能問題,大多數數據庫都是如此,MySQL的問題尤為明顯.)
(3):limit能夠接受整形的參數,從而對查詢返回的數據行的數量進行限制.:offset參數則指定了偏移量,也就是從結果集的哪一行開始獲取數據行,它的取值范圍為1至最大的索引.這兩個選項合在一起,都用于對結果進行分頁.
eg:針對10個記錄一頁的時間表列表,以下代碼就用于查找第二頁的記錄.
(備注:根據應用程序數據模型的細節,對于某一特定的查詢,總是限制其獲取的ActiveRecord對象的最大數量是非常有意義的.如果讓用戶能夠觸發一些查詢,并一次性獲取了成千上萬的ActiveRecord對象,就無疑是引火ZF(cao ni ma ge B ---FGW,這也算敏感詞).)
(4):select
在默認情況下,:select選項是"*",與"SELECT * FROM"語句類似.但是,在需要的時候,這個值是可以改變的.
eg:
(備注:
要獲取對象常規的列值以及計算出來的列值,需要給:select參數增加個*
)
(5):form選項指定了所生成的SQL語句的表名部分.如果你需要包含用于連接的額外表或者對數據視圖的引用,那么你可以提供一個自定義值.
eg:
(備注:如果你在思考為什么使用table_name而不是一個顯式的值,那么可以告訴你,因為這個代碼混入(mixin)到了一個使用Ruby 模組的目標類)
(6)group by 選項
通過某個屬性名,我們能夠將結果集進行分組,就像GROUP BY SQL子句一樣.一般來說,你需要將:group選項結合:select選項一起用,因為合法的SQL要求包含分組操作的SELECT語句所選取的列要么是聚合函數,要么就是數據表的常規列.
(備注:額外獲取的列值是字符串類型 -------ActiveRecord并不會對它們進行類型轉換.你需要使用to_i和to_f方法將它們轉換為數據類型.
)
(7):lock
在事務作用域內對查找操作指定":lock => true"選項會對選取的數據行設置唯一的鎖.
(8):joins
在你執行“GROUP BY”并且聚合了其他表達數據的時候,:joins選項是非常有用的,但你并不需要裝載關聯的對象.
盡管如此,:joins和:include選項最常見的用法還是讓你能夠在單個SELETE語句中主動獲取(eager-fetch)額外的對象.
(9):readonly
指定":readonly => true "選項會將返回的對象標記為只讀的.你可以改變它們的屬性,但是不能將這些更改的屬性保存到數據庫.(ff:這個是個很邪惡的用法)
如果你指定的條件包含布爾值,那么你就需要特別留意.不同的數據庫有多種不同的方式表達布爾值.有的是"1"和"0",而有的是"T"和"F".
如果你使用數組或者散列作為條件并且使用Ruby布爾值作為參數,那么Rails會為你處理數據轉換的問題,這對用戶來說是透明的.
Timesheet.find(:all, :conditions => ['submitted=?', true])
(2):order選項能通過SQL子句來指定數據列的排序.
Timesheet.find(:all, :order => 'created_at desc')
(備注:SQL規范制定:在省略ascending/descending)選項的情況下,默認排序是升序的.
隨機排序
Rails并不會對:order選項的值進行校驗,這意味著你可以傳遞任何值,而不只是排序的列或升降序,只要底層數據庫能夠理解該值即可.在需要獲取一個隨機值的時候,該特性十分有用,以下例子說明了這一點:
# MySQL Timesheet.find(:first, :order => ‘RAND()’) # Postgres Timesheet.find(:first, :order => ‘RANDOM()’) # Microsoft SQL Server Timesheet.find(:first, :order => ‘NEWID()’) # Oracle Timesheet.find(:first, :order => ‘dbms_random.value’)
(ff:請記住,對大型的數據集進行隨機排序會造成嚴重的性能問題,大多數數據庫都是如此,MySQL的問題尤為明顯.)
(3):limit能夠接受整形的參數,從而對查詢返回的數據行的數量進行限制.:offset參數則指定了偏移量,也就是從結果集的哪一行開始獲取數據行,它的取值范圍為1至最大的索引.這兩個選項合在一起,都用于對結果進行分頁.
eg:針對10個記錄一頁的時間表列表,以下代碼就用于查找第二頁的記錄.
Timesheet.find(:all, :limit => 10, :offset => 11)
(備注:根據應用程序數據模型的細節,對于某一特定的查詢,總是限制其獲取的ActiveRecord對象的最大數量是非常有意義的.如果讓用戶能夠觸發一些查詢,并一次性獲取了成千上萬的ActiveRecord對象,就無疑是引火ZF(cao ni ma ge B ---FGW,這也算敏感詞).)
(4):select
在默認情況下,:select選項是"*",與"SELECT * FROM"語句類似.但是,在需要的時候,這個值是可以改變的.
eg:
>> b = BillableWeek.find(:first, :select => "monday_hours + tuesday_hours + wednesday_hours as three_day_total") => #<BillableWeek:0x2345fd8 @attributes={"three_day_total"=>"24"}>
(備注:
warning:>> b.monday_hours NoMethodError: undefined method `monday_hours’ for #<BillableWeek:0x2336f74 @attributes={“three_day_total”=>”24”}> from activerecord/lib/active_record/base.rb:1850:in `method_missing’ from (irb):38
要獲取對象常規的列值以及計算出來的列值,需要給:select參數增加個*
:select => '*, monday_hours + tuesday_hours + wednesday_hours as three_day_total'
)
(5):form選項指定了所生成的SQL語句的表名部分.如果你需要包含用于連接的額外表或者對數據視圖的引用,那么你可以提供一個自定義值.
eg:
def find_tagged_with(list) find(:all, :select =>"#{table_name}.*", :from => "#{table_name}, tags, taggings", :conditions => ["#{table_name}.#{primary_key}=taggings.taggable_id and taggings.taggable_type = ? and taggings.tag_id = tags.id and tags.name IN (?)", name, Tag.parse(list)]) end
(備注:如果你在思考為什么使用table_name而不是一個顯式的值,那么可以告訴你,因為這個代碼混入(mixin)到了一個使用Ruby 模組的目標類)
(6)group by 選項
通過某個屬性名,我們能夠將結果集進行分組,就像GROUP BY SQL子句一樣.一般來說,你需要將:group選項結合:select選項一起用,因為合法的SQL要求包含分組操作的SELECT語句所選取的列要么是聚合函數,要么就是數據表的常規列.
>> users = Account.find(:all, :select => ‘name, SUM(cash) as money’, :group => ‘name’) => [#<User:0x26a744 @attributes={“name”=>”Joe”, “money”=>”3500”}>, #<User:0xaf33aa @attributes={“name”=>”Jane”, “money”=>”9245”}>]
(備注:額外獲取的列值是字符串類型 -------ActiveRecord并不會對它們進行類型轉換.你需要使用to_i和to_f方法將它們轉換為數據類型.
>> users.first.money > 1_000_000 ArgumentError: comparison of String with Fixnum failed from (irb):8:in ‘>’
)
(7):lock
在事務作用域內對查找操作指定":lock => true"選項會對選取的數據行設置唯一的鎖.
(8):joins
在你執行“GROUP BY”并且聚合了其他表達數據的時候,:joins選項是非常有用的,但你并不需要裝載關聯的對象.
Buyer.find(:all, :select => 'buyers.id, count(carts.id) as cart_count', :joins => 'left join carts on carts.buyer_id=buyers.id', :group => 'buyers.id')
盡管如此,:joins和:include選項最常見的用法還是讓你能夠在單個SELETE語句中主動獲取(eager-fetch)額外的對象.
(9):readonly
指定":readonly => true "選項會將返回的對象標記為只讀的.你可以改變它們的屬性,但是不能將這些更改的屬性保存到數據庫.(ff:這個是個很邪惡的用法)
>> c = Comment.find(:first, :readonly => true) => #<Comment id: 1, body: “Hey beeyotch!”> >> c.body = “Keep it clean!” => “Keep it clean!” >> c.save ActiveRecord::ReadOnlyRecord: ActiveRecord::ReadOnlyRecord from /vendor/rails/activerecord/lib/active_record/base.rb:1958
发表评论
-
快闪行动-->为你的项目添加标签模块
2011-04-23 16:44 1224在开始之前,还是要不厌其烦的说说,那些不必要写的你自己搞把,反 ... -
Paperclip在Windows下的那些Po事
2011-04-02 04:22 13241.Paperclip提示command is not rec ... -
FireBug实用指南
2011-03-28 00:14 1429古语有云:工欲善其事必先利其器.对于Web开发人员来说, ... -
在或不在
2011-02-13 23:58 0我在我的路上停止了脚步,为的是走一条新的路...没有人明白我的 ... -
验证码生成插件simple_captcha
2011-01-12 23:37 1932插件地址:https://github.com/eshopwo ... -
关于Mar's shoe的创意思考
2011-01-12 00:52 1040在昨天我的一个伙 ... -
ruby各种小脚本(集装箱)
2010-12-01 03:32 1891有时候听歌听的入迷了,就想下载google的歌词,可是下下来总 ... -
我是rails插件控
2010-12-01 03:01 0有些问题总是有点疑惑,既然能够用插件解决,为啥要自己写呢?反正 ... -
豆瓣“我说”功能的rails简单实现
2010-11-30 23:07 011111 -
用rails开发新版的起点中文网
2010-11-30 23:06 011111 -
用rails实现简单邮件发送测试
2010-11-02 17:53 1490我的环境是ruby1.8.7, rails ... -
工作中遇到的Aajx
2010-10-30 10:22 01.ObjectRange $A($R(1,5)).join( ... -
后台订单处理提醒功能
2010-10-26 17:31 01.参考豆瓣提醒 2. 用户<%= link_to&qu ... -
工作遇到的图片问题
2010-10-26 11:09 0<% record = shirt_window %&g ... -
工作中遇到的JS
2010-10-26 10:17 01.getElementById() 方法可返回对拥有指定 I ... -
页面代码
2010-10-25 13:08 0<% record = shirt_window %&g ... -
工作中遇到的CSS
2010-10-24 20:13 01.cursor 属性规定要显示的光标的类型(形状). 引用 ... -
工作小记
2010-10-19 18:50 01.svn commit 提交要注意别把别人的代码冲走了.. ... -
問答頻道模塊開發
2010-10-12 09:22 0直接參考JE的問道頻道.... -
草稿箱的崛起...
2010-09-30 16:51 0你懂个P啊...
相关推荐
在本项目 "rails-bootstrap-modals" 中,我们将探讨如何在 Rails 4 应用中整合 Bootstrap 的模态功能。 模态(Modal)是 Bootstrap 提供的一种功能,它可以创建弹出窗口,用户可以在不离开当前页面的情况下查看或...
- Camera Window >>DEMO - Cinematics >>DEMO - Content Fitter >>DEMO - Forward Focus >>DEMO - Geometry Boundaries - Limit Distance >>DEMO - Limit Speed >>DEMO - Numeric Boundaries >>DEMO - Pan ...
Since the API documentation is liberally licensed (just like the rest of Rails), there are some sections of the book that draw from the API documentation. But in practically all of those cases, the ...
rails-dev-box, 面向 Ruby on Rails 核心开发的虚拟机 用于 Ruby on Rails 核心开发的虚拟机简介注意:这个虚拟机不是为 Rails 应用程序开发而设计的,只是为。 这个项目自动设置开发环境,以便在 Ruby on Rails ...
rails-nginx-passenger-ubuntu, 关于如何在 Nginx 8.04服务器上启动和运行和乘客的说明 rails-nginx-passenger-ubuntu我关于用 ubuntu 。Nginx 。乘客和mysql建立 Rails的简单制作服务器的笔记。别名echo"alias ll='...
### 关于《The Rails 4 Way》一书的知识点概览 ...通过以上章节内容的梳理,《The Rails 4 Way》这本书为读者提供了全面且深入的Rails 4框架知识体系,有助于开发者在实践中更好地理解和运用Rails的核心功能和技术点。
在本项目"rails应用--导航栏实例工程"中,我们将探讨如何在Ruby on Rails框架下构建一个实用的导航栏。Rails是一个流行的开源Web应用程序框架,它遵循MVC(模型-视图-控制器)架构模式,使得开发过程更加高效且结构...
"rails-2.1.0-gem"是Rails框架的一个特定版本,即2.1.0的gem包,用于在Ruby环境中安装和管理Rails框架。 Rails的核心理念是“约定优于配置”(Convention over Configuration),这意味着开发者可以遵循一套预设的...
`rails-documentation-2-0-2.chm` 文件详细涵盖了这些概念,包含了关于Rails 2.0.2的API参考、教程和指南。通过仔细阅读和实践,开发者能够深入理解Rails的工作原理,并有效地开发出高效、可维护的Web应用。
标题 "rails-documentation-1-2-1.zip" 暗示这是一份关于 Ruby on Rails 框架的文档,版本为 1.2.1。Ruby 是一种面向对象的编程语言,而 Rails 是一个基于 Ruby 的开源 Web 应用程序框架,遵循 Model-View-...
itamae ssh configuration/roles/rails.rb -u ec2-user -p < port>> -i ~ /.ssh/aws/initialize.pem -h < ip> 服务器规格 如果您想听到密码 ASK_SUDO_PASSWORD=true \ PORT= < port> \ USER= < user> \ KEY_PATH=
- **使用**:在视图文件中通过`<%= render component %>`的方式调用组件。 #### 九、安全性 - **重要性**:确保Web应用的安全对于保护用户数据至关重要。 - **措施**:Rails提供了多种内置的安全特性,如防止跨站...
《The Rails Way》一书由Obie Fernandez撰写,属于Addison-Wesley Professional Ruby系列,该系列致力于为读者提供实用、面向人且深入的信息,帮助他们利用Ruby平台创建动态技术解决方案。这一系列书籍的创立基于一...
### 关于《The Rails 4 Way》的知识点总结 #### 标题:The Rails 4 Way 这本书主要讲述了Ruby on Rails 4版本的核心特性和最佳实践。Ruby on Rails(简称Rails)是一个用Ruby语言编写的开源全栈Web应用框架。本书...
通过对"rails-playlists-源码"的深入学习,开发者不仅可以理解Rails的基础知识,还能掌握如何在实际项目中运用这些知识,构建出功能完备且易于维护的Web应用。阅读源码是提升编程技能的绝佳方式,尤其是对于想要深入...
<strong><%= row.value %></strong> (<%= link_to "remove", :class => nil %>) <% end %> </li> <% end %> </ul> </div> <% end %> <% @results.each do |s| %> <div id="search_result"> <% if s.class....
ActiveRecord模型Rails实验室 目标 手动创建迁移 手动创建模型 建立模型实例方法 建立模型 您可以在spec/models目录中找到此应用程序的测试套件,并使用以下命令运行它们: bundle exec rspec 。 该实验室进行测试以...