日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

ruby 数据sql操作

發(fā)布時(shí)間:2023/12/18 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ruby 数据sql操作 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

ActiveRecord

ActiveRecord 是 Rails 的 ORM 元件,負(fù)責(zé)與資料庫(kù)溝通,讓我們可以用物件導(dǎo)向的語(yǔ)法操作資料庫(kù)。在”打造 CRUD 應(yīng)用程式”一章中提到的對(duì)應(yīng)概念如下:

  • 將資料庫(kù)表格(table) 對(duì)應(yīng)到一個(gè)類別(classe)
  • 類別方法就是操作表格(table)
  • 將資料庫(kù)一列 (row) 對(duì)應(yīng)到一個(gè)物件(object)
  • 物件方法就是操作個(gè)別的資料(row)
  • 將資料庫(kù)欄位(column) 對(duì)應(yīng)到物件的屬性(object attribute)

因此,資料庫(kù)裡面的資料表,我們用一個(gè) Model 類別來(lái)表示,而其中的一筆資料,就是一個(gè) Model 物件。

ActiveRecord 這個(gè)函式庫(kù)實(shí)作了 Martin Fowler 的 Active Record 設(shè)計(jì)模式(Design Pattern)http://martinfowler.com/eaaCatalog/activeRecord.html

ORM 與抽象滲漏法則

ORM (Object-relational mapping ) 是一種對(duì)映設(shè)關(guān)聯(lián)式資料與物件資料的程式技術(shù)。物件導(dǎo)向和從數(shù)學(xué)理論發(fā)展出來(lái)的關(guān)聯(lián)式資料庫(kù),有著顯著的區(qū)別,而 ORM 正是解決這個(gè)不匹配問(wèn)題所產(chǎn)生的工具。它可以讓你使用物件導(dǎo)向語(yǔ)法來(lái)操作關(guān)聯(lián)式資料庫(kù),非常容易使用、撰碼十分有效率,不需要撰寫(xiě)繁瑣的SQL語(yǔ)法,同時(shí) 也增加了程式碼維護(hù)性。

不過(guò),有些熟悉 SQL 語(yǔ)法的程式設(shè)計(jì)師反對(duì)使用這樣的機(jī)制,因?yàn)橹苯幼珜?xiě) SQL 可以確保操作資料庫(kù)的執(zhí)行效率,畢竟有些時(shí)候 ORM 產(chǎn)生出來(lái)的 SQL 效率不是最佳解,而你卻不一定有經(jīng)驗(yàn)?zāi)軌蛞庾R(shí)到什麼時(shí)候需要擔(dān)心或處理這個(gè)問(wèn)題。

知名軟體人 Joel Spolsky (他有兩本中文翻譯書(shū)值得推薦:約耳趣談軟體和約耳續(xù)談軟體,悅知出版) 有個(gè)理論:抽象滲漏法則:所有重大的抽象機(jī)制在某種程式上都是有漏洞的。有非常多程式設(shè)計(jì)其實(shí)都是在建立抽象機(jī)制,C 語(yǔ)言簡(jiǎn)化了組合組言的繁雜、動(dòng)態(tài)語(yǔ)言如 Ruby 簡(jiǎn)化了 C 語(yǔ)言、TCP 協(xié)定簡(jiǎn)化了 IP 通訊協(xié)定,甚至車子的擋風(fēng)玻璃跟雨刷也簡(jiǎn)化了下雨的事實(shí)。

但 是這些抽象機(jī)制或多或少都會(huì)力有未及的地方,用 C 語(yǔ)言撰寫(xiě)的 Linux 核心也包括少量組合語(yǔ)言、部分 Ruby 套件用 C 語(yǔ)言撰寫(xiě)擴(kuò)充來(lái)增加效能、保證訊息會(huì)抵達(dá) TCP 訊息,碰到 IP 封包在路由器上隨機(jī)遺失的時(shí)候,你也只會(huì)覺(jué)得速度很慢、即使有擋風(fēng)玻璃跟雨刷,開(kāi)車還是必須小心路滑。

當(dāng) 某人發(fā)明一套神奇可以大幅提升效率的新程式工具時(shí),就會(huì)聽(tīng)到很多人說(shuō):「應(yīng)該先學(xué)會(huì)如何手動(dòng)進(jìn)行,然後才用這個(gè)神奇的工具來(lái)節(jié)省時(shí)間。」任何抽象機(jī)制都有 漏洞,而唯一能完美處理漏洞的方法,就是只去弄懂該抽象原理以及所隱藏的東西。這是否表示我們應(yīng)該永遠(yuǎn)只應(yīng)該使用比較低階的工具呢?不是這樣的。而是應(yīng)該 依照不同的情境,選擇效益最大的抽象化工具。以商務(wù)邏輯為多的 Web 應(yīng)用程式,選擇動(dòng)態(tài)語(yǔ)言開(kāi)發(fā)就相對(duì)合適,用 C 語(yǔ)言開(kāi)發(fā)固然執(zhí)行效率極高,但是完成相同的功能卻需要極高的人月開(kāi)發(fā)時(shí)數(shù)。如果是作業(yè)系統(tǒng),使用無(wú)法隨意控制記憶體分配的動(dòng)態(tài)語(yǔ)言也顯然不是個(gè)好主意。

能 夠意識(shí)到什麼時(shí)候抽象化工具會(huì)產(chǎn)生滲漏,正是”有純熟經(jīng)驗(yàn)”的程式設(shè)計(jì)師和”新手”設(shè)計(jì)師之間的差別。ORM 雖然替我們節(jié)省了工作的時(shí)間,不過(guò)對(duì)資深的程式設(shè)計(jì)師來(lái)說(shuō),學(xué)習(xí) SQL 的時(shí)間還是省不掉的。這一切都似乎表示,即使我們擁有愈來(lái)愈高階的程式設(shè)計(jì)工具,抽象化也做得愈來(lái)愈好,要成為一個(gè)由高階到低階都純熟的程式設(shè)計(jì)專家是愈 來(lái)愈困難了(也越來(lái)越稀有及寶貴)。

建立 Model

首先,讓我們示範(fàn)如何建立一個(gè) Model:

rails g model Category

這個(gè)指令會(huì)產(chǎn)生幾個(gè)檔案

category.rb
category_test.rb
categories.yml
xxxxxxxx_create_categories.rb

打開(kāi) xxxxxxxx_create_categories.rb 你可以看到資料表的定義,讓我們加上幾個(gè)欄位吧:

class CreateCategories < ActiveRecord::Migration
????def self.up
????????create_table :categories do |t|
??????????t.string :name
??????????t.integer :position
??????????t.timestamps
????????end
??????end

??def self.down
????drop_table :categories
??end
end

接著執(zhí)行以下指令便會(huì)產(chǎn)生出資料庫(kù)資料表

rake db:migrate

db:migrate 指令會(huì)將上述的 Ruby 程式變成以下 SQL 執(zhí)行。

CREATE TABLE categories (
"id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
"name" varchar(255) DEFAULT NULL,
"position" int(4) DEFAULT NULL,
"created_at" datetime DEFAULT NULL,
"updated_at" datetime DEFAULT NULL);????

接著我們打開(kāi) category.rb 你可以看到

class Category < ActiveRecord::Base
end

這是一個(gè)繼承 ActiveRecord::Base 的 Category 類別。

我們?cè)趯W(xué)習(xí) Ruby 的時(shí)候提過(guò) irb 這個(gè)互動(dòng)工具,而 Rails 也提供了特殊的 irb 介面叫做 console,讓我們可以直接與 Rails 程式互動(dòng):

rails console (可以簡(jiǎn)寫(xiě)成 rails c)

透過(guò) console,我們可以輕易的練習(xí)操作 ActiveRecord。

觀看 Log

