1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.shardingsphere.mode.repository.standalone.jdbc;
19
20 import com.google.common.base.Strings;
21 import com.zaxxer.hikari.HikariConfig;
22 import com.zaxxer.hikari.HikariDataSource;
23 import com.zaxxer.hikari.util.PropertyElf;
24 import lombok.SneakyThrows;
25 import lombok.extern.slf4j.Slf4j;
26 import org.apache.shardingsphere.mode.repository.standalone.StandalonePersistRepository;
27 import org.apache.shardingsphere.mode.repository.standalone.jdbc.props.JDBCRepositoryProperties;
28 import org.apache.shardingsphere.mode.repository.standalone.jdbc.props.JDBCRepositoryPropertyKey;
29 import org.apache.shardingsphere.mode.repository.standalone.jdbc.sql.JDBCRepositorySQL;
30 import org.apache.shardingsphere.mode.repository.standalone.jdbc.sql.JDBCRepositorySQLLoader;
31
32 import java.sql.Connection;
33 import java.sql.PreparedStatement;
34 import java.sql.ResultSet;
35 import java.sql.SQLException;
36 import java.sql.Statement;
37 import java.util.ArrayList;
38 import java.util.Arrays;
39 import java.util.Collections;
40 import java.util.Comparator;
41 import java.util.LinkedList;
42 import java.util.List;
43 import java.util.Properties;
44 import java.util.UUID;
45
46
47
48
49 @Slf4j
50 public final class JDBCRepository implements StandalonePersistRepository {
51
52 private static final String SEPARATOR = "/";
53
54 private JDBCRepositorySQL repositorySQL;
55
56 private HikariDataSource dataSource;
57
58 @SneakyThrows(SQLException.class)
59 @Override
60 public void init(final Properties props) {
61 JDBCRepositoryProperties jdbcRepositoryProps = new JDBCRepositoryProperties(props);
62 repositorySQL = JDBCRepositorySQLLoader.load(jdbcRepositoryProps.getValue(JDBCRepositoryPropertyKey.PROVIDER));
63 dataSource = new HikariDataSource(createHikariConfiguration(props, jdbcRepositoryProps));
64 try (
65 Connection connection = dataSource.getConnection();
66 Statement statement = connection.createStatement()) {
67 statement.execute(repositorySQL.getCreateTableSQL());
68
69 if (jdbcRepositoryProps.<String>getValue(JDBCRepositoryPropertyKey.JDBC_URL).contains("h2:mem:")) {
70 try {
71 statement.execute("TRUNCATE TABLE `repository`");
72 } catch (final SQLException ignored) {
73 }
74 }
75
76 }
77 }
78
79 private HikariConfig createHikariConfiguration(final Properties props, final JDBCRepositoryProperties jdbcRepositoryProps) {
80 HikariConfig result = new HikariConfig(copyProperties(props));
81 result.setDriverClassName(repositorySQL.getDriverClassName());
82 result.setJdbcUrl(jdbcRepositoryProps.getValue(JDBCRepositoryPropertyKey.JDBC_URL));
83 result.setUsername(jdbcRepositoryProps.getValue(JDBCRepositoryPropertyKey.USERNAME));
84 result.setPassword(jdbcRepositoryProps.getValue(JDBCRepositoryPropertyKey.PASSWORD));
85 return result;
86 }
87
88 private Properties copyProperties(final Properties props) {
89 Properties result = PropertyElf.copyProperties(props);
90 result.remove(JDBCRepositoryPropertyKey.PROVIDER.getKey());
91 result.remove(JDBCRepositoryPropertyKey.JDBC_URL.getKey());
92 result.remove(JDBCRepositoryPropertyKey.USERNAME.getKey());
93 result.remove(JDBCRepositoryPropertyKey.PASSWORD.getKey());
94 return result;
95 }
96
97 @Override
98 public String query(final String key) {
99 try (
100 Connection connection = dataSource.getConnection();
101 PreparedStatement preparedStatement = connection.prepareStatement(repositorySQL.getSelectByKeySQL())) {
102 preparedStatement.setString(1, key);
103 try (ResultSet resultSet = preparedStatement.executeQuery()) {
104 if (resultSet.next()) {
105 return resultSet.getString("value");
106 }
107 }
108 } catch (final SQLException ex) {
109 log.error("Get {} data by key: {} failed", getType(), key, ex);
110 }
111 return "";
112 }
113
114 @Override
115 public List<String> getChildrenKeys(final String key) {
116 try (
117 Connection connection = dataSource.getConnection();
118 PreparedStatement preparedStatement = connection.prepareStatement(repositorySQL.getSelectByParentKeySQL())) {
119 preparedStatement.setString(1, key);
120 try (ResultSet resultSet = preparedStatement.executeQuery()) {
121 List<String> resultChildren = new LinkedList<>();
122 while (resultSet.next()) {
123 String childrenKey = resultSet.getString("key");
124 if (Strings.isNullOrEmpty(childrenKey)) {
125 continue;
126 }
127 int lastIndexOf = childrenKey.lastIndexOf(SEPARATOR);
128 resultChildren.add(childrenKey.substring(lastIndexOf + 1));
129 }
130 resultChildren.sort(Comparator.reverseOrder());
131 return new ArrayList<>(resultChildren);
132 }
133 } catch (final SQLException ex) {
134 log.error("Get children {} data by key: {} failed", getType(), key, ex);
135 return Collections.emptyList();
136 }
137 }
138
139 @Override
140 public boolean isExisted(final String key) {
141 try (
142 Connection connection = dataSource.getConnection();
143 PreparedStatement preparedStatement = connection.prepareStatement(repositorySQL.getSelectByKeySQL())) {
144 preparedStatement.setString(1, key);
145 try (ResultSet resultSet = preparedStatement.executeQuery()) {
146 return resultSet.next();
147 }
148 } catch (final SQLException ex) {
149 log.error("Check existence of {} data by key: {} failed", getType(), key, ex);
150 }
151 return false;
152 }
153
154 @Override
155 public void persist(final String key, final String value) {
156 try {
157 if (isExisted(key)) {
158 update(key, value);
159 return;
160 }
161 String tempPrefix = "";
162 String parent = SEPARATOR;
163 String[] paths = Arrays.stream(key.split(SEPARATOR)).filter(each -> !Strings.isNullOrEmpty(each)).toArray(String[]::new);
164
165 for (int i = 0; i < paths.length - 1; i++) {
166 String tempKey = tempPrefix + SEPARATOR + paths[i];
167 if (!isExisted(tempKey)) {
168 insert(tempKey, "", parent);
169 }
170 tempPrefix = tempKey;
171 parent = tempKey;
172 }
173 insert(key, value, parent);
174 } catch (final SQLException ex) {
175 log.error("Persist {} data to key: {} failed", getType(), key, ex);
176 }
177 }
178
179 private void insert(final String key, final String value, final String parent) throws SQLException {
180 try (
181 Connection connection = dataSource.getConnection();
182 PreparedStatement preparedStatement = connection.prepareStatement(repositorySQL.getInsertSQL())) {
183 preparedStatement.setString(1, UUID.randomUUID().toString());
184 preparedStatement.setString(2, key);
185 preparedStatement.setString(3, value);
186 preparedStatement.setString(4, parent);
187 preparedStatement.executeUpdate();
188 }
189 }
190
191 @Override
192 public void update(final String key, final String value) {
193 try (
194 Connection connection = dataSource.getConnection();
195 PreparedStatement preparedStatement = connection.prepareStatement(repositorySQL.getUpdateSQL())) {
196 preparedStatement.setString(1, value);
197 preparedStatement.setString(2, key);
198 preparedStatement.executeUpdate();
199 } catch (final SQLException ex) {
200 log.error("Update {} data to key: {} failed", getType(), key, ex);
201 }
202 }
203
204
205
206
207
208
209
210
211 @Override
212 public void delete(final String key) {
213 if (dataSource.isClosed() && dataSource.getJdbcUrl().startsWith("jdbc:h2:mem:")) {
214 return;
215 }
216 try (
217 Connection connection = dataSource.getConnection();
218 PreparedStatement preparedStatement = connection.prepareStatement(repositorySQL.getDeleteSQL())) {
219 preparedStatement.setString(1, key + "%");
220 preparedStatement.executeUpdate();
221 } catch (final SQLException ex) {
222 log.error("Delete {} data by key: {} failed", getType(), key, ex);
223 }
224 }
225
226 @Override
227 public void close() {
228 dataSource.close();
229 }
230
231 @Override
232 public String getType() {
233 return "JDBC";
234 }
235 }