Ruby如何使用Mysql2连接操作MySQL
时间:2024-10-26 21:19 文章来源于网友投稿,仅供参考!
| Ruby操作MySQL 使用mysql2连接mysql并操作mysql。 geminstallmysql2连接mysql 建立连接: require'mysql2'conn=Mysql2::Client.new({host:'192.168.200.73',username:'root',password:'P@ssword1!'})接受的连接选项包括: Mysql2::Client.new(:host,:username,:password,:port,:database,:socket='/path/to/mysql.sock',:flags=REMEMBER_OPTIONS|LONG_PASSWORD|LONG_FLAG|TRANSACTIONS|PROTOCOL_41|SECURE_CONNECTION|MULTI_STATEMENTS,:encoding='utf8',:read_timeout=seconds,:write_timeout=seconds,:connect_timeout=seconds,:connect_attrs={:program_name=>$PROGRAM_NAME,...},:reconnect=true/false,:local_infile=true/false,:secure_auth=true/false,:ssl_mode=:disabled/:preferred/:required/:verify_ca/:verify_identity,:default_file='$HOME/.my.cnf',#=>从文件读取连接信息:default_group='my.cfgsection',#=>选择.my.cnf中的section:default_auth='authentication_windows_client',:init_command=>SQL_Statement#=>主要用于设置本次连接时的某些变量)连接建立后就可以操作数据库了,比如执行SQL语句: conn.query('createdatabsemytest')conn.select_db('mytest')#conn.query('usemytest')conn.query('createtabletb(namevarchar(1024),ageint)')conn.query<<-SQLinsertintotbvalues('junmajinlong',23),('woniu',25),('fairy',26)SQL如果测试和mysql的连接是否断开,可执行ping(): conn.ping 如果连接未断开,ping()返回true,如果连接已断开但已启用auto-reconnect,则ping()会尝试依次reconnect,连接成功则返回true,否则报错。如果连接已断开,且未启用auto-reconnect,则报错。 query()查询和结果处理
查询结果可使用each进行迭代,迭代时传递查询到的每一行记录,可使用hash索引的方式(默认以hash类型保存每一行)查询某个字段的内容: conn.query("showdatabases").eachdo|row|pprowend=begin{"Database"=>"information_schema"}{"Database"=>"mysql"}{"Database"=>"mytest"}{"Database"=>"performance_schema"}{"Database"=>"sys"}=endconn.query("select*frommytest.tb").eachdo|row|pprowpprow["name"]end=begin{"name"=>"junmajinlong","age"=>23}"junmajinlong"{"name"=>"woniu","age"=>25}"woniu"{"name"=>"fairy","age"=>26}"fairy"=end可见,查询结果中,每一行数据默认以hash格式保存。 实际上,对于增删改的SQL语句,query()的返回值为nil,对于查询类的语句,其返回值以 conn.query("createtablemytest.t1(idint)")#=>nilres=conn.query("select*frommytest.tb")pres结果: #<Mysql2::Result:0x00007fffe833a230@query_options={:as=>:hash,:async=>false,:cast_booleans=>false,:symbolize_keys=>false,:database_timezone=>:local,:application_timezone=>nil,:cache_rows=>true,:connect_flags=>2148540933,:cast=>true,:default_file=>nil,:default_group=>nil,:host=>"192.168.200.73",:username=>"root",:password=>"P@ssword1!"},@server_flags={:no_good_index_used=>false,:no_index_used=>true,:query_was_slow=>false}>
可在查询时指定这些参数,也可在each迭代时指定这些参数,例如: conn.query("select*frommytest.tb",symbolize_keys:true).eachdo|row|pprowendconn.query("select*frommytest.tb").each(symbolize_keys:true)do|row|pprowend结果: {:name=>"junmajinlong",:age=>23}{:name=>"woniu",:age=>25}{:name=>"fairy",:age=>26}虽然大多数时候使用hash保存每一行数据更方便,但有时候也会想要以数组方式操作每一行数据,例如连接每一个字段的值: sql='select*frommytest.tb'res=conn.query(sql)res.each(as::array)do|row|prow.join(",")end结果: "junmajinlong,23""woniu,25""fairy,26"
#count?Object(also:#size)#each(*args)?Object#fields?Object#free?Object 外, sql='select*frommytest.tb'res=conn.query(sql)res.first#=>{"name"=>"junmajinlong","age"=>23}需注意,所有SQL语句中涉及到的值都是未经转义的,有时候需要也建议在执行它们之前先对它们进行转义。 escaped=conn.escape("gi'thu\"bbe\0r's")results=conn.query("SELECT*FROMusersWHEREgroup='#{escaped}'")查询选项含义以及默认查询选项query()默认的查询选项可以通过 Mysql2::Client.default_query_options=begin{:as=>:hash,:async=>false,:cast_booleans=>false,:symbolize_keys=>false,:database_timezone=>:local,:application_timezone=>nil,:cache_rows=>true,:connect_flags=>2148540933,:cast=>true,:default_file=>nil,:default_group=>nil}=end其中(重要):
Mysql2处理查询结果的流程: Mysql2的MySQL C api从MySQL服务端查询数据,并保存在Ruby的查询结果集(结果集属于C)
Mysql2在需要取得结果集中的数据时(比如each迭代),才从结果集中根据查询选项构建所需行并返回,比如构建hash结构的行,构建数组结构的行,构建hash结构时将key转换为Symbol类型等 默认情况下,从结果集中查询并构建出来的hash行或array行会缓存在Ruby中,使得下次再次请求这一行时(比如再次迭代),可用直接从缓存中取得hash行或array行 比如从MySQL服务端查询了100行数据保存在C的结果集中,第一次以hash方式请求其中4行,这4行hash数据会缓存起来,如果下次再从头开始以hash方式请求15行,则前4行来自于缓存,后11行来自于结果集的临时构建 如果 如果能确保查询的结果集只使用一次,可禁用
修改 Mysql2::Client.default_query_options#=>{:as=>:hash,...}Mysql2::Client.default_query_options.merge!(:as=>:array)#=>{:as=>:array,...}prepare()+execute()除了直接使用query()执行SQL语句查询数据库,也可以使用prepare()方法将字符串准备成一个待执行的SQL语句,其中可以使用 prepare后的语句是一个 res_sql=conn.prepare('select*frommytest.tbwhereage>=?andnamelike?')res=res_sql.execute(20,'%junma%',as::array)res.first处理多结果集有些存储过程中可能包含多个查询结果集,或者有时候会在一行SQL中包含多个select语句而同时返回多个结果集,Mysql2能很好地处理多结果集问题。 要处理多结果集,连接mysql时必须指定一个flag: conn=Mysql2::Client.new({host:"192.168.200.73",username:"root",password:"P@ssword1!",flags:Mysql2::Client::MULTI_STATEMENTS})然后执行多结果集的多个查询语句: res=conn.query('select1;select2;select3')虽然本次query()涉及了多个select语句,Mysql2也已经保存了这三个select的查询结果集(保存在结果集队列中),但本次query()方法的返回值仅是第一个结果集,所以res中保存的是第一个结果集的内容。 res.first#=>{"1"=>1}要获取剩余的结果集,可通过 conn.next_resultres=conn.store_resultres.first#=>{"2"=>2}conn.next_resultres=conn.store_resultres.first#=>{"3"=>3}conn.next_result#=>false所以,可遍历多个结果集: res=conn.query('select1;select2;select3')loopdopres.firstbreakunlessconn.next_resultres=conn.store_resultend#或者pres.firstwhileconn.next_resultres=conn.store_resultpres.firstend输出结果: {"1"=>1}{"2"=>2}{"3"=>3}需注意,开启多行语句(即多结果集)功能后,所查询得到的所有结果集必须已经处理完成(严格来说,是存放结果集的队列已经为空),才能继续执行后续的SQL语句(事实上,经测试,结果集队列未空的情况下执行其它SQL语句会导致直接断开mysql连接)。可使用 #res和res1都只保存第一个结果集#但结果集队列中保留的是select5和select6的结果集res=conn.query('select1;select2;select3')conn.abandon_results!#丢弃所有剩余结果集res1=conn.query('select4;select5;select6')另外,如果多个查询语句中间的某个查询语句报错,它将影响其后面的语句不会执行,所以无法获取后面的结果集。 res=conn.query('select1;select2;selectA;select3')loopdopres.firstbreakunlessconn.next_resultres=conn.store_resultend结果: {"1"=>1}{"2"=>2}Mysql2::Error:Unknowncolumn'A'in'fieldlist'Mysql2的EventMachineMysql2支持EM,可以执行异步的query(),此外,可以指定当query()查询成功或失败时的回调语句块: require'mysql2/em'EM.rundoclient1=Mysql2::EM::Client.newdefer1=client1.query"SELECTsleep(3)asfirst_query"defer1.callbackdo|result|puts"Result:#{result.to_a.inspect}"endclient2=Mysql2::EM::Client.newdefer2=client2.query"SELECTsleep(1)second_query"defer2.callbackdo|result|puts"Result:#{result.to_a.inspect}"endendORM之:Sequel
另一个轻量级的ORM是Sequel,它支持ADO, JDBC, MySQL, Mysql2, ODBC, Oracle, PostgreSQL, SQLite3等等。 例如: require'sequel'#创建数据库实例DB=Sequel.connect(adapter::mysql2,user:'root',password:'P@ssword1!',host:'192.168.200.73',port:3306,database:'mytest')#创建数据集,数据集表示的是一张表或表部分数据#此时不会去查询数据,会推迟到需要数据时才查询dataset=DB[:tb]#迭代表数据dataset.eachdo|row|pprowend#条件查询ppdataset.where(name:'junmajinlong',age:23).firstppdataset.where{name=~"junmajinlong"andage=~23}.first |