ruby 数据sql操作

ActiveRecord

ActiveRecord 是 Rails 的 ORM 元件,負責與資料庫溝通,讓我們可以用物件導向的語法操作資料庫。在”打造 CRUD 應用程式”一章中提到的對應概念如下:

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

因此,資料庫裡面的資料表,我們用一個 Model 類別來表示,而其中的一筆資料,就是一個 Model 物件。

ActiveRecord 這個函式庫實作了 Martin Fowler 的 Active Record 設計模式(Design Pattern)http://martinfowler.com/eaaCatalog/activeRecord.html

ORM 與抽象滲漏法則

ORM (Object-relational mapping ) 是一種對映設關聯式資料與物件資料的程式技術。物件導向和從數學理論發展出來的關聯式資料庫,有著顯著的區別,而 ORM 正是解決這個不匹配問題所產生的工具。它可以讓你使用物件導向語法來操作關聯式資料庫,非常容易使用、撰碼十分有效率,不需要撰寫繁瑣的SQL語法,同時 也增加了程式碼維護性。

不過,有些熟悉 SQL 語法的程式設計師反對使用這樣的機制,因為直接撰寫 SQL 可以確保操作資料庫的執行效率,畢竟有些時候 ORM 產生出來的 SQL 效率不是最佳解,而你卻不一定有經驗能夠意識到什麼時候需要擔心或處理這個問題。

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

但 是這些抽象機制或多或少都會力有未及的地方,用 C 語言撰寫的 Linux 核心也包括少量組合語言、部分 Ruby 套件用 C 語言撰寫擴充來增加效能、保證訊息會抵達 TCP 訊息,碰到 IP 封包在路由器上隨機遺失的時候,你也只會覺得速度很慢、即使有擋風玻璃跟雨刷,開車還是必須小心路滑。

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

能 夠意識到什麼時候抽象化工具會產生滲漏,正是”有純熟經驗”的程式設計師和”新手”設計師之間的差別。ORM 雖然替我們節省了工作的時間,不過對資深的程式設計師來說,學習 SQL 的時間還是省不掉的。這一切都似乎表示,即使我們擁有愈來愈高階的程式設計工具,抽象化也做得愈來愈好,要成為一個由高階到低階都純熟的程式設計專家是愈 來愈困難了(也越來越稀有及寶貴)。

建立 Model

首先,讓我們示範如何建立一個 Model:

rails g model Category

這個指令會產生幾個檔案

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

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

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

接著執行以下指令便會產生出資料庫資料表

rake db:migrate

db:migrate 指令會將上述的 Ruby 程式變成以下 SQL 執行。

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);    

接著我們打開 category.rb 你可以看到

class Category < ActiveRecord::Base
end

這是一個繼承 ActiveRecord::Base 的 Category 類別。

我們在學習 Ruby 的時候提過 irb 這個互動工具,而 Rails 也提供了特殊的 irb 介面叫做 console,讓我們可以直接與 Rails 程式互動:

rails console (可以簡寫成 rails c)

透過 console,我們可以輕易的練習操作 ActiveRecord。

觀看 Log

不像 rails server 可以直接看到 log,在 Rails 主控台下必須透過觀察 log 檔案。我們可以透過 log 觀察到 Rails 產生出來的 SQL 長的如何。

tail -f log/development.log

Windows 上沒有這個指令,可以安裝 Tail for Win32 這個工具來即時觀察 log 檔案。或是安裝 GNU utilities for Win32 來獲得 tail 指令。

基礎操作

如何新增

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 )

其中createcreate!就等於new完就savesave!,有無驚嘆號的差別在於validate資料驗證不正確的動作,無驚嘆號版本會回傳布林值(true或false),有驚嘆號版本則是驗證錯誤會丟出例外。

何 時使用驚嘆號版本呢?save和create通常用在會處理回傳布林值(true/false)的情況下(例如在 controller 裡面根據成功失敗決定 render 或 redirect),否則在預期應該會儲存成功的情況下,請用 save!或create! 來處理,這樣一旦碰到儲存失敗的情形,才好追蹤 bug。

透過 :valiate => false 可以略過驗證

c.save( :validate => false )

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

如何查詢

ActiveRecord 使用了 Arel 技術來實作查詢功能,你可以自由組合 where、limit、select、order 等條件。

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

first, last 和 all

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

c1 = Category.first
c2 = Category.last
categories = Category.all # 這會是一個陣列

如果資料量較多,請不要在正式上線環境中執行.all 把所有資料拿出來,這樣會耗費非常多的記憶體。請用分頁或縮小查詢範圍。

find

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

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

find 也可以接受陣列參數,這樣就會一次找尋多個並回傳陣列:

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

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

find_by_* 和 find_all_by_*

find_by_* 和 find_all_by_* 是 Rails 的動態方法,可以自由用 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

如果需要手動撰寫 SQL,可以使用 find_by_sql,例如:

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

不過在絕大多數的情況,是不需要手動寫 SQL 的。

where 查詢條件

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

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

其中參數有兩種寫法,一種是 Hash,另一種是 Array。前者的寫法雖然比較簡潔,但是就沒辦法寫出 or 的查詢。注意到不要使用字串寫法,例如

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

