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

future-architect / uroborosql / #715

pending completion
#715

push

web-flow
merge v0.x changes to master (#310)

* 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

1154 of 1154 new or added lines in 77 files covered. (100.0%)

7721 of 8533 relevant lines covered (90.48%)

0.9 hits per line

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

85.85
/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.List;
16
import java.util.concurrent.ConcurrentHashMap;
17
import java.util.concurrent.ConcurrentMap;
18

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

22
import jp.co.future.uroborosql.config.SqlConfig;
23
import jp.co.future.uroborosql.connection.ConnectionContext;
24
import jp.co.future.uroborosql.context.ExecutionContext;
25
import jp.co.future.uroborosql.exception.UroborosqlSQLException;
26
import jp.co.future.uroborosql.exception.UroborosqlTransactionException;
27

28
/**
29
 * ローカルトランザクションContext
30
 *
31
 * @author ota
32
 */
33
class LocalTransactionContext implements AutoCloseable {
34
        /** ロガー */
35
        private static final Logger LOG = LoggerFactory.getLogger("jp.co.future.uroborosql.log");
1✔
36

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

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

43
        /** SQL設定クラス */
44
        private final SqlConfig sqlConfig;
45

46
        /** コネクション */
47
        private Connection connection;
48

49
        /** ロールバックフラグ */
50
        private boolean rollbackOnly = false;
1✔
51

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

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

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

72
        /**
73
         * コネクションの取得
74
         *
75
         * @return コネクション
76
         * @throws SQLException SQL例外
77
         */
78
        Connection getConnection() throws SQLException {
79
                if (connection == null) {
1✔
80
                        if (connectionContext == null) {
1✔
81
                                connection = this.sqlConfig.getConnectionSupplier().getConnection();
1✔
82
                        } else {
83
                                connection = this.sqlConfig.getConnectionSupplier().getConnection(connectionContext);
1✔
84
                        }
85
                        initSavepoints(connection);
1✔
86
                }
87
                return connection;
1✔
88
        }
89

90
        /**
91
         * ステートメント取得
92
         *
93
         * @param executionContext ExecutionContext
94
         * @return PreparedStatement
95
         * @throws SQLException SQL例外
96
         */
97
        PreparedStatement getPreparedStatement(final ExecutionContext executionContext) throws SQLException {
98
                var conn = getConnection();
1✔
99

100
                PreparedStatement stmt = null;
1✔
101
                switch (executionContext.getSqlKind()) {
1✔
102
                case INSERT:
103
                case BULK_INSERT:
104
                case BATCH_INSERT:
105
                        if (updatable) {
1✔
106
                                if (executionContext.hasGeneratedKeyColumns()) {
1✔
107
                                        stmt = conn.prepareStatement(executionContext.getExecutableSql(),
1✔
108
                                                        executionContext.getGeneratedKeyColumns());
1✔
109
                                } else {
110
                                        stmt = conn.prepareStatement(executionContext.getExecutableSql());
1✔
111
                                }
112
                        } else {
113
                                throw new UroborosqlTransactionException("Transaction not started.");
1✔
114
                        }
115
                        break;
116
                case SELECT:
117
                        stmt = conn.prepareStatement(executionContext.getExecutableSql(),
1✔
118
                                        executionContext.getResultSetType(),
1✔
119
                                        executionContext.getResultSetConcurrency());
1✔
120
                        break;
1✔
121
                default:
122
                        if (updatable) {
1✔
123
                                stmt = conn.prepareStatement(executionContext.getExecutableSql());
1✔
124
                        } else {
125
                                throw new UroborosqlTransactionException("Transaction not started.");
1✔
126
                        }
127
                        break;
128
                }
129
                return this.sqlConfig.getSqlFilterManager().doPreparedStatement(executionContext, stmt);
1✔
130
        }
131

132
        /**
133
         * Callableステートメント初期化
134
         *
135
         * @param executionContext ExecutionContext
136
         * @return CallableStatement
137
         * @throws SQLException SQL例外
138
         */
139
        CallableStatement getCallableStatement(final ExecutionContext executionContext) throws SQLException {
140
                var conn = getConnection();
1✔
141

142
                if (this.updatable) {
1✔
143
                        return this.sqlConfig.getSqlFilterManager().doCallableStatement(executionContext,
1✔
144
                                        conn.prepareCall(executionContext.getExecutableSql(), executionContext.getResultSetType(),
1✔
145
                                                        executionContext.getResultSetConcurrency()));
1✔
146
                } else {
147
                        throw new UroborosqlTransactionException("Transaction not started.");
1✔
148
                }
149
        }
150

151
        /**
152
         * トランザクションのセーブポイントを作成します。
153
         *
154
         * <pre>
155
         *  この処理は{@link Connection#setSavepoint(String)}の処理に依存します。
156
         * </pre>
157
         *
158
         * @param savepointName セーブポイントの名前
159
         * @throws SQLException SQL例外
160
         */
161
        void setSavepoint(final String savepointName) {
162
                if (savepointNames.contains(savepointName)) {
1✔
163
                        throw new IllegalStateException();
×
164
                }
165
                savepointNames.add(savepointName);
1✔
166

167
                if (connection != null) {
1✔
168
                        try {
169
                                savepointMap.put(savepointName, connection.setSavepoint(savepointName));
1✔
170
                        } catch (SQLException e) {
×
171
                                throw new UroborosqlSQLException(e);
×
172
                        }
1✔
173
                }
174
        }
1✔
175

176
        /**
177
         * トランザクションから指定されたセーブポイントと以降のセーブポイントを削除します。
178
         *
179
         * <pre>
180
         *  この処理は{@link Connection#releaseSavepoint(java.sql.Savepoint)}の処理に依存します。
181
         * </pre>
182
         *
183
         * @param savepointName セーブポイントの名前
184
         * @throws SQLException SQL例外
185
         */
186
        void releaseSavepoint(final String savepointName) {
187
                var savepoint = savepointMap.get(savepointName);
1✔
188

189
                var pos = savepointNames.lastIndexOf(savepointName);
1✔
190
                if (pos > -1) {
1✔
191
                        var subList = savepointNames.subList(pos, savepointNames.size());
1✔
192
                        for (var name : subList) {
1✔
193
                                savepointMap.remove(name);
1✔
194
                        }
1✔
195
                        subList.clear();
1✔
196
                }
197

198
                if (savepoint != null && connection != null) {
1✔
199
                        try {
200
                                connection.releaseSavepoint(savepoint);
1✔
201
                        } catch (SQLException e) {
×
202
                                throw new UroborosqlSQLException(e);
×
203
                        }
1✔
204
                }
205
        }
1✔
206

207
        /**
208
         * 指定されたセーブポイントが設定されたあとに行われたすべての変更をロールバックします。
209
         *
210
         * <pre>
211
         *  この処理は{@link Connection#rollback(java.sql.Savepoint)}の処理に依存します。
212
         * </pre>
213
         *
214
         * @param savepointName セーブポイントの名前
215
         * @throws SQLException SQL例外
216
         */
217
        void rollback(final String savepointName) {
218
                if (connection != null) {
1✔
219
                        try {
220
                                connection.rollback(savepointMap.get(savepointName));
1✔
221
                        } catch (SQLException e) {
×
222
                                throw new UroborosqlSQLException(e);
×
223
                        }
1✔
224
                }
225
        }
1✔
226

227
        /**
228
         * 現在のトランザクションをロールバックすることを予約します。
229
         */
230
        void setRollbackOnly() {
231
                this.rollbackOnly = true;
1✔
232
        }
1✔
233

234
        /**
235
         * 現在のトランザクションがロールバック指定になっているかを取得します。
236
         */
237
        boolean isRollbackOnly() {
238
                return rollbackOnly;
1✔
239
        }
240

241
        /**
242
         * トランザクションのコミット
243
         *
244
         * @throws SQLException SQL例外. トランザクションのコミットに失敗した場合
245
         */
246
        void commit() {
247
                try {
248
                        if (connection != null && !connection.isClosed() && !connection.getAutoCommit()) {
1✔
249
                                connection.commit();
1✔
250
                        }
251
                } catch (SQLException e) {
×
252
                        throw new UroborosqlSQLException(e);
×
253
                }
1✔
254
                clearState();
1✔
255
        }
1✔
256

257
        /**
258
         * トランザクションのロールバック
259
         *
260
         * @throws SQLException SQL例外. トランザクションのロールバックに失敗した場合
261
         */
262
        void rollback() {
263
                try {
264
                        if (connection != null && !connection.isClosed() && !connection.getAutoCommit()) {
1✔
265
                                connection.rollback();
1✔
266
                        }
267
                } catch (SQLException e) {
×
268
                        throw new UroborosqlSQLException(e);
×
269
                }
1✔
270
                clearState();
1✔
271
        }
1✔
272

273
        /**
274
         * {@inheritDoc}
275
         *
276
         * @see java.lang.AutoCloseable#close()
277
         */
278
        @Override
279
        public void close() {
280
                try {
281
                        if (!isRollbackOnly()) {
1✔
282
                                commit();
1✔
283
                        } else {
284
                                rollback();
1✔
285
                        }
286
                        if (connection != null && !connection.isClosed()) {
1✔
287
                                connection.close();
1✔
288
                        } else {
289
                                LOG.debug("Connection close was skipped because the connection was already closed.");
1✔
290
                        }
291
                } catch (SQLException e) {
×
292
                        throw new UroborosqlSQLException(e);
×
293
                }
1✔
294
                connection = null;
1✔
295
        }
1✔
296

297
        /**
298
         * ステータスクリア
299
         */
300
        void clearState() {
301
                savepointNames.clear();
1✔
302
                savepointMap.clear();
1✔
303
                rollbackOnly = false;
1✔
304
        }
1✔
305

306
        /**
307
         * Savepointの設定を遅延して行う
308
         *
309
         * @param connection コネクション
310
         * @throws SQLException SQL例外
311
         */
312
        private void initSavepoints(final Connection connection) {
313
                for (var savepointName : savepointNames) {
1✔
314
                        try {
315
                                savepointMap.put(savepointName, connection.setSavepoint(savepointName));
1✔
316
                        } catch (SQLException e) {
×
317
                                throw new UroborosqlSQLException(e);
×
318
                        }
1✔
319
                }
1✔
320
        }
1✔
321

322
}
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