jdbc-helper 0.5.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +251 -0
- data/lib/jdbc-helper.rb +1 -10
- data/lib/jdbc-helper/connection.rb +347 -351
- data/lib/jdbc-helper/connection/callable_statement.rb +56 -56
- data/lib/jdbc-helper/connection/parameterized_statement.rb +57 -46
- data/lib/jdbc-helper/connection/prepared_statement.rb +88 -88
- data/lib/jdbc-helper/connection/result_set_enumerator.rb +102 -91
- data/lib/jdbc-helper/connection/row.rb +106 -115
- data/lib/jdbc-helper/connection/statement_pool.rb +44 -44
- data/lib/jdbc-helper/connection/type_map.rb +41 -66
- data/lib/jdbc-helper/connector.rb +10 -10
- data/lib/jdbc-helper/connector/mysql_connector.rb +24 -24
- data/lib/jdbc-helper/connector/oracle_connector.rb +33 -32
- data/lib/jdbc-helper/constants.rb +20 -17
- data/lib/jdbc-helper/sql.rb +168 -175
- data/lib/jdbc-helper/wrapper/function_wrapper.rb +12 -12
- data/lib/jdbc-helper/wrapper/object_wrapper.rb +17 -17
- data/lib/jdbc-helper/wrapper/procedure_wrapper.rb +120 -123
- data/lib/jdbc-helper/wrapper/sequence_wrapper.rb +43 -43
- data/lib/jdbc-helper/wrapper/table_wrapper.rb +172 -169
- data/test/helper.rb +2 -10
- data/test/performance.rb +141 -0
- data/test/test_connection.rb +443 -389
- data/test/test_connectors.rb +47 -47
- data/test/test_object_wrapper.rb +541 -432
- data/test/test_sql.rb +143 -135
- metadata +119 -123
- data/README.rdoc +0 -223
- data/test/test_performance.rb +0 -138
data/README.rdoc
DELETED
@@ -1,223 +0,0 @@
|
|
1
|
-
_ _ _ _ _
|
2
|
-
(_) | | | | | | |
|
3
|
-
_ __| | |__ ___ ______| |__ ___| |_ __ ___ _ __
|
4
|
-
| |/ _` | '_ \ / __|______| '_ \ / _ \ | '_ \ / _ \ '__|
|
5
|
-
| | (_| | |_) | (__ | | | | __/ | |_) | __/ |
|
6
|
-
| |\__,_|_.__/ \___| |_| |_|\___|_| .__/ \___|_|
|
7
|
-
_/ | | |
|
8
|
-
|__/ |_|
|
9
|
-
|
10
|
-
= jdbc-helper
|
11
|
-
|
12
|
-
A JDBC helper for Ruby/Database developers.
|
13
|
-
JDBCHelper::Connection object wraps around a JDBC connection and provides much nicer interface to
|
14
|
-
crucial database operations from primitive selects and updates to more complex ones involving
|
15
|
-
batch updates, prepared statements and transactions.
|
16
|
-
As the name implies, this gem only works on JRuby.
|
17
|
-
|
18
|
-
== Installation
|
19
|
-
=== Install gem
|
20
|
-
gem install jdbc-helper
|
21
|
-
|
22
|
-
=== Setting up CLASSPATH
|
23
|
-
Add the appropriate JDBC drivers to the CLASSPATH.
|
24
|
-
export CLASSPATH=$CLASSPATH:~/lib/mysql-connector-java-5.1.16-bin.jar:~/lib/ojdbc6.jar
|
25
|
-
|
26
|
-
=== In Ruby
|
27
|
-
require 'jdbc-helper'
|
28
|
-
|
29
|
-
== Examples
|
30
|
-
=== Connecting to a database
|
31
|
-
|
32
|
-
# :driver and :url must be given
|
33
|
-
conn = JDBCHelper::Connection.new(
|
34
|
-
:driver => 'com.mysql.jdbc.Driver',
|
35
|
-
:url => 'jdbc:mysql://localhost/test')
|
36
|
-
conn.close
|
37
|
-
|
38
|
-
|
39
|
-
# Optional :user and :password
|
40
|
-
conn = JDBCHelper::Connection.new(
|
41
|
-
:driver => 'com.mysql.jdbc.Driver',
|
42
|
-
:url => 'jdbc:mysql://localhost/test',
|
43
|
-
:user => 'mysql',
|
44
|
-
:password => '')
|
45
|
-
conn.close
|
46
|
-
|
47
|
-
|
48
|
-
# MySQL shortcut connector
|
49
|
-
conn = JDBCHelper::MySQLConnector.connect('localhost', 'mysql', '', 'test')
|
50
|
-
conn.close
|
51
|
-
|
52
|
-
# Oracle shortcut connector
|
53
|
-
conn = JDBCHelper::OracleConnector.connect(host, user, password, service_name)
|
54
|
-
conn.close
|
55
|
-
|
56
|
-
=== Querying database table
|
57
|
-
|
58
|
-
conn.query("SELECT a, b, c FROM T") do |row|
|
59
|
-
row.labels
|
60
|
-
row.rownum
|
61
|
-
|
62
|
-
row.a, row.b, row.c # Dot-notation
|
63
|
-
row[0], row[1], row[2] # Numeric index
|
64
|
-
row['a'], row['b'], row['c'] # String index. Case-insensitive.
|
65
|
-
row[:a], row[:b], row[:c] # Symbol index. Case-insensitive.
|
66
|
-
|
67
|
-
row[0..-1] # Range index. Returns an array of values.
|
68
|
-
row[0, 3] # Offset and length. Returns an array of values.
|
69
|
-
end
|
70
|
-
|
71
|
-
# Returns an array of rows when block is not given
|
72
|
-
rows = conn.query("SELECT b FROM T")
|
73
|
-
uniq_rows = rows.uniq
|
74
|
-
|
75
|
-
# You can even nest queries
|
76
|
-
conn.query("SELECT a FROM T") do |row1|
|
77
|
-
conn.query("SELECT * FROM T_#{row1.a}") do |row2|
|
78
|
-
# ...
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
# `enumerate' method returns an Enumerable object if block is not given.
|
83
|
-
# When the result set of the query is expected to be large and you wish to
|
84
|
-
# chain enumerators, `enumerate' is much preferred over `query'. (which returns the
|
85
|
-
# array of the entire rows)
|
86
|
-
conn.enumerate("SELECT * FROM LARGE_T").each_slice(1000) do |slice|
|
87
|
-
slice.each do | row |
|
88
|
-
# ...
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
=== Updating database table
|
93
|
-
del_count = conn.update("DELETE FROM T")
|
94
|
-
|
95
|
-
=== Transaction
|
96
|
-
committed = conn.transaction do |tx|
|
97
|
-
# ...
|
98
|
-
# Transaction logic here
|
99
|
-
# ...
|
100
|
-
|
101
|
-
if success
|
102
|
-
tx.commit
|
103
|
-
else
|
104
|
-
tx.rollback
|
105
|
-
end
|
106
|
-
# You never reach here.
|
107
|
-
end
|
108
|
-
|
109
|
-
=== Using batch interface
|
110
|
-
conn.add_batch("DELETE FROM T");
|
111
|
-
conn.execute_batch
|
112
|
-
conn.add_batch("DELETE FROM T");
|
113
|
-
conn.clear_batch
|
114
|
-
|
115
|
-
=== Using prepared statements
|
116
|
-
p_sel = conn.prepare("SELECT * FROM T WHERE b = ? and c = ?")
|
117
|
-
p_sel.query(100, 200) do |row|
|
118
|
-
p row
|
119
|
-
end
|
120
|
-
p_sel.close
|
121
|
-
|
122
|
-
p_upd = conn.prepare("UPDATE T SET a = ? WHERE b = ?")
|
123
|
-
count = 0
|
124
|
-
100.times do |i|
|
125
|
-
count += p_upd.update('updated a', i)
|
126
|
-
end
|
127
|
-
|
128
|
-
p_upd.add_batch('pstmt + batch', 10)
|
129
|
-
p_upd.add_batch('pstmt + batch', 20)
|
130
|
-
p_upd.add_batch('pstmt + batch', 30)
|
131
|
-
p_upd.execute_batch
|
132
|
-
p_upd.close
|
133
|
-
|
134
|
-
=== Using table wrappers (since 0.2.0)
|
135
|
-
# For more complex examples, refer to test/test_object_wrapper.rb
|
136
|
-
|
137
|
-
# Creates a table wrapper
|
138
|
-
table = conn.table('test.data')
|
139
|
-
|
140
|
-
# Counting the records in the table
|
141
|
-
table.count
|
142
|
-
table.count(:a => 10)
|
143
|
-
table.where(:a => 10).count
|
144
|
-
|
145
|
-
table.empty?
|
146
|
-
table.where(:a => 10).empty?
|
147
|
-
|
148
|
-
# Selects the table by combining select, where, and order methods
|
149
|
-
table.select('a apple', :b).where(:c => (1..10)).order('b desc', 'a asc') do |row|
|
150
|
-
puts row.apple
|
151
|
-
end
|
152
|
-
|
153
|
-
# Build select SQL
|
154
|
-
sql = table.select('a apple', :b).where(:c => (1..10)).order('b desc', 'a asc').sql
|
155
|
-
|
156
|
-
# Updates with conditions
|
157
|
-
table.update(:a => 'hello', :b => JDBCHelper::SQL('now()'), :where => { :c => 3 })
|
158
|
-
# Or equivalently,
|
159
|
-
table.where(:c => 3).update(:a => 'hello', :b => JDBCHelper::SQL('now()'))
|
160
|
-
|
161
|
-
# Insert into the table
|
162
|
-
table.insert(:a => 10, :b => 20, :c => JDBCHelper::SQL('10 + 20'))
|
163
|
-
table.insert_ignore(:a => 10, :b => 20, :c => 30)
|
164
|
-
table.replace(:a => 10, :b => 20, :c => 30)
|
165
|
-
|
166
|
-
# Update with common default values
|
167
|
-
with_defaults = table.default(:a => 10, :b => 20)
|
168
|
-
with_defaults.insert(:c => 30)
|
169
|
-
with_defaults.where('a != 10 or b != 20').update # sets a => 10, b => 20
|
170
|
-
|
171
|
-
# Batch updates with batch method
|
172
|
-
table.batch.insert(:a => 10, :b => 20, :c => JDBCHelper::SQL('10 + 20'))
|
173
|
-
table.batch.insert_ignore(:a => 10, :b => 20, :c => 30)
|
174
|
-
conn.execute_batch
|
175
|
-
|
176
|
-
# Delete with conditions
|
177
|
-
table.delete(:c => 3)
|
178
|
-
# Or equivalently,
|
179
|
-
table.where(:c => 3).delete
|
180
|
-
|
181
|
-
# Truncate or drop table (Cannot be undone)
|
182
|
-
table.truncate!
|
183
|
-
table.drop!
|
184
|
-
|
185
|
-
=== Using function wrappers (since 0.2.2)
|
186
|
-
conn.function(:mod).call 5, 3
|
187
|
-
conn.function(:coalesce).call(nil, nil, 'king')
|
188
|
-
|
189
|
-
=== Using procedure wrappers (since 0.3.0)
|
190
|
-
# Working with IN/INOUT/OUT parameteres
|
191
|
-
# Bind by ordinal number
|
192
|
-
conn.procedure(:update_and_fetch_something).call(
|
193
|
-
100, # Input parameter
|
194
|
-
["value", String], # Input/Output parameter
|
195
|
-
Fixnum # Output parameter
|
196
|
-
)
|
197
|
-
|
198
|
-
# Bind by parameter name
|
199
|
-
conn.procedure(:update_and_fetch_something).call(
|
200
|
-
:a => 100, :b => ["value", String], :c => Fixnum)
|
201
|
-
|
202
|
-
=== Using sequence wrappers (since 0.4.2)
|
203
|
-
seq = conn.sequence(:my_seq)
|
204
|
-
next = seq.nextval
|
205
|
-
curr = seq.currval
|
206
|
-
seq.reset!
|
207
|
-
seq.reset! 100
|
208
|
-
|
209
|
-
== Contributing to jdbc-helper
|
210
|
-
|
211
|
-
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
212
|
-
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
213
|
-
* Fork the project
|
214
|
-
* Start a feature/bugfix branch
|
215
|
-
* Commit and push until you are happy with your contribution
|
216
|
-
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
217
|
-
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
218
|
-
|
219
|
-
== Copyright
|
220
|
-
|
221
|
-
Copyright (c) 2011 Junegunn Choi. See LICENSE.txt for
|
222
|
-
further details.
|
223
|
-
|
data/test/test_performance.rb
DELETED
@@ -1,138 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
require 'benchmark'
|
3
|
-
|
4
|
-
class TestPerformance < Test::Unit::TestCase
|
5
|
-
include JDBCHelperTestHelper
|
6
|
-
|
7
|
-
def setup
|
8
|
-
@table = 'tmp_jdbc_helper'
|
9
|
-
@range = 'aaa'..'aaz'
|
10
|
-
@count = 10000 # Increase this for performance measurement
|
11
|
-
end
|
12
|
-
|
13
|
-
def teardown
|
14
|
-
each_connection do | conn |
|
15
|
-
drop_table conn
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
# No assertion here.
|
20
|
-
def test_performance
|
21
|
-
each_connection do | conn |
|
22
|
-
reset conn
|
23
|
-
puts "Normal inserts: #{Benchmark.measure {
|
24
|
-
@count.times do |i|
|
25
|
-
conn.update "insert into #{@table} values (#{@range.map{rand @count}.join ','})"
|
26
|
-
end
|
27
|
-
}.real}"
|
28
|
-
|
29
|
-
puts "Normal inserts (batch & chuck-transactional): #{Benchmark.measure {
|
30
|
-
(0...@count).each_slice(50) do |slice|
|
31
|
-
conn.transaction do
|
32
|
-
slice.each do |i|
|
33
|
-
conn.add_batch "insert into #{@table} values (#{@range.map{rand @count}.join ','})"
|
34
|
-
end
|
35
|
-
conn.execute_batch
|
36
|
-
end
|
37
|
-
end
|
38
|
-
}.real}"
|
39
|
-
|
40
|
-
puts "Prepared inserts: #{Benchmark.measure {
|
41
|
-
pins = conn.prepare "insert into #{@table} values (#{@range.map{'?'}.join ','})"
|
42
|
-
@count.times do |i|
|
43
|
-
pins.update *(@range.map {rand @count})
|
44
|
-
end
|
45
|
-
pins.close
|
46
|
-
}.real}"
|
47
|
-
|
48
|
-
puts "Prepared inserts (batch & chuck-transactional): #{Benchmark.measure {
|
49
|
-
pins = conn.prepare "insert into #{@table} values (#{@range.map{'?'}.join ','})"
|
50
|
-
(0...@count).each_slice(50) do |slice|
|
51
|
-
conn.transaction do
|
52
|
-
slice.each do |i|
|
53
|
-
pins.add_batch *(@range.map {rand @count})
|
54
|
-
end
|
55
|
-
pins.execute_batch
|
56
|
-
end
|
57
|
-
end
|
58
|
-
pins.close
|
59
|
-
}.real}"
|
60
|
-
|
61
|
-
puts "Inserts with hash: #{Benchmark.measure {
|
62
|
-
table = conn.table(@table)
|
63
|
-
@count.times do |i|
|
64
|
-
table.insert @range.inject({}) { |hash, key| hash[key] = rand; hash }
|
65
|
-
end
|
66
|
-
}.real}"
|
67
|
-
|
68
|
-
puts "Inserts with hash (batch & chunk-transactional): #{Benchmark.measure {
|
69
|
-
table = conn.table(@table)
|
70
|
-
btable = table.batch
|
71
|
-
(0...@count).each_slice(50) do |slice|
|
72
|
-
conn.transaction do
|
73
|
-
slice.each do |i|
|
74
|
-
btable.insert @range.inject({}) { |hash, key| hash[key] = rand; hash }
|
75
|
-
end
|
76
|
-
conn.execute_batch
|
77
|
-
end
|
78
|
-
end
|
79
|
-
}.real}"
|
80
|
-
|
81
|
-
assert_equal @count * 6, conn.table(@table).count
|
82
|
-
|
83
|
-
conn.query("select * from #{@table}") do |row|
|
84
|
-
# ...
|
85
|
-
end
|
86
|
-
|
87
|
-
puts "Accessing records using dot notation: #{Benchmark.measure {
|
88
|
-
conn.query("select * from #{@table}") do |row|
|
89
|
-
@range.each do |r|
|
90
|
-
row.send r
|
91
|
-
end
|
92
|
-
end
|
93
|
-
}.real}"
|
94
|
-
|
95
|
-
puts "Accessing records using numeric indexes: #{Benchmark.measure {
|
96
|
-
conn.query("select * from #{@table}") do |row|
|
97
|
-
@range.each_with_index do |r,i|
|
98
|
-
row[i]
|
99
|
-
end
|
100
|
-
end
|
101
|
-
}.real}"
|
102
|
-
|
103
|
-
puts "Chaining enumerators with query: #{Benchmark.measure {
|
104
|
-
conn.query("select * from #{@table}").each_slice(50) do |slice|
|
105
|
-
slice.each do |row|
|
106
|
-
@range.each_with_index do |r,i|
|
107
|
-
row[i]
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
111
|
-
}.real}"
|
112
|
-
|
113
|
-
puts "Chaining enumerators with enumerate: #{Benchmark.measure {
|
114
|
-
conn.enumerate("select * from #{@table}").each_slice(50) do |slice|
|
115
|
-
slice.each do |row|
|
116
|
-
@range.each_with_index do |r,i|
|
117
|
-
row[i]
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
}.real}"
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
def create_table conn
|
126
|
-
conn.update("create table #{@table} (#{@range.map { |e| "#{e} int" }.join(', ')})")
|
127
|
-
end
|
128
|
-
|
129
|
-
def drop_table conn
|
130
|
-
conn.update("drop table #{@table}") rescue nil
|
131
|
-
end
|
132
|
-
|
133
|
-
def reset conn
|
134
|
-
drop_table conn
|
135
|
-
create_table conn
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|