不像 rails server 可以直接看到 log,在 Rails 主控臺(tái)下必須透過(guò)觀察 log 檔案。我們可以透過(guò) log 觀察到 Rails 產(chǎn)生出來(lái)的 SQL 長(zhǎng)的如何。

tail -f log/development.log

Windows 上沒(méi)有這個(gè)指令,可以安裝?Tail for Win32?這個(gè)工具來(lái)即時(shí)觀察 log 檔案。或是安裝?GNU utilities for Win32?來(lái)獲得 tail 指令。

基礎(chǔ)操作

如何新增

ActiveRecord提供了四種API,分別是save、save!、create和create!:

a = Category.new( :name => 'Ruby', :position => 1 )
a.save

b = Category.new( :name => 'Perl', :position => 2 )
b.save!
????????
Category.create( :name => 'Python', :position => 3 )
c = Category.create!( :name => 'PHP', :position => 4 )

其中create和create!就等於new完就save和save!,有無(wú)驚嘆號(hào)的差別在於validate資料驗(yàn)證不正確的動(dòng)作,無(wú)驚嘆號(hào)版本會(huì)回傳布林值(true或false),有驚嘆號(hào)版本則是驗(yàn)證錯(cuò)誤會(huì)丟出例外。

何 時(shí)使用驚嘆號(hào)版本呢?save和create通常用在會(huì)處理回傳布林值(true/false)的情況下(例如在 controller 裡面根據(jù)成功失敗決定 render 或 redirect),否則在預(yù)期應(yīng)該會(huì)儲(chǔ)存成功的情況下,請(qǐng)用 save!或create! 來(lái)處理,這樣一旦碰到儲(chǔ)存失敗的情形,才好追蹤 bug。

透過(guò) :valiate => false 可以略過(guò)驗(yàn)證

c.save( :validate => false )

在 Rails3 之前的版本是 user.save(false)

如何查詢

ActiveRecord 使用了 Arel 技術(shù)來(lái)實(shí)作查詢功能,你可以自由組合 where、limit、select、order 等條件。

Arel 是 relational algebra” library。但根據(jù) 2.0 實(shí)作者 tenderlove 的說(shuō)法,也可以說(shuō)是一種 SQL compiler。 http://engineering.attinteractive.com/2010/12/architecture-of-arel-2-0/

first, last 和 all

這三個(gè)方法可以分別拿出資料庫(kù)中的第一筆、最後一筆及全部的資料:

c1 = Category.first
c2 = Category.last
categories = Category.all # 這會(huì)是一個(gè)陣列

如果資料量較多,請(qǐng)不要在正式上線環(huán)境中執(zhí)行.all 把所有資料拿出來(lái),這樣會(huì)耗費(fèi)非常多的記憶體。請(qǐng)用分頁(yè)或縮小查詢範(fàn)圍。

find

已知資料的主鍵 ID 的值的話,可以使用 find 方法:

c3 = Category.find(1)
c4 = Category.find(2)

find 也可以接受陣列參數(shù),這樣就會(huì)一次找尋多個(gè)並回傳陣列:

arr = Category.find([1,2])
# 或是
arr = Category.find(1,2)

如果找不到資料的話,會(huì)丟 ActiveRecord::RecordNotFound 例外。如果是 find_by_id 就不會(huì)丟出例外,而是回傳 nil。

find_by_* 和 find_all_by_*

find_by_* 和 find_all_by_* 是 Rails 的動(dòng)態(tài)方法,可以自由用 and 組合,例如:

c5 = Category.find_by_name('Ruby')
c6 = Category.find_by_name_and_position('Ruby', 1)
c7 = Category.find_all_by_position(2)
find_by_sql

如果需要手動(dòng)撰寫(xiě) SQL,可以使用 find_by_sql,例如:

c8 = Category.find_by_sql("select * from categories")

不過(guò)在絕大多數(shù)的情況,是不需要手動(dòng)寫(xiě) SQL 的。

