jdbc-helper 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.txt +20 -0
- data/README.rdoc +114 -0
- data/lib/jdbc-helper.rb +21 -0
- data/lib/jdbc-helper/connection.rb +395 -0
- data/lib/jdbc-helper/connection/prepared_statement.rb +141 -0
- data/lib/jdbc-helper/connection/result_set_enumerator.rb +100 -0
- data/lib/jdbc-helper/connection/row.rb +110 -0
- data/lib/jdbc-helper/connection/statement_pool.rb +61 -0
- data/lib/jdbc-helper/connector.rb +6 -0
- data/lib/jdbc-helper/connector/mysql_connector.rb +28 -0
- data/lib/jdbc-helper/connector/oracle_connector.rb +29 -0
- data/lib/jdbc-helper/constants.rb +26 -0
- data/test/database.yml +13 -0
- data/test/helper.rb +17 -0
- data/test/test_jdbc-helper.rb +292 -0
- metadata +105 -0
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Junegunn Choi
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
= jdbc-helper
|
2
|
+
|
3
|
+
A JDBC helper for Ruby/Database developers.
|
4
|
+
JDBCHelper::Connection object wraps around a JDBC connection and provides much nicer interface to
|
5
|
+
crucial database operations from primitive selects and updates to more complex ones involving
|
6
|
+
batch updates, prepared statements and transactions.
|
7
|
+
As the name implies, only works on JRuby.
|
8
|
+
|
9
|
+
= Examples
|
10
|
+
|
11
|
+
== Prerequisites
|
12
|
+
Add JDBC driver of the DBMS you're willing to use to your CLASSPATH
|
13
|
+
export CLASSPATH=$CLASSPATH:~/lib/mysql-connector-java.jar
|
14
|
+
|
15
|
+
|
16
|
+
== Connecting to a database
|
17
|
+
|
18
|
+
# :driver and :url must be given
|
19
|
+
conn = JDBCHelper::Connection.new(
|
20
|
+
:driver => 'com.mysql.jdbc.Driver',
|
21
|
+
:url => 'jdbc:mysql://localhost/test')
|
22
|
+
conn.close
|
23
|
+
|
24
|
+
|
25
|
+
# Optional :user and :password
|
26
|
+
conn = JDBCHelper::Connection.new(
|
27
|
+
:driver => 'com.mysql.jdbc.Driver',
|
28
|
+
:url => 'jdbc:mysql://localhost/test',
|
29
|
+
:user => 'mysql',
|
30
|
+
:password => '')
|
31
|
+
conn.close
|
32
|
+
|
33
|
+
|
34
|
+
# MySQL shortcut connector
|
35
|
+
conn = JDBCHelper::MySQLConnector.connect('localhost', 'mysql', '', 'test')
|
36
|
+
conn.close
|
37
|
+
|
38
|
+
== Querying database table
|
39
|
+
|
40
|
+
conn.query("SELECT a, b, c FROM T") do | row |
|
41
|
+
p row.labels
|
42
|
+
p row.rownum
|
43
|
+
|
44
|
+
puts row.a, row.b, row.c
|
45
|
+
puts row[0], row[1], row[2]
|
46
|
+
puts row['a'], row['b'], row['c']
|
47
|
+
end
|
48
|
+
|
49
|
+
# Returns an array of rows when block is not given
|
50
|
+
rows = conn.query("SELECT b FROM T")
|
51
|
+
uniq_rows = rows.uniq
|
52
|
+
|
53
|
+
# You can even nest queries
|
54
|
+
conn.query("SELECT a FROM T") do | row1 |
|
55
|
+
conn.query("SELECT * FROM T_#{row1.a}") do | row2 |
|
56
|
+
# ...
|
57
|
+
end
|
58
|
+
end
|
59
|
+
== Updating database table
|
60
|
+
del_count = conn.update("DELETE FROM T")
|
61
|
+
|
62
|
+
== Transaction
|
63
|
+
committed = conn.transaction do | tx |
|
64
|
+
# ...
|
65
|
+
# Transaction logic here
|
66
|
+
# ...
|
67
|
+
|
68
|
+
if success
|
69
|
+
tx.commit
|
70
|
+
else
|
71
|
+
tx.rollback
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
== Using batch interface
|
76
|
+
conn.add_batch("DELETE FROM T");
|
77
|
+
conn.execute_batch
|
78
|
+
conn.add_batch("DELETE FROM T");
|
79
|
+
conn.clear_batch
|
80
|
+
|
81
|
+
== Using prepared statements
|
82
|
+
p_sel = conn.prepare("SELECT * FROM T WHERE b = ? and c = ?")
|
83
|
+
p_sel.query(100, 200) do | row |
|
84
|
+
p row
|
85
|
+
end
|
86
|
+
p_sel.close
|
87
|
+
|
88
|
+
p_upd = conn.prepare("UPDATE T SET a = ? WHERE b = ?")
|
89
|
+
count = 0
|
90
|
+
100.times do | i |
|
91
|
+
count += p_upd.update('updated a', i)
|
92
|
+
end
|
93
|
+
|
94
|
+
p_upd.add_batch('pstmt + batch', 10)
|
95
|
+
p_upd.add_batch('pstmt + batch', 20)
|
96
|
+
p_upd.add_batch('pstmt + batch', 30)
|
97
|
+
p_upd.execute_batch
|
98
|
+
p_upd.close
|
99
|
+
|
100
|
+
== Contributing to jdbc-helper
|
101
|
+
|
102
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
103
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
104
|
+
* Fork the project
|
105
|
+
* Start a feature/bugfix branch
|
106
|
+
* Commit and push until you are happy with your contribution
|
107
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
108
|
+
* 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.
|
109
|
+
|
110
|
+
== Copyright
|
111
|
+
|
112
|
+
Copyright (c) 2011 Junegunn Choi. See LICENSE.txt for
|
113
|
+
further details.
|
114
|
+
|
data/lib/jdbc-helper.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# Junegunn Choi (junegunn.c@gmail.com)
|
3
|
+
|
4
|
+
if RUBY_PLATFORM.match(/java/).nil?
|
5
|
+
raise LoadError, 'JRuby is required for JDBC'
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'java'
|
9
|
+
|
10
|
+
module JavaLang # :nodoc:
|
11
|
+
include_package 'java.lang'
|
12
|
+
end
|
13
|
+
|
14
|
+
module JavaSql # :nodoc:
|
15
|
+
include_package 'java.sql'
|
16
|
+
end
|
17
|
+
|
18
|
+
require 'jdbc-helper/constants'
|
19
|
+
require 'jdbc-helper/connection'
|
20
|
+
require 'jdbc-helper/connector'
|
21
|
+
|
@@ -0,0 +1,395 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# Junegunn Choi (junegunn.c@gmail.com)
|
3
|
+
|
4
|
+
require 'jdbc-helper/connection/statement_pool'
|
5
|
+
require 'jdbc-helper/connection/prepared_statement'
|
6
|
+
require 'jdbc-helper/connection/result_set_enumerator'
|
7
|
+
require 'jdbc-helper/connection/row'
|
8
|
+
|
9
|
+
module JDBCHelper
|
10
|
+
# Encapsulates JDBC database connection.
|
11
|
+
# Lets you easily execute SQL statements and access their results.
|
12
|
+
#
|
13
|
+
#
|
14
|
+
# = Examples
|
15
|
+
#
|
16
|
+
# == Prerequisites
|
17
|
+
# Add JDBC driver of the DBMS you're willing to use to your CLASSPATH
|
18
|
+
# export CLASSPATH=$CLASSPATH:~/lib/mysql-connector-java.jar
|
19
|
+
#
|
20
|
+
#
|
21
|
+
# == Connecting to a database
|
22
|
+
#
|
23
|
+
# # :driver and :url must be given
|
24
|
+
# conn = JDBCHelper::Connection.new(
|
25
|
+
# :driver => 'com.mysql.jdbc.Driver',
|
26
|
+
# :url => 'jdbc:mysql://localhost/test')
|
27
|
+
# conn.close
|
28
|
+
#
|
29
|
+
#
|
30
|
+
# # Optional :user and :password
|
31
|
+
# conn = JDBCHelper::Connection.new(
|
32
|
+
# :driver => 'com.mysql.jdbc.Driver',
|
33
|
+
# :url => 'jdbc:mysql://localhost/test',
|
34
|
+
# :user => 'mysql',
|
35
|
+
# :password => '')
|
36
|
+
# conn.close
|
37
|
+
#
|
38
|
+
#
|
39
|
+
# # MySQL shortcut connector
|
40
|
+
# conn = JDBCHelper::MySQLConnector.connect('localhost', 'mysql', '', 'test')
|
41
|
+
# conn.close
|
42
|
+
#
|
43
|
+
# == Querying database table
|
44
|
+
#
|
45
|
+
# conn.query("SELECT a, b, c FROM T") do | row |
|
46
|
+
# p row.labels
|
47
|
+
# p row.rownum
|
48
|
+
#
|
49
|
+
# puts row.a, row.b, row.c
|
50
|
+
# puts row[0], row[1], row[2]
|
51
|
+
# puts row['a'], row['b'], row['c']
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
# # Returns an array of rows when block is not given
|
55
|
+
# rows = conn.query("SELECT b FROM T")
|
56
|
+
# uniq_rows = rows.uniq
|
57
|
+
#
|
58
|
+
# # You can even nest queries
|
59
|
+
# conn.query("SELECT a FROM T") do | row1 |
|
60
|
+
# conn.query("SELECT * FROM T_#{row1.a}") do | row2 |
|
61
|
+
# # ...
|
62
|
+
# end
|
63
|
+
# end
|
64
|
+
# == Updating database table
|
65
|
+
# del_count = conn.update("DELETE FROM T")
|
66
|
+
#
|
67
|
+
# == Transaction
|
68
|
+
# committed = conn.transaction do | tx |
|
69
|
+
# # ...
|
70
|
+
# # Transaction logic here
|
71
|
+
# # ...
|
72
|
+
#
|
73
|
+
# if success
|
74
|
+
# tx.commit
|
75
|
+
# else
|
76
|
+
# tx.rollback
|
77
|
+
# end
|
78
|
+
# end
|
79
|
+
#
|
80
|
+
# == Using batch interface
|
81
|
+
# conn.add_batch("DELETE FROM T");
|
82
|
+
# conn.execute_batch
|
83
|
+
# conn.add_batch("DELETE FROM T");
|
84
|
+
# conn.clear_batch
|
85
|
+
#
|
86
|
+
# == Using prepared statements
|
87
|
+
# p_sel = conn.prepare("SELECT * FROM T WHERE b = ? and c = ?")
|
88
|
+
# p_sel.query(100, 200) do | row |
|
89
|
+
# p row
|
90
|
+
# end
|
91
|
+
# p_sel.close
|
92
|
+
#
|
93
|
+
# p_upd = conn.prepare("UPDATE T SET a = ? WHERE b = ?")
|
94
|
+
# count = 0
|
95
|
+
# 100.times do | i |
|
96
|
+
# count += p_upd.update('updated a', i)
|
97
|
+
# end
|
98
|
+
#
|
99
|
+
# p_upd.add_batch('pstmt + batch', 10)
|
100
|
+
# p_upd.add_batch('pstmt + batch', 20)
|
101
|
+
# p_upd.add_batch('pstmt + batch', 30)
|
102
|
+
# p_upd.execute_batch
|
103
|
+
# p_upd.close
|
104
|
+
class Connection
|
105
|
+
Stat = Struct.new("DBExecStat", :type, :elapsed, :success_count, :fail_count) # :nodoc:
|
106
|
+
|
107
|
+
# Returns the statistics of the previous operation
|
108
|
+
def prev_stat
|
109
|
+
@prev_stat.dup
|
110
|
+
end
|
111
|
+
|
112
|
+
# Returns the accumulated statistics of each operation
|
113
|
+
attr_reader :stats
|
114
|
+
|
115
|
+
# Returns the underlying JDBC Connection object.
|
116
|
+
# Only use this when you really need to access it directly.
|
117
|
+
def jdbc_conn
|
118
|
+
@conn
|
119
|
+
end
|
120
|
+
alias java_obj jdbc_conn
|
121
|
+
|
122
|
+
# Creates a database connection.
|
123
|
+
# - `args` hash must include :driver (or "driver") and :url (or "url")
|
124
|
+
# - and takes optional :user and :password tuples (or "user", "password")
|
125
|
+
# - You can also specify :timeout (or "timeout") to override the default connection timeout (60 seconds)
|
126
|
+
#
|
127
|
+
# Must be closed explicitly if not used.
|
128
|
+
# If a block is given, the connection is automatically closed after executing the block.
|
129
|
+
def initialize(args = {})
|
130
|
+
# String-tolerance..
|
131
|
+
%w[driver url user password timeout].each do | strk |
|
132
|
+
args[strk.to_sym] = args.delete strk if args.has_key? strk
|
133
|
+
end
|
134
|
+
|
135
|
+
raise ArgumentError.new("driver not given") unless args.has_key? :driver
|
136
|
+
raise ArgumentError.new("url not given") unless args.has_key? :url
|
137
|
+
|
138
|
+
begin
|
139
|
+
Java::JavaClass.for_name args[:driver]
|
140
|
+
rescue Exception
|
141
|
+
# TODO
|
142
|
+
raise
|
143
|
+
end
|
144
|
+
|
145
|
+
timeout = args.has_key?(:timeout) ? args.delete(:timeout) : Constants::DEFAULT_LOGIN_TIMEOUT
|
146
|
+
JavaSql::DriverManager.setLoginTimeout timeout if timeout
|
147
|
+
|
148
|
+
props = java.util.Properties.new
|
149
|
+
(args.keys - [:url, :driver]).each do | key |
|
150
|
+
props.setProperty(key.to_s, args[key]) if args[key]
|
151
|
+
end
|
152
|
+
|
153
|
+
@conn = JavaSql::DriverManager.get_connection(args[:url], props)
|
154
|
+
@spool = StatementPool.send :new, self
|
155
|
+
@pstmts = {}
|
156
|
+
@bstmt = nil
|
157
|
+
|
158
|
+
@stats = Hash.new { | h, k | h[k] = Stat.new(k, 0, 0, 0) }
|
159
|
+
@prev_stat = Stat.new(nil, 0, 0, 0)
|
160
|
+
|
161
|
+
if block_given?
|
162
|
+
begin
|
163
|
+
yield self
|
164
|
+
ensure
|
165
|
+
close rescue nil
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# Creates a prepared statement, which is also an encapsulation of Java PreparedStatement object
|
171
|
+
def prepare(qstr)
|
172
|
+
check_closed
|
173
|
+
|
174
|
+
return @pstmts[qstr] if @pstmts.has_key? qstr
|
175
|
+
|
176
|
+
pstmt = PreparedStatement.send(:new, self, @pstmts, qstr,
|
177
|
+
measure(:prepare) { @conn.prepare_statement(qstr) })
|
178
|
+
@pstmts[qstr] = pstmt
|
179
|
+
pstmt
|
180
|
+
end
|
181
|
+
|
182
|
+
# Executes the given code block as a transaction. Returns true if the transaction is committed.
|
183
|
+
# A transaction object is passed to the block, which only has commit and rollback methods.
|
184
|
+
# The execution breaks out of the code block when either of the methods is called.
|
185
|
+
def transaction
|
186
|
+
check_closed
|
187
|
+
|
188
|
+
raise ArgumentError.new("Transaction block not given") unless block_given?
|
189
|
+
tx = Transaction.send :new, @conn
|
190
|
+
ac = @conn.get_auto_commit
|
191
|
+
status = :unknown
|
192
|
+
begin
|
193
|
+
@conn.set_auto_commit false
|
194
|
+
yield tx
|
195
|
+
@conn.commit
|
196
|
+
status = :committed
|
197
|
+
rescue Transaction::Commit
|
198
|
+
status = :committed
|
199
|
+
rescue Transaction::Rollback
|
200
|
+
status = :rolledback
|
201
|
+
ensure
|
202
|
+
@conn.rollback if status == :unknown
|
203
|
+
@conn.set_auto_commit ac
|
204
|
+
end
|
205
|
+
status == :committed
|
206
|
+
end
|
207
|
+
|
208
|
+
# Executes an update and returns the count of the updated rows.
|
209
|
+
def update(qstr)
|
210
|
+
check_closed
|
211
|
+
|
212
|
+
@spool.with do | stmt |
|
213
|
+
ret = measure(:update) { stmt.execute_update(qstr) }
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
# Executes a select query.
|
218
|
+
# When a code block is given, each row of the result is passed to the block one by one.
|
219
|
+
# If a code block not given, this method will return the array of the entire result rows.
|
220
|
+
# (which can be pretty inefficient when the result set is large. In such cases, use enumerate instead.)
|
221
|
+
#
|
222
|
+
# The concept of statement object of JDBC is encapsulated, so there's no need to do additional task,
|
223
|
+
# when you nest select queries, for example.
|
224
|
+
#
|
225
|
+
# conn.query("SELECT a FROM T") do | trow |
|
226
|
+
# conn.query("SELECT * FROM U_#{trow.a}") do | urow |
|
227
|
+
# # ... and so on ...
|
228
|
+
# end
|
229
|
+
# end
|
230
|
+
def query(qstr, &blk)
|
231
|
+
check_closed
|
232
|
+
|
233
|
+
@spool.with do | stmt |
|
234
|
+
measure(:query) { stmt.execute(qstr) }
|
235
|
+
process_and_close_rset(stmt.get_result_set, &blk)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
# Returns an enumerable object of the query result.
|
240
|
+
# "enumerate" method is preferable when dealing with a large result set,
|
241
|
+
# since it doesn't have to build a large array.
|
242
|
+
#
|
243
|
+
# The returned enumerator is automatically closed after enumeration.
|
244
|
+
#
|
245
|
+
# conn.enumerate('SELECT * FROM T').each_slice(10) do | slice |
|
246
|
+
# slice.each { | row | print row }
|
247
|
+
# puts
|
248
|
+
# end
|
249
|
+
#
|
250
|
+
def enumerate(qstr, &blk)
|
251
|
+
check_closed
|
252
|
+
|
253
|
+
return query(qstr, &blk) if block_given?
|
254
|
+
|
255
|
+
stmt = @spool.take
|
256
|
+
begin
|
257
|
+
measure(:query) { stmt.execute(qstr) }
|
258
|
+
rescue Exception
|
259
|
+
@spool.give stmt
|
260
|
+
raise
|
261
|
+
end
|
262
|
+
|
263
|
+
ResultSetEnumerator.send(:new, stmt.get_result_set) { @spool.give stmt }
|
264
|
+
end
|
265
|
+
|
266
|
+
# Adds a statement to be executed in batch
|
267
|
+
def add_batch(qstr)
|
268
|
+
check_closed
|
269
|
+
|
270
|
+
@bstmt ||= @spool.take
|
271
|
+
@bstmt.add_batch qstr
|
272
|
+
end
|
273
|
+
|
274
|
+
# Executes batched statements. No effect when no statment is added
|
275
|
+
def execute_batch
|
276
|
+
check_closed
|
277
|
+
|
278
|
+
return unless @bstmt
|
279
|
+
ret = measure(:execute_batch) { @bstmt.execute_batch }
|
280
|
+
@spool.give @bstmt
|
281
|
+
@bstmt = nil
|
282
|
+
ret
|
283
|
+
end
|
284
|
+
|
285
|
+
# Clears the batched statements
|
286
|
+
def clear_batch
|
287
|
+
check_closed
|
288
|
+
|
289
|
+
return unless @bstmt
|
290
|
+
@bstmt.clear_batch
|
291
|
+
@spool.give @bstmt
|
292
|
+
@bstmt = nil
|
293
|
+
end
|
294
|
+
|
295
|
+
# Gives the JDBC driver a hint of the number of rows to fetch from the database by a single interaction.
|
296
|
+
# This is only a hint. It may have no effect at all.
|
297
|
+
def set_fetch_size(fsz)
|
298
|
+
check_closed
|
299
|
+
|
300
|
+
@fetch_size = fsz
|
301
|
+
@spool.each { | stmt | stmt.set_fetch_size @fetch_size }
|
302
|
+
end
|
303
|
+
|
304
|
+
# Closes the connection
|
305
|
+
def close
|
306
|
+
return if closed?
|
307
|
+
@pstmts.each { | q, pstmt | pstmt.close }
|
308
|
+
@spool.close
|
309
|
+
@conn.close
|
310
|
+
@conn = @spool = nil
|
311
|
+
end
|
312
|
+
|
313
|
+
# Returns if this connection is closed or not
|
314
|
+
def closed?
|
315
|
+
@conn.nil?
|
316
|
+
end
|
317
|
+
|
318
|
+
private
|
319
|
+
# Transaction object passed to the code block given to transaction method
|
320
|
+
class Transaction
|
321
|
+
# Commits the transaction
|
322
|
+
def commit
|
323
|
+
@conn.commit
|
324
|
+
raise Commit
|
325
|
+
end
|
326
|
+
# Rolls back this transaction
|
327
|
+
def rollback
|
328
|
+
@conn.rollback
|
329
|
+
raise Rollback
|
330
|
+
end
|
331
|
+
private
|
332
|
+
def initialize(conn) # :nodoc:
|
333
|
+
@conn = conn
|
334
|
+
end
|
335
|
+
class Commit < Exception # :nodoc:
|
336
|
+
end
|
337
|
+
class Rollback < Exception # :nodoc:
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
def create_statement # :nodoc:
|
342
|
+
stmt = @conn.create_statement
|
343
|
+
stmt.set_fetch_size @fetch_size if @fetch_size
|
344
|
+
stmt
|
345
|
+
end
|
346
|
+
|
347
|
+
def process_and_close_rset(rset) # :nodoc:
|
348
|
+
enum = ResultSetEnumerator.send :new, rset
|
349
|
+
rows = []
|
350
|
+
|
351
|
+
begin
|
352
|
+
enum.each do | row |
|
353
|
+
if block_given?
|
354
|
+
yield row
|
355
|
+
else
|
356
|
+
rows << row
|
357
|
+
end
|
358
|
+
end
|
359
|
+
block_given? ? nil : rows
|
360
|
+
ensure
|
361
|
+
enum.close
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
def update_stat(type, elapsed, success_count, fail_count) # :nodoc:
|
366
|
+
@prev_stat.type = type
|
367
|
+
@prev_stat.elapsed = elapsed
|
368
|
+
@prev_stat.success_count = success_count
|
369
|
+
@prev_stat.fail_count = fail_count
|
370
|
+
|
371
|
+
accum = @stats[type]
|
372
|
+
accum.elapsed += elapsed
|
373
|
+
accum.success_count += success_count
|
374
|
+
accum.fail_count += fail_count
|
375
|
+
end
|
376
|
+
|
377
|
+
def measure(type)
|
378
|
+
begin
|
379
|
+
st = Time.now
|
380
|
+
ret = yield
|
381
|
+
elapsed = Time.now - st
|
382
|
+
update_stat(type, elapsed, 1, 0)
|
383
|
+
rescue Exception
|
384
|
+
update_stat(type, 0, 0, 1)
|
385
|
+
raise
|
386
|
+
end
|
387
|
+
ret
|
388
|
+
end
|
389
|
+
|
390
|
+
def check_closed
|
391
|
+
raise RuntimeError.new('Connection already closed') if closed?
|
392
|
+
end
|
393
|
+
end#Connection
|
394
|
+
end#JDBCHelper
|
395
|
+
|