這是因為字串寫法會有 SQL injection 的安全性問題,請改用陣列寫法。

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

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

limit

limit 可以限制筆數

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

order

order 可以設定排序條件

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 可以設定忽略前幾筆不取出,通常用於資料分頁:

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

select

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

Category.select("id, name")

例如欄位中有 Binary 資料時,你不會希望每次都讀取出龐大的 Binary 資料佔用記憶體,而只希望在使用者要下載的時候才讀取出來。

joins

針對Model中的belongs_tohas_many關連,可以使用joins,也就是INNER JOIN

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

可以一次關連多個:

Post.joins(:category, :comments)

不過這樣抓出來的category物件是沒有event物件的,如果需要一次載入出來,會使用includesjoins主要的用途是條件:

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可以預先將關連的資料讀取出來,避免N+1問題(見效能一章)

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

同理,也可以一次載入多個關連:

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

串接寫法

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

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

find_each 批次處理

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

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

預設會批次撈 1000 筆,如果需要設定可以加上 :batch_size 參數。

重新載入

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

p = Category.first
p.reload

如何刪除

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

c12 = Category.first
c12.destroy

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

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

delete 不會有 callback 回呼,destroy 有 callback 回呼。什麼是回呼詳見下一章。

統計方法

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

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

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

如何更新

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

注意 update_attribute 會略過 validation 資料驗證 注意 mass assign 安全性問題,可以透過 attr_protected 或 attr_accessor 設定,詳見安全性一章。

Scopes 作用域

Model Scopes是一項非常酷的功能,它可以將常用的查詢條件宣告起來,讓程式變得乾淨易讀,更厲害的是可以串接使用。例如,我們編輯app/models/event.rb,加上兩個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

串接的順序沒有影響

接著,我們可以設定一個預設的Scope,通常會拿來設定排序:

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

unscoped方法可以暫時取消預設的default_scope

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

最後,Scope也可以接受參數,例如:

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 )

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

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

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

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

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

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

自定 attribute 與資料庫互動

(TODO)

使用 attr_accessor

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

转载于:https://www.cnblogs.com/wangyuyu/p/3242611.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/460866.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android的按钮单击事件及监听器的实现方式

2019独角兽企业重金招聘Python工程师标准>>> 第一种&#xff1a;匿名内部类作为事件监听器类 大部分时候&#xff0c;事件处理器都没有什么利用价值&#xff08;可利用代码通常都被抽象成了业务逻辑方法&#xff09;&#xff0c;因此大部分事件监听器只是临时使用一…

Sublime text在Linux下的安装与配置

以下内容源于网络资源的整理&#xff0c;如有侵权请告知删除。文章内容主要整理源&#xff1a;C语言中文网&#xff1a;C语言程序设计门户网站(入门教程、编程软件)。 一、安装Sublime text 安装方法有两种&#xff1a;利用软件包管理工具安装&#xff0c;利用下载好的软件包进…

计算机统考分数短信显示合格,今年起全省八年级网考信息技术 成绩不合格不能升高中...

4月11日&#xff0c;省教育厅正式公布我省初中信息技术学业水平考试实施办法&#xff0c;明确从2019年起全面实施初中信息技术学业水平考试&#xff0c;考试对象为八年级(初二)学生&#xff0c;考试时间为每年5月下旬。今年首次参加信息技术学业水平考试的学生为2017年秋季入学…

在Spring中使用JTA事务管理

2019独角兽企业重金招聘Python工程师标准>>> Spring 通过AOP技术可以让我们在脱离EJB的情况下享受声明式事务的丰盛大餐&#xff0c;脱离Java EE应用服务器使用声明式事务的道路已经畅通无阻。但是很大部分人都还认为脱离Java EE应用服务器就无法使用JTA事务&#x…

Window7无法访问 Window server 2008 R2文件服务器的共享

最近碰到奇怪的问题&#xff0c;原来的R2文件服务器一直都正常&#xff0c;突然win7系统不能访问此服务器的共享了&#xff0c;Ping和远程都可以&#xff0c;而且XP系统也可以访问其共享&#xff0c;就是Win7不行&#xff0c;表现为&#xff1a;按IP访问好久没反应&#xff0c;…

第一季7:海思的根文件系统的概览与制作

一、根文件系统理论 关于根文件系统的原理&#xff0c;可以参看以下博客。 根文件系统的原理 使用BusyBox制作根文件系统的理论分析 二、海思的根文件系统 1、海思的根文件系统体现在Hi3518E_SDK_V1.0.3.0\package\rootfs_uclibc目录。 而根文件系统大部分工作由etc/init.d/…

破坏计算机系统既遂的标准,破坏计算机信息系统罪的量刑标准是什么

只有当我们知道了破坏计算机系统罪的定义我们才知道这个罪有多严重&#xff0c;如果触犯会受到怎样的处罚。所以破坏计算机信息系统罪实际意义是&#xff1a;某些人通过对计算机信息系统中正储存的数据&#xff0c;正在处理的数据以及正在传输的数据和针对相关的应用程序进行恶…