where 查詢條件

where 可以非常彈性的組合出 SQL 查詢,例如:

c9 = Category.where( :name => 'Ruby', :position => 1 )
c10 = Category.where( [ "name = ? or position = ?", 'Ruby', 2] )

其中參數(shù)有兩種寫(xiě)法,一種是 Hash,另一種是 Array。前者的寫(xiě)法雖然比較簡(jiǎn)潔,但是就沒(méi)辦法寫(xiě)出 or 的查詢。注意到不要使用字串寫(xiě)法,例如

Category.where("name = #{params[:name]}") # 請(qǐng)不要這樣寫(xiě)

這是因?yàn)樽执畬?xiě)法會(huì)有 SQL injection 的安全性問(wèn)題,請(qǐng)改用陣列寫(xiě)法。

另外,where 是 lazy loading,也就是直到真的需要取值的時(shí)候,才會(huì)跟資料庫(kù)拿資料。如果需要立即觸發(fā),可以接著使用 .all, .first, .last,例如

c11 = Category.where( :name => 'Ruby', :position => 1 ).all

limit

limit 可以限制筆數(shù)

c = Category.limit(5).all
c.size # 5

order

order 可以設(shè)定排序條件

Category.order("position")
Category.order("position DESC")
Category.order("position DESC, name ASC")

如果要消去order條件,可以用reorder:

Category.order("position").reorder("name") # 改用 name 排序
Category.order("position").reorder(nil) # 取消所有排序

offset

offset 可以設(shè)定忽略前幾筆不取出,通常用於資料分頁(yè):

c = Category.limit(2)
c.first.id # 1
Category.limit(2).offset(3)
c.first.id # 4

select

預(yù)設(shè)的 SQL 查詢會(huì)取出資料的所有欄位,有時(shí)候你可能不需要所有資料,為了效能我們可以只取出其中特定欄位:

Category.select("id, name")

例如欄位中有 Binary 資料時(shí),你不會(huì)希望每次都讀取出龐大的 Binary 資料佔(zhàn)用記憶體,而只希望在使用者要下載的時(shí)候才讀取出來(lái)。

joins

針對(duì)Model中的belongs_to和has_many關(guān)連,可以使用joins,也就是INNER JOIN

Category.joins(:events)
# SELECT categories.* FROM categories INNER JOIN events ON events.category_id = categories.id

可以一次關(guān)連多個(gè):

Post.joins(:category, :comments)

不過(guò)這樣抓出來(lái)的category物件是沒(méi)有event物件的,如果需要一次載入出來(lái),會(huì)使用includes。joins主要的用途是條件:

Category.joins(:events).where("events.name is NOT NULL")

也可以直接給SQL字串:

Client.joins('LEFT OUTER JOIN addresses ON addresses.client_id = clients.id')
# SELECT clients.* FROM clients LEFT OUTER JOIN addresses ON addresses.client_id = clients.id

includes

includes可以預(yù)先將關(guān)連的資料讀取出來(lái),避免N+1問(wèn)題(見(jiàn)效能一章)

Event.includes(:category)
# SELECT * FROM events
# SELECT * FROM categories WHERE categories.id IN (1,2,3...)

同理,也可以一次載入多個(gè)關(guān)連:

Post.includes(:category, :comments)

includes方法也可以加上條件:

Event.includes(:category).where( :category => { :position => 1 } )
# 或 Event.includes(:category).where( "categories.position = 1" )

group

(TODO)

lock

(TODO)

readonly

(TODO)

from

(TODO)

having

串接寫(xiě)法

以上的 where, order , limit, offset, joins, select 等等,都可以自由串接起來(lái)組合出最終的 SQL 條件:

c12 = Category.where( :name => 'Ruby' ).order("id desc").limit(3)

find_each 批次處理

如果資料量很大,但是又需要全部拿出來(lái)處理,可以使用 find_each 批次處理

