• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

future-architect / uroborosql / #743

28 Jun 2024 04:17PM UTC coverage: 90.988% (+0.5%) from 90.484%
#743

push

web-flow
add paramIfNotEmpty method (#318)

* v0.x to master merge

* fix nanoseconds diff (java8 to java11)

* eclipse cleanup and  optimize import

* eclipse format

* optimize Imports

* remove unused annotation

* library version up

* migrate v0.x to master
- update java version 8 to 11
- update junit4 to junit5
- library version update

* fix test failed

* remove unused annotation

* fixed bug

* use var

* fix java8 coding style

* Refactoring TransactionContextManager

* Refactoring SqlAgent

* 途中コミット

* fix testcase

* fix review

* fix javadoc comments

* merge v0.x PR

* cleanup code

* cleanup test code

* change build status badge

* - agent.query, update, proc, batch にそれぞれSupplierを引数にとるメソッドを追加
- SqlQuery.paramとSqlEntityUpdate.setにFunctionを受け取るメソッドを追加

* testcaseの整形

* - SqlFluent と ExtractionCondition の分離
- Arrays.asList -> List.of への変更
- テストの整形

* - v0.x系の不具合対応の追いつき
- ログ出力の整理

* - SqlKindの整理(ENTITY_XXXの追加)
- REPL_LOGの追加
- Deprecatedメソッドの削除(SqlAgent)
- SqlAgent, ExecutionContextでsetterをfluent APIに変更

* DB接続URLの修正

* add and fix testcases.

* add event testcases.

* fix typo

* add paramIfNotEmpty method and StringUtils rename ObjectUtils

* fix review comments.

* remove unused import

1695 of 1958 new or added lines in 97 files covered. (86.57%)

26 existing lines in 10 files now uncovered.

8249 of 9066 relevant lines covered (90.99%)

0.91 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.14
/src/main/java/jp/co/future/uroborosql/tx/LocalTransactionContext.java
1
/**
2
 * Copyright (c) 2017-present, Future Corporation
3
 *
4
 * This source code is licensed under the MIT license found in the
5
 * LICENSE file in the root directory of this source tree.
6
 */
7
package jp.co.future.uroborosql.tx;
8

9
import java.sql.CallableStatement;
10
import java.sql.Connection;
11
import java.sql.PreparedStatement;
12
import java.sql.SQLException;
13
import java.sql.Savepoint;
14
import java.util.ArrayList;
15
import java.util.Collections;
16
import java.util.List;
17
import java.util.concurrent.ConcurrentHashMap;
18
import java.util.concurrent.ConcurrentMap;
19

20
import org.slf4j.Logger;
21
import org.slf4j.LoggerFactory;
22

23
import jp.co.future.uroborosql.config.SqlConfig;
24
import jp.co.future.uroborosql.connection.ConnectionContext;
25
import jp.co.future.uroborosql.context.ExecutionContext;
26
import jp.co.future.uroborosql.event.AfterCommitEvent;
27
import jp.co.future.uroborosql.event.AfterCreateCallableStatementEvent;
28
import jp.co.future.uroborosql.event.AfterCreatePreparedStatementEvent;
29
import jp.co.future.uroborosql.event.AfterRollbackEvent;
30
import jp.co.future.uroborosql.event.BeforeCommitEvent;
31
import jp.co.future.uroborosql.event.BeforeRollbackEvent;
32
import jp.co.future.uroborosql.exception.UroborosqlSQLException;
33
import jp.co.future.uroborosql.exception.UroborosqlTransactionException;
34

35
/**
36
 * ローカルトランザクションContext
37
 *
38
 * @author ota
39
 */
40
class LocalTransactionContext implements TransactionContext {
41
        /** ロガー */
42
        private static final Logger LOG = LoggerFactory.getLogger("jp.co.future.uroborosql.log");
1✔
43

44
        /** セーブポイント名リスト */
45
        private final List<String> savepointNames = new ArrayList<>();
1✔
46

47
        /** セーブポイントキャッシュ */
48
        private final ConcurrentMap<String, Savepoint> savepointMap = new ConcurrentHashMap<>();
1✔
49

50
        /** SQL設定クラス */
51
        private final SqlConfig sqlConfig;
52

53
        /** コネクション */
54
        private Connection connection;
55

56
        /** ロールバックフラグ */
57
        private boolean rollbackOnly = false;
1✔
58

59
        /** トランザクション内での更新を強制するかどうか */
60
        private final boolean updatable;
61

62
        /** DB接続情報. ConnectionSupplierで指定したデフォルトの接続情報を使用する場合は<code>null</code>を指定する */
63
        private final ConnectionContext connectionContext;
64

65
        /**
66
         * コンストラクタ
67
         *
68
         * @param sqlConfig SQL設定クラス
69
         * @param updatable 更新(INSERT/UPDATE/DELETE)SQL発行可能かどうか
70
         * @param connectionContext DB接続情報. ConnectionSupplierで指定したデフォルトの接続情報を使用する場合は<code>null</code>を指定する
71
         */
72
        LocalTransactionContext(final SqlConfig sqlConfig, final boolean updatable,
73
                        final ConnectionContext connectionContext) {
1✔
74
                this.sqlConfig = sqlConfig;
1✔
75
                this.updatable = updatable;
1✔
76
                this.connectionContext = connectionContext;
1✔
77
        }
1✔
78

79
        /**
80
         * {@inheritDoc}
81
         *
82
         * @see jp.co.future.uroborosql.tx.TransactionContext#getSqlConfig()
83
         */
84
        @Override
85
        public SqlConfig getSqlConfig() {
NEW
86
                return this.sqlConfig;
×
87
        }
88

89
        /**
90
         * {@inheritDoc}
91
         *
92
         * @see jp.co.future.uroborosql.tx.TransactionContext#getConnection()
93
         */
94
        @Override
95
        public Connection getConnection() throws SQLException {
96
                if (connection == null) {
1✔
97
                        if (connectionContext == null) {
1✔
98
                                connection = this.sqlConfig.getConnectionSupplier().getConnection();
1✔
99
                        } else {
100
                                connection = this.sqlConfig.getConnectionSupplier().getConnection(connectionContext);
1✔
101
                        }
102
                        initSavepoints(connection);
1✔
103
                }
104
                return connection;
1✔
105
        }
106

107
        /**
108
         * {@inheritDoc}
109
         *
110
         * @see jp.co.future.uroborosql.tx.TransactionContext#getConnectionContext()
111
         */
112
        @Override
113
        public ConnectionContext getConnectionContext() {
NEW
114
                return this.connectionContext;
×
115
        }
116

117
        /**
118
         * {@inheritDoc}
119
         *
120
         * @see jp.co.future.uroborosql.tx.TransactionContext#getPreparedStatement(jp.co.future.uroborosql.context.ExecutionContext)
121
         */
122
        @Override
123
        public PreparedStatement getPreparedStatement(final ExecutionContext executionContext) throws SQLException {
124
                var conn = getConnection();
1✔
125

126
                PreparedStatement stmt = null;
1✔
127
                switch (executionContext.getSqlKind()) {
1✔
128
                case INSERT:
129
                case ENTITY_INSERT:
130
                case BULK_INSERT:
131
                case BATCH_INSERT:
132
                case ENTITY_BULK_INSERT:
133
                case ENTITY_BATCH_INSERT:
134
                        if (updatable) {
1✔
135
                                if (executionContext.hasGeneratedKeyColumns()) {
1✔
136
                                        stmt = conn.prepareStatement(executionContext.getExecutableSql(),
1✔
137
                                                        executionContext.getGeneratedKeyColumns());
1✔
138
                                } else {
139
                                        stmt = conn.prepareStatement(executionContext.getExecutableSql());
1✔
140
                                }
141
                        } else {
142
                                throw new UroborosqlTransactionException("Transaction not started.");
1✔
143
                        }
144
                        break;
145
                case SELECT:
146
                case ENTITY_SELECT:
147
                        stmt = conn.prepareStatement(executionContext.getExecutableSql(),
1✔
148
                                        executionContext.getResultSetType(),
1✔
149
                                        executionContext.getResultSetConcurrency());
1✔
150
                        break;
1✔
151
                default:
152
                        if (updatable) {
1✔
153
                                stmt = conn.prepareStatement(executionContext.getExecutableSql());
1✔
154
                        } else {
155
                                throw new UroborosqlTransactionException("Transaction not started.");
1✔
156
                        }
157
                        break;
158
                }
159

160
                // PreparedStatement作成後イベント発行
161
                if (this.sqlConfig.getEventListenerHolder().hasAfterCreatePreparedStatementListener()) {
1✔
162
                        var eventObj = new AfterCreatePreparedStatementEvent(executionContext, conn, stmt);
1✔
163
                        for (var listener : this.sqlConfig.getEventListenerHolder().getAfterCreatePreparedStatementListeners()) {
1✔
164
                                listener.accept(eventObj);
1✔
165
                        }
1✔
166
                        stmt = eventObj.getPreparedStatement();
1✔
167
                }
168
                return stmt;
1✔
169
        }
170

171
        /**
172
         * {@inheritDoc}
173
         *
174
         * @see jp.co.future.uroborosql.tx.TransactionContext#getCallableStatement(jp.co.future.uroborosql.context.ExecutionContext)
175
         */
176
        @Override
177
        public CallableStatement getCallableStatement(final ExecutionContext executionContext) throws SQLException {
178
                var conn = getConnection();
1✔
179

180
                if (this.updatable) {
1✔
181
                        var cstmt = conn.prepareCall(executionContext.getExecutableSql(),
1✔
182
                                        executionContext.getResultSetType(),
1✔
183
                                        executionContext.getResultSetConcurrency());
1✔
184

185
                        // CallableStatement作成後イベント発行
186
                        if (this.sqlConfig.getEventListenerHolder().hasAfterCreateCallableStatementListener()) {
1✔
187
                                var eventObj = new AfterCreateCallableStatementEvent(executionContext, conn, cstmt);
1✔
188
                                for (var listener : this.sqlConfig.getEventListenerHolder()
1✔
189
                                                .getAfterCreateCallableStatementListeners()) {
1✔
190
                                        listener.accept(eventObj);
1✔
191
                                }
1✔
192
                                cstmt = eventObj.getCallableStatement();
1✔
193

194
                        }
195
                        return cstmt;
1✔
196
                } else {
197
                        throw new UroborosqlTransactionException("Transaction not started.");
1✔
198
                }
199
        }
200

201
        /**
202
         * {@inheritDoc}
203
         *
204
         * @see jp.co.future.uroborosql.tx.TransactionContext#commit()
205
         */
206
        @Override
207
        public void commit() {
208
                try {
209
                        if (connection != null && !connection.isClosed() && !connection.getAutoCommit()) {
1✔
210
                                // コミット前イベント発行
211
                                if (this.sqlConfig.getEventListenerHolder().hasBeforeCommitListener()) {
1✔
212
                                        var beforeEventObj = new BeforeCommitEvent(this, connection);
1✔
213
                                        this.sqlConfig.getEventListenerHolder().getBeforeCommitListeners()
1✔
214
                                                        .forEach(listener -> listener.accept(beforeEventObj));
1✔
215
                                }
216
                                connection.commit();
1✔
217
                                // コミット後イベント発行
218
                                if (this.sqlConfig.getEventListenerHolder().hasAfterCommitListener()) {
1✔
219
                                        var afterEventObj = new AfterCommitEvent(this, connection);
1✔
220
                                        this.sqlConfig.getEventListenerHolder().getAfterCommitListeners()
1✔
221
                                                        .forEach(listener -> listener.accept(afterEventObj));
1✔
222
                                }
223
                        }
NEW
224
                } catch (SQLException ex) {
×
NEW
225
                        throw new UroborosqlSQLException(ex);
×
226
                }
1✔
227
                clearState();
1✔
228
        }
1✔
229

230
        /**
231
         * {@inheritDoc}
232
         *
233
         * @see jp.co.future.uroborosql.tx.TransactionContext#rollback()
234
         */
235
        @Override
236
        public void rollback() {
237
                try {
238
                        if (connection != null && !connection.isClosed() && !connection.getAutoCommit()) {
1✔
239
                                // ロールバック前イベント発行
240
                                if (this.sqlConfig.getEventListenerHolder().hasBeforeRollbackListener()) {
1✔
241
                                        var beforeEventObj = new BeforeRollbackEvent(this, connection);
1✔
242
                                        this.sqlConfig.getEventListenerHolder().getBeforeRollbackListeners()
1✔
243
                                                        .forEach(listener -> listener.accept(beforeEventObj));
1✔
244
                                }
245
                                connection.rollback();
1✔
246
                                // ロールバック後イベント発行
247
                                if (this.sqlConfig.getEventListenerHolder().hasAfterRollbackListener()) {
1✔
248
                                        var afterEventObj = new AfterRollbackEvent(this, connection);
1✔
249
                                        this.sqlConfig.getEventListenerHolder().getAfterRollbackListeners()
1✔
250
                                                        .forEach(listener -> listener.accept(afterEventObj));
1✔
251
                                }
252
                        }
NEW
253
                } catch (SQLException ex) {
×
NEW
254
                        throw new UroborosqlSQLException(ex);
×
255
                }
1✔
256
                clearState();
1✔
257
        }
1✔
258

259
        /**
260
         * {@inheritDoc}
261
         *
262
         * @see jp.co.future.uroborosql.tx.TransactionContext#isRollbackOnly()
263
         */
264
        @Override
265
        public boolean isRollbackOnly() {
266
                return rollbackOnly;
1✔
267
        }
268

269
        /**
270
         * {@inheritDoc}
271
         *
272
         * @see jp.co.future.uroborosql.tx.TransactionContext#setRollbackOnly()
273
         */
274
        @Override
275
        public void setRollbackOnly() {
276
                this.rollbackOnly = true;
1✔
277
        }
1✔
278

279
        /**
280
         * {@inheritDoc}
281
         *
282
         * @see jp.co.future.uroborosql.tx.TransactionContext#rollback(java.lang.String)
283
         */
284
        @Override
285
        public void rollback(final String savepointName) {
286
                if (connection != null) {
1✔
287
                        try {
288
                                connection.rollback(savepointMap.get(savepointName));
1✔
NEW
289
                        } catch (SQLException ex) {
×
NEW
290
                                throw new UroborosqlSQLException(ex);
×
291
                        }
1✔
292
                }
293
        }
1✔
294

295
        /**
296
         * {@inheritDoc}
297
         *
298
         * @see jp.co.future.uroborosql.tx.TransactionContext#setSavepoint(java.lang.String)
299
         */
300
        @Override
301
        public void setSavepoint(final String savepointName) {
302
                if (savepointNames.contains(savepointName)) {
1✔
NEW
303
                        throw new IllegalStateException();
×
304
                }
305
                savepointNames.add(savepointName);
1✔
306

307
                if (connection != null) {
1✔
308
                        try {
309
                                savepointMap.put(savepointName, connection.setSavepoint(savepointName));
1✔
NEW
310
                        } catch (SQLException ex) {
×
NEW
311
                                throw new UroborosqlSQLException(ex);
×
312
                        }
1✔
313
                }
314
        }
1✔
315

316
        /**
317
         * {@inheritDoc}
318
         *
319
         * @see jp.co.future.uroborosql.tx.TransactionContext#releaseSavepoint(java.lang.String)
320
         */
321
        @Override
322
        public void releaseSavepoint(final String savepointName) {
323
                var savepoint = savepointMap.get(savepointName);
1✔
324

325
                var pos = savepointNames.lastIndexOf(savepointName);
1✔
326
                if (pos > -1) {
1✔
327
                        var subList = savepointNames.subList(pos, savepointNames.size());
1✔
328
                        for (var name : subList) {
1✔
329
                                savepointMap.remove(name);
1✔
330
                        }
1✔
331
                        subList.clear();
1✔
332
                }
333

334
                if (savepoint != null && connection != null) {
1✔
335
                        try {
336
                                connection.releaseSavepoint(savepoint);
1✔
NEW
337
                        } catch (SQLException ex) {
×
NEW
338
                                throw new UroborosqlSQLException(ex);
×
339
                        }
1✔
340
                }
341
        }
1✔
342

343
        /**
344
         * {@inheritDoc}
345
         *
346
         * @see jp.co.future.uroborosql.tx.TransactionContext#getSavepointNames()
347
         */
348
        @Override
349
        public List<String> getSavepointNames() {
NEW
350
                return Collections.unmodifiableList(this.savepointNames);
×
351
        }
352

353
        /**
354
         * {@inheritDoc}
355
         *
356
         * @see jp.co.future.uroborosql.tx.TransactionContext#close()
357
         */
358
        @Override
359
        public void close() {
360
                try {
361
                        if (!isRollbackOnly()) {
1✔
362
                                commit();
1✔
363
                        } else {
364
                                rollback();
1✔
365
                        }
366
                        if (connection != null && !connection.isClosed()) {
1✔
367
                                connection.close();
1✔
368
                        } else {
369
                                if (LOG.isWarnEnabled()) {
1✔
370
                                        LOG.warn("Connection close was skipped because the connection was already closed.");
1✔
371
                                }
372
                        }
NEW
373
                } catch (SQLException ex) {
×
NEW
374
                        throw new UroborosqlSQLException(ex);
×
375
                }
1✔
376
                connection = null;
1✔
377
        }
1✔
378

379
        /**
380
         * ステータスクリア
381
         */
382
        void clearState() {
383
                savepointNames.clear();
1✔
384
                savepointMap.clear();
1✔
385
                rollbackOnly = false;
1✔
386
        }
1✔
387

388
        /**
389
         * Savepointの設定を遅延して行う
390
         *
391
         * @param connection コネクション
392
         * @throws SQLException SQL例外
393
         */
394
        private void initSavepoints(final Connection connection) {
395
                for (var savepointName : savepointNames) {
1✔
396
                        try {
397
                                savepointMap.put(savepointName, connection.setSavepoint(savepointName));
1✔
NEW
398
                        } catch (SQLException ex) {
×
NEW
399
                                throw new UroborosqlSQLException(ex);
×
400
                        }
1✔
401
                }
1✔
402
        }
1✔
403
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc