1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.skife.jdbi.v2;
18
19 import org.skife.jdbi.v2.exceptions.TransactionFailedException;
20 import org.skife.jdbi.v2.exceptions.UnableToCloseResourceException;
21 import org.skife.jdbi.v2.tweak.SQLLog;
22 import org.skife.jdbi.v2.tweak.StatementBuilder;
23 import org.skife.jdbi.v2.tweak.StatementCustomizer;
24 import org.skife.jdbi.v2.tweak.StatementLocator;
25 import org.skife.jdbi.v2.tweak.StatementRewriter;
26 import org.skife.jdbi.v2.tweak.TransactionHandler;
27
28 import java.sql.Connection;
29 import java.sql.SQLException;
30 import java.util.Collections;
31 import java.util.HashMap;
32 import java.util.List;
33 import java.util.Map;
34
35 class BasicHandle implements Handle
36 {
37 private final TransactionHandler transactions;
38 private final Connection connection;
39 private StatementRewriter statementRewriter;
40 private StatementLocator statementLocator;
41 private SQLLog log;
42 private TimingCollector timingCollector;
43 private StatementBuilder statementBuilder;
44 private final Map<String, Object> globalStatementAttributes;
45
46 BasicHandle(TransactionHandler transactions,
47 StatementLocator statementLocator,
48 StatementBuilder preparedStatementCache,
49 StatementRewriter statementRewriter,
50 Connection connection,
51 Map<String, Object> globalStatementAttributes,
52 SQLLog log,
53 TimingCollector timingCollector) {
54 this.statementBuilder = preparedStatementCache;
55 this.statementRewriter = statementRewriter;
56 this.transactions = transactions;
57 this.connection = connection;
58 this.statementLocator = statementLocator;
59 this.log = log;
60 this.timingCollector = timingCollector;
61 this.globalStatementAttributes = new HashMap<String, Object>();
62 this.globalStatementAttributes.putAll(globalStatementAttributes);
63 }
64
65 public Query<Map<String, Object>> createQuery(String sql) {
66 return new Query<Map<String, Object>>(new Binding(),
67 new DefaultMapper(),
68 statementLocator,
69 statementRewriter,
70 connection,
71 statementBuilder,
72 sql,
73 new StatementContext(globalStatementAttributes),
74 log,
75 timingCollector,
76 Collections.<StatementCustomizer>emptyList());
77 }
78
79
80
81
82
83
84 public Connection getConnection() {
85 return this.connection;
86 }
87
88 public void close() {
89 statementBuilder.close(getConnection());
90 try {
91 connection.close();
92 log.logReleaseHandle(this);
93 }
94 catch (SQLException e) {
95 throw new UnableToCloseResourceException("Unable to close Connection", e);
96 }
97 }
98
99 public void define(String key, Object value) {
100 this.globalStatementAttributes.put(key, value);
101 }
102
103
104
105
106 public Handle begin() {
107 transactions.begin(this);
108 log.logBeginTransaction(this);
109 return this;
110 }
111
112
113
114
115 public Handle commit() {
116 final long start = System.nanoTime();
117 transactions.commit(this);
118 log.logCommitTransaction((System.nanoTime() - start) / 1000000L, this);
119 return this;
120 }
121
122
123
124
125 public Handle rollback() {
126 final long start = System.nanoTime();
127 transactions.rollback(this);
128 log.logRollbackTransaction((System.nanoTime() - start) / 1000000L, this);
129 return this;
130 }
131
132
133
134
135
136
137
138
139 public Handle checkpoint(String name) {
140 transactions.checkpoint(this, name);
141 log.logCheckpointTransaction(this, name);
142 return this;
143 }
144
145
146
147
148
149
150 public Handle release(String checkpointName) {
151 transactions.release(this, checkpointName);
152 log.logReleaseCheckpointTransaction(this, checkpointName);
153 return this;
154 }
155
156 public void setStatementBuilder(StatementBuilder builder) {
157 this.statementBuilder = builder;
158 }
159
160 public void setSQLLog(SQLLog log) {
161 this.log = log;
162 }
163
164 public void setTimingCollector(final TimingCollector timingCollector) {
165 if (timingCollector == null) {
166 this.timingCollector = TimingCollector.NOP_TIMING_COLLECTOR;
167 }
168 else {
169 this.timingCollector = timingCollector;
170 }
171 }
172
173
174
175
176
177
178
179 public Handle rollback(String checkpointName) {
180 final long start = System.nanoTime();
181 transactions.rollback(this, checkpointName);
182 log.logRollbackToCheckpoint((System.nanoTime() - start) / 1000000L, this, checkpointName);
183 return this;
184 }
185
186 public boolean isInTransaction() {
187 return transactions.isInTransaction(this);
188 }
189
190 public Update createStatement(String sql) {
191 return new Update(connection,
192 statementLocator,
193 statementRewriter,
194 statementBuilder,
195 sql,
196 new StatementContext(globalStatementAttributes),
197 log,
198 timingCollector);
199 }
200
201 public Call createCall(String sql) {
202 return new Call(connection,
203 statementLocator,
204 statementRewriter,
205 statementBuilder,
206 sql,
207 new StatementContext(globalStatementAttributes),
208 log,
209 timingCollector,
210 Collections.<StatementCustomizer>emptyList());
211 }
212
213 public int insert(String sql, Object... args) {
214 return update(sql, args);
215 }
216
217 public int update(String sql, Object... args) {
218 Update stmt = createStatement(sql);
219 int position = 0;
220 for (Object arg : args) {
221 stmt.bind(position++, arg);
222 }
223 return stmt.execute();
224 }
225
226 public PreparedBatch prepareBatch(String sql) {
227 return new PreparedBatch(statementLocator,
228 statementRewriter,
229 connection,
230 statementBuilder,
231 sql,
232 globalStatementAttributes,
233 log,
234 timingCollector);
235 }
236
237 public Batch createBatch() {
238 return new Batch(this.statementRewriter,
239 this.connection,
240 globalStatementAttributes,
241 log,
242 timingCollector);
243 }
244
245 public <ReturnType> ReturnType inTransaction(TransactionCallback<ReturnType> callback) throws TransactionFailedException {
246 final boolean[] failed = {false};
247 TransactionStatus status = new TransactionStatus()
248 {
249 public void setRollbackOnly() {
250 failed[0] = true;
251 }
252 };
253 final ReturnType returnValue;
254 try {
255 this.begin();
256 returnValue = callback.inTransaction(this, status);
257 if (!failed[0]) {
258 this.commit();
259 }
260 }
261 catch (RuntimeException e) {
262 this.rollback();
263 throw e;
264 }
265 catch (Exception e) {
266 this.rollback();
267 throw new TransactionFailedException("Transaction failed do to exception being thrown " +
268 "from within the callback. See cause " +
269 "for the original exception.", e);
270 }
271 if (failed[0]) {
272 this.rollback();
273 throw new TransactionFailedException("Transaction failed due to transaction status being set " +
274 "to rollback only.");
275 }
276 else {
277 return returnValue;
278 }
279 }
280
281 public List<Map<String, Object>> select(String sql, Object... args) {
282 Query<Map<String, Object>> query = this.createQuery(sql);
283 int position = 0;
284 for (Object arg : args) {
285 query.bind(position++, arg);
286 }
287 return query.list();
288 }
289
290 public void setStatementLocator(StatementLocator locator) {
291 this.statementLocator = locator;
292 }
293
294 public void setStatementRewriter(StatementRewriter rewriter) {
295 this.statementRewriter = rewriter;
296 }
297
298 public Script createScript(String name) {
299 return new Script(this, statementLocator, name, globalStatementAttributes);
300 }
301
302 public void execute(String sql, Object... args) {
303 this.update(sql, args);
304 }
305 }