Category.where("position > 1").find_each do |category|
????category.do_some_thing
end

預(yù)設(shè)會(huì)批次撈 1000 筆,如果需要設(shè)定可以加上 :batch_size 參數(shù)。

重新載入

如果已經(jīng)讀取的 AR 資料,需要重新載入,可以用 reload 方法:

p = Category.first
p.reload

如何刪除

一種是先抓到該物件,然後刪除:

c12 = Category.first
c12.destroy

另一種是直接對(duì)類別呼叫刪除,傳入 ID 或條件:

Category.delete(2)
Category.delete_all(conditions = nil)
Category.destroy_all(conditions = nil)

delete 不會(huì)有 callback 回呼,destroy 有 callback 回呼。什麼是回呼詳見(jiàn)下一章。

統(tǒng)計(jì)方法

Category.count
Category.average(:position)
Category.maximum(:position)
Category.sum(:position)

其中我們可以利用上述的 where 條件縮小範(fàn)圍,例如:

Category.where( :name => "Ruby").count

如何更新

c13 = Category.first
c13.update_attributes(attributes)
c13.update_attributes!(attributes)
c13.update_attribute(attribute_name, value)

注意 update_attribute 會(huì)略過(guò) validation 資料驗(yàn)證 注意 mass assign 安全性問(wèn)題,可以透過(guò) attr_protected 或 attr_accessor 設(shè)定,詳見(jiàn)安全性一章。

Scopes 作用域

Model Scopes是一項(xiàng)非常酷的功能,它可以將常用的查詢條件宣告起來(lái),讓程式變得乾淨(jìng)易讀,更厲害的是可以串接使用。例如,我們編輯app/models/event.rb,加上兩個(gè)Scopes:

class Event < ActiveRecord::Base
????scope :public, where( :is_public => true )
????scope :recent_three_days, where(["created_at > ? ", Time.now - 3.days ])
end

Event.create( :name => "public event", :is_public => true )
Event.create( :name => "private event", :is_public => false )
Event.create( :name => "private event", :is_public => true )

Event.public
Event.public.recent_three_days

串接的順序沒(méi)有影響

接著,我們可以設(shè)定一個(gè)預(yù)設(shè)的Scope,通常會(huì)拿來(lái)設(shè)定排序:

class Event < ActiveRecord::Base????
????default_scope order('id DESC')????????
end

unscoped方法可以暫時(shí)取消預(yù)設(shè)的default_scope:

Event.unscoped do
????Event.all
????# SELECT * FROM events
end

最後,Scope也可以接受參數(shù),例如:

class Event < ActiveRecord::Base
????scope :recent, lambda{ |date| where(["created_at > ? ", date ]) }
????# 或 scope :recent, Proc.new{ |t| where(["created_at > ? ", t ]) }
end

Event.recent( Time.now - 7.days )

不過(guò),筆者會(huì)推薦上述這種帶有參數(shù)的Scope,改成如下的類別方法,可以比較明確看清楚參數(shù)是什麼,特別是你想給預(yù)設(shè)值的時(shí)候:

class Event < ActiveRecord::Base
????def recent(t=Time.now)
????????where(["created_at > ? ", t ])
????end
end

Event.recent( Time.now - 7.days )

這樣的效果是一樣的,也是一樣可以和其他Scope做串接。

scoped方法可以將Model轉(zhuǎn)成可以串接的形式,方便依照參數(shù)組合出不同查詢,例如

fruits = Fruit.scoped
fruits = fruits.where(:colour => 'red') if options[:red_only]
fruits = fruits.limit(10) if limited?

自定 attribute 與資料庫(kù)互動(dòng)

(TODO)

使用 attr_accessor

可以使用 read_attribute 和 write_attribute 這兩個(gè)比較底層的 API

轉(zhuǎn)載于:https://www.cnblogs.com/wangyuyu/p/3242611.html

總結(jié)

以上是生活随笔為你收集整理的ruby 数据sql操作的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。