关于shell脚本编程一些有用资源的小结

系统维护管理过程中&#xff0c;编写一些能减轻管理负担的shell脚本是个明智的做法&#xff0c;一些例程性的事务&#xff0c;shell脚本会比手动操作高效的多。我有时也要编写一些&#xff0c;总结了一些学习及参考的shell资料&#xff0c;实用好用为主&#xff0c;大家看看有没…

五.几何对象和空间参考

几何对象是ArcGIS Engine中最基本的也是最常用的对象&#xff0c;我们所说的空间对象&#xff08;点&#xff0c;线&#xff0c;面&#xff09;都是几何对象&#xff0c;我们在删除&#xff0c;创建和进行地理分析的时候&#xff0c;就是处理一个包含几个对象的矢量图形。 Geom…

第一季8:完整版(即包含mpp)根文件系统的制作

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 一、概述 mpp是海思编写的与视频编解码有关的驱动、库等内容。我们需要部署这些内容&#xff0c;也就是把这些内容放在合适的目录位置。 二、mpp的目录结构 mpp目录位于Hi3518E_SDK_V1.0.3.0\pack…

计算机三级会保研加分吗,366所高校有保研资格,除了对成绩有要求外,还有哪些要求?...

文&#xff5c;冷丝栏目&#xff5c;考研录取我国本科院校有1000余所&#xff0c;具有保研资格的高校有366所&#xff0c;这些高校也是在不同年份按照不同批次获得保研资格。(本文文末附录全部高校名单)推免制度最初的目的上为了提高招生工作的质量&#xff0c;并且加大培养拔尖…

包装设计中文字字体的logo设计要注意什么

包装设计中文字字体的logo设计要注意什么 设计字体的目的&#xff0c;是要使文字既具有充分传达信息的功能&#xff0c;又与产品形式、产品功能&#xff1b;人们的审美观念达到和谐和统一。一般可根据以下几个原则进行设计。 (1)要符合包装装潢总体设计要求 包装装潢是造型、构…

每天一个小算法(Shell Sort1)

希尔排序是1959 年由D.L.Shell 提出来的&#xff0c;相对直接排序有较大的改进。希尔排序又叫缩小增量排序 基本思想&#xff1a; 先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序&#xff0c;待整个序列中的记录“基本有序”时&#xff0c;再对全体记录进行依…

第一季8:sample_venc.c的编译和测试

注意&#xff0c;以下内容基于前面完整版的根文件系统&#xff0c;因此需要先完成前面的步骤。 1、明确sample文件夹的位置 海思SDK有很多sample&#xff0c;以方便开发人员的参阅。sample文件夹位于/package/mpp/目录下。 其中/package/mpp/sample/venc目录完成了视频的采集以…

计算机电缆 耐火,耐火计算机电缆ZR-NH-DJVVP

耐火计算机电缆ZR-NH-DJVVP低烟无卤阻燃计算机电缆用途&#xff1a;本电缆具有低压电容和低电感&#xff0c;并具有良好屏蔽性能和抗干扰性能&#xff0c;因而防爆性能优于一般计算机电缆和控制电缆&#xff0e;它适用于有防爆要求场合的集散系统和自动化检测控制等要求低烟无卤…

HashMap HashTable ConcurrentHashMap

1. Hashtable 和 HashMap&#xff08;1&#xff09;区别&#xff0c;这两个类主要有以下几方面的不同&#xff1a;Hashtable和HashMap都实现了Map接口&#xff0c;但是Hashtable的实现是基于Dictionary抽象类。 在HashMap中&#xff0c;null可以作为键&#xff0c;这样的键只有…

Linux 安装Resin4.0.40

一、Resin简介Resin官网地址&#xff1a;http://caucho.com/ Resin源码包下载地址&#xff1a;http://caucho.com/products/resin/downloadResin是CAUCHO公司的产品&#xff0c;是一个非常流行的支持servlets和jsp的引擎&#xff0c;速度非常快。Resin本身包含了一个支持HTTP/1…

int main(int argc,char* argv[])详解

int main(int argc,char* argv[])也可以写成int main(int argc,char** argv)。 argc表示程序运行时发送给main函数的命令行参数的个数&#xff08;包括可执行程序以及传参&#xff09;。 argv[]是字符指针数组&#xff0c;它的每个元素都是字符指针&#xff0c;指向命令行中每个…

计算机教师研修计划书,教师信息技术个人研修计划书

《教师信息技术个人研修计划书》由会员分享&#xff0c;可在线阅读&#xff0c;更多相关《教师信息技术个人研修计划书(6页珍藏版)》请在人人文库网上搜索。1、教师信息技术个人研修计划书 教师信息技术个人研修计划书 通过专家教授的讲解引领&#xff0c;不断更新自己的教育观…

java php 等,路径 上级路径,上上级路径表示方法

如何表示上级目录 ../表示源文件所在目录的上一级目录&#xff0c;../../表示源文件所在目录的上上级目录&#xff0c;以此类推。 ../表示源文件所在目录的上一级目录&#xff0c;../../表示源文件所在目录的上上级目录&#xff0c;以此类推。 假设info.html路径是&#xff1a;…