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