1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.shardingsphere.driver.jdbc.core.statement;
19
20 import lombok.EqualsAndHashCode;
21 import lombok.RequiredArgsConstructor;
22 import org.apache.shardingsphere.driver.jdbc.adapter.executor.ForceExecuteTemplate;
23 import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
24 import org.apache.shardingsphere.infra.executor.sql.context.ExecutionUnit;
25 import org.apache.shardingsphere.infra.executor.sql.execute.engine.ConnectionMode;
26 import org.apache.shardingsphere.infra.executor.sql.prepare.driver.jdbc.ExecutorJDBCStatementManager;
27 import org.apache.shardingsphere.infra.executor.sql.prepare.driver.jdbc.StatementOption;
28
29 import java.sql.Connection;
30 import java.sql.PreparedStatement;
31 import java.sql.SQLException;
32 import java.sql.SQLFeatureNotSupportedException;
33 import java.sql.Statement;
34 import java.util.Map;
35 import java.util.Optional;
36 import java.util.concurrent.ConcurrentHashMap;
37
38
39
40
41 public final class StatementManager implements ExecutorJDBCStatementManager, AutoCloseable {
42
43 private final Map<CacheKey, Statement> cachedStatements = new ConcurrentHashMap<>();
44
45 private final ForceExecuteTemplate<Statement> forceExecuteTemplate = new ForceExecuteTemplate<>();
46
47 @Override
48 public Statement createStorageResource(final Connection connection, final ConnectionMode connectionMode, final StatementOption option, final DatabaseType databaseType) throws SQLException {
49 return createStatement(connection, option);
50 }
51
52 @Override
53 public Statement createStorageResource(final ExecutionUnit executionUnit, final Connection connection, final int connectionOffset,
54 final ConnectionMode connectionMode, final StatementOption option, final DatabaseType databaseType) throws SQLException {
55 CacheKey cacheKey = new CacheKey(executionUnit, connectionMode, connectionOffset);
56 Statement result = cachedStatements.get(cacheKey);
57 if (null == result || result.getConnection().isClosed() || result.isClosed()) {
58 Optional.ofNullable(result).ifPresent(optional -> cachedStatements.remove(cacheKey));
59 result = prepareStatement(executionUnit, connection, option);
60 cachedStatements.put(cacheKey, result);
61 }
62 return result;
63 }
64
65 @SuppressWarnings("MagicConstant")
66 private Statement createStatement(final Connection connection, final StatementOption option) throws SQLException {
67 Statement result;
68 try {
69 result = connection.createStatement(option.getResultSetType(), option.getResultSetConcurrency(), option.getResultSetHoldability());
70 } catch (final SQLFeatureNotSupportedException ignore) {
71 result = connection.createStatement();
72 }
73 return result;
74 }
75
76 private PreparedStatement prepareStatement(final ExecutionUnit executionUnit, final Connection connection, final StatementOption option) throws SQLException {
77 PreparedStatement result;
78 String sql = executionUnit.getSqlUnit().getSql();
79 if (option.isReturnGeneratedKeys()) {
80 result = null == option.getColumns() || 0 == option.getColumns().length
81 ? connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)
82 : connection.prepareStatement(sql, option.getColumns());
83 } else {
84 result = prepareStatement(connection, sql, option.getResultSetType(), option.getResultSetConcurrency(), option.getResultSetHoldability());
85 }
86 return result;
87 }
88
89 private PreparedStatement prepareStatement(final Connection connection, final String sql, final int resultSetType, final int resultSetConcurrency,
90 final int resultSetHoldability) throws SQLException {
91 PreparedStatement result;
92 try {
93 result = connection.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
94 } catch (final SQLFeatureNotSupportedException ignore) {
95 result = connection.prepareStatement(sql);
96 }
97 return result;
98 }
99
100 @Override
101 public void close() throws SQLException {
102 try {
103 forceExecuteTemplate.execute(cachedStatements.values(), Statement::close);
104 } finally {
105 cachedStatements.clear();
106 }
107 }
108
109 @RequiredArgsConstructor
110 @EqualsAndHashCode
111 private static final class CacheKey {
112
113 private final ExecutionUnit executionUnit;
114
115 private final ConnectionMode connectionMode;
116
117 private final int connectionOffset;
118 }
119 }