Commit 03631c83b0b6f982c7dcd1f284c12534bf74026f
Committed by
Andrew Shvayka
1 parent
19d103fe
Fixed violations on attributes primary keys constraints (#1909)
* init commit * fix-violation-of-primary-key-constraint * revert thingsboard.yml changes * remove @Slf4j annotation * update code
Showing
7 changed files
with
283 additions
and
10 deletions
1 | +/** | |
2 | + * Copyright © 2016-2019 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.dao.util; | |
17 | + | |
18 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | |
19 | + | |
20 | +@ConditionalOnProperty(prefix = "spring.jpa", value = "database-platform", havingValue = "org.hibernate.dialect.HSQLDialect") | |
21 | +public @interface HsqlDao { | |
22 | +} | |
\ No newline at end of file | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2019 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.dao.util; | |
17 | + | |
18 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | |
19 | + | |
20 | +@ConditionalOnProperty(prefix = "spring.jpa", value = "database-platform", havingValue = "org.hibernate.dialect.PostgreSQLDialect") | |
21 | +public @interface PsqlDao { | |
22 | +} | |
\ No newline at end of file | ... | ... |
... | ... | @@ -16,7 +16,6 @@ |
16 | 16 | package org.thingsboard.server.dao.model.sql; |
17 | 17 | |
18 | 18 | import lombok.Data; |
19 | -import org.thingsboard.server.common.data.EntityType; | |
20 | 19 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
21 | 20 | import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; |
22 | 21 | import org.thingsboard.server.common.data.kv.BooleanDataEntry; |
... | ... | @@ -29,19 +28,11 @@ import org.thingsboard.server.dao.model.ToData; |
29 | 28 | import javax.persistence.Column; |
30 | 29 | import javax.persistence.EmbeddedId; |
31 | 30 | import javax.persistence.Entity; |
32 | -import javax.persistence.EnumType; | |
33 | -import javax.persistence.Enumerated; | |
34 | -import javax.persistence.Id; | |
35 | -import javax.persistence.IdClass; | |
36 | 31 | import javax.persistence.Table; |
37 | 32 | import java.io.Serializable; |
38 | 33 | |
39 | -import static org.thingsboard.server.dao.model.ModelConstants.ATTRIBUTE_KEY_COLUMN; | |
40 | -import static org.thingsboard.server.dao.model.ModelConstants.ATTRIBUTE_TYPE_COLUMN; | |
41 | 34 | import static org.thingsboard.server.dao.model.ModelConstants.BOOLEAN_VALUE_COLUMN; |
42 | 35 | import static org.thingsboard.server.dao.model.ModelConstants.DOUBLE_VALUE_COLUMN; |
43 | -import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_ID_COLUMN; | |
44 | -import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_TYPE_COLUMN; | |
45 | 36 | import static org.thingsboard.server.dao.model.ModelConstants.LAST_UPDATE_TS_COLUMN; |
46 | 37 | import static org.thingsboard.server.dao.model.ModelConstants.LONG_VALUE_COLUMN; |
47 | 38 | import static org.thingsboard.server.dao.model.ModelConstants.STRING_VALUE_COLUMN; | ... | ... |
dao/src/main/java/org/thingsboard/server/dao/sql/attributes/AttributeKvInsertRepository.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2019 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.dao.sql.attributes; | |
17 | + | |
18 | +import lombok.extern.slf4j.Slf4j; | |
19 | +import org.springframework.data.jpa.repository.Modifying; | |
20 | +import org.springframework.stereotype.Repository; | |
21 | +import org.thingsboard.server.dao.model.sql.AttributeKvEntity; | |
22 | +import org.thingsboard.server.dao.util.SqlDao; | |
23 | + | |
24 | +import javax.persistence.EntityManager; | |
25 | +import javax.persistence.PersistenceContext; | |
26 | + | |
27 | +@Slf4j | |
28 | +@SqlDao | |
29 | +@Repository | |
30 | +public abstract class AttributeKvInsertRepository { | |
31 | + | |
32 | + protected static final String BOOL_V = "bool_v"; | |
33 | + protected static final String STR_V = "str_v"; | |
34 | + protected static final String LONG_V = "long_v"; | |
35 | + protected static final String DBL_V = "dbl_v"; | |
36 | + | |
37 | + @PersistenceContext | |
38 | + protected EntityManager entityManager; | |
39 | + | |
40 | + public abstract void saveOrUpdate(AttributeKvEntity entity); | |
41 | + | |
42 | + protected void processSaveOrUpdate(AttributeKvEntity entity, String requestBoolValue, String requestStrValue, String requestLongValue, String requestDblValue) { | |
43 | + if (entity.getBooleanValue() != null) { | |
44 | + saveOrUpdateBoolean(entity, requestBoolValue); | |
45 | + } | |
46 | + if (entity.getStrValue() != null) { | |
47 | + saveOrUpdateString(entity, requestStrValue); | |
48 | + } | |
49 | + if (entity.getLongValue() != null) { | |
50 | + saveOrUpdateLong(entity, requestLongValue); | |
51 | + } | |
52 | + if (entity.getDoubleValue() != null) { | |
53 | + saveOrUpdateDouble(entity, requestDblValue); | |
54 | + } | |
55 | + } | |
56 | + | |
57 | + @Modifying | |
58 | + private void saveOrUpdateBoolean(AttributeKvEntity entity, String query) { | |
59 | + entityManager.createNativeQuery(query) | |
60 | + .setParameter("entity_type", entity.getId().getEntityType().name()) | |
61 | + .setParameter("entity_id", entity.getId().getEntityId()) | |
62 | + .setParameter("attribute_type", entity.getId().getAttributeType()) | |
63 | + .setParameter("attribute_key", entity.getId().getAttributeKey()) | |
64 | + .setParameter("bool_v", entity.getBooleanValue()) | |
65 | + .setParameter("last_update_ts", entity.getLastUpdateTs()) | |
66 | + .executeUpdate(); | |
67 | + } | |
68 | + | |
69 | + @Modifying | |
70 | + private void saveOrUpdateString(AttributeKvEntity entity, String query) { | |
71 | + entityManager.createNativeQuery(query) | |
72 | + .setParameter("entity_type", entity.getId().getEntityType().name()) | |
73 | + .setParameter("entity_id", entity.getId().getEntityId()) | |
74 | + .setParameter("attribute_type", entity.getId().getAttributeType()) | |
75 | + .setParameter("attribute_key", entity.getId().getAttributeKey()) | |
76 | + .setParameter("str_v", entity.getStrValue()) | |
77 | + .setParameter("last_update_ts", entity.getLastUpdateTs()) | |
78 | + .executeUpdate(); | |
79 | + } | |
80 | + | |
81 | + @Modifying | |
82 | + private void saveOrUpdateLong(AttributeKvEntity entity, String query) { | |
83 | + entityManager.createNativeQuery(query) | |
84 | + .setParameter("entity_type", entity.getId().getEntityType().name()) | |
85 | + .setParameter("entity_id", entity.getId().getEntityId()) | |
86 | + .setParameter("attribute_type", entity.getId().getAttributeType()) | |
87 | + .setParameter("attribute_key", entity.getId().getAttributeKey()) | |
88 | + .setParameter("long_v", entity.getLongValue()) | |
89 | + .setParameter("last_update_ts", entity.getLastUpdateTs()) | |
90 | + .executeUpdate(); | |
91 | + } | |
92 | + | |
93 | + @Modifying | |
94 | + private void saveOrUpdateDouble(AttributeKvEntity entity, String query) { | |
95 | + entityManager.createNativeQuery(query) | |
96 | + .setParameter("entity_type", entity.getId().getEntityType().name()) | |
97 | + .setParameter("entity_id", entity.getId().getEntityId()) | |
98 | + .setParameter("attribute_type", entity.getId().getAttributeType()) | |
99 | + .setParameter("attribute_key", entity.getId().getAttributeKey()) | |
100 | + .setParameter("dbl_v", entity.getDoubleValue()) | |
101 | + .setParameter("last_update_ts", entity.getLastUpdateTs()) | |
102 | + .executeUpdate(); | |
103 | + } | |
104 | +} | |
\ No newline at end of file | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2019 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.dao.sql.attributes; | |
17 | + | |
18 | +import lombok.extern.slf4j.Slf4j; | |
19 | +import org.hibernate.exception.ConstraintViolationException; | |
20 | +import org.springframework.beans.factory.annotation.Autowired; | |
21 | +import org.springframework.stereotype.Repository; | |
22 | +import org.springframework.transaction.PlatformTransactionManager; | |
23 | +import org.springframework.transaction.TransactionDefinition; | |
24 | +import org.springframework.transaction.TransactionStatus; | |
25 | +import org.springframework.transaction.support.DefaultTransactionDefinition; | |
26 | +import org.thingsboard.server.common.data.UUIDConverter; | |
27 | +import org.thingsboard.server.dao.model.sql.AttributeKvEntity; | |
28 | +import org.thingsboard.server.dao.util.HsqlDao; | |
29 | +import org.thingsboard.server.dao.util.SqlDao; | |
30 | + | |
31 | +@Slf4j | |
32 | +@SqlDao | |
33 | +@HsqlDao | |
34 | +@Repository | |
35 | +public class HsqlInsertRepository extends AttributeKvInsertRepository { | |
36 | + | |
37 | + @Autowired | |
38 | + private PlatformTransactionManager transactionManager; | |
39 | + | |
40 | + private static final String INSERT_BOOL_STATEMENT = getInsertString(BOOL_V); | |
41 | + private static final String INSERT_STR_STATEMENT = getInsertString(STR_V); | |
42 | + private static final String INSERT_LONG_STATEMENT = getInsertString(LONG_V); | |
43 | + private static final String INSERT_DBL_STATEMENT = getInsertString(DBL_V); | |
44 | + | |
45 | + private static final String WHERE_STATEMENT = " WHERE entity_type = :entity_type AND entity_id = :entity_id AND attribute_type = :attribute_type AND attribute_key = :attribute_key"; | |
46 | + | |
47 | + private static final String UPDATE_BOOL_STATEMENT = getUpdateString(BOOL_V); | |
48 | + private static final String UPDATE_STR_STATEMENT = getUpdateString(STR_V); | |
49 | + private static final String UPDATE_LONG_STATEMENT = getUpdateString(LONG_V); | |
50 | + private static final String UPDATE_DBL_STATEMENT = getUpdateString(DBL_V); | |
51 | + | |
52 | + @Override | |
53 | + public void saveOrUpdate(AttributeKvEntity entity) { | |
54 | + DefaultTransactionDefinition insertDefinition = new DefaultTransactionDefinition(); | |
55 | + insertDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); | |
56 | + TransactionStatus insertTransaction = transactionManager.getTransaction(insertDefinition); | |
57 | + try { | |
58 | + processSaveOrUpdate(entity, INSERT_BOOL_STATEMENT, INSERT_STR_STATEMENT, INSERT_LONG_STATEMENT, INSERT_DBL_STATEMENT); | |
59 | + transactionManager.commit(insertTransaction); | |
60 | + } catch (Throwable e) { | |
61 | + transactionManager.rollback(insertTransaction); | |
62 | + if (e.getCause() instanceof ConstraintViolationException) { | |
63 | + log.trace("Insert request leaded in a violation of a defined integrity constraint {} for Entity with entityId {} and entityType {}", e.getMessage(), UUIDConverter.fromString(entity.getId().getEntityId()), entity.getId().getEntityType()); | |
64 | + DefaultTransactionDefinition definition = new DefaultTransactionDefinition(); | |
65 | + definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); | |
66 | + TransactionStatus transaction = transactionManager.getTransaction(definition); | |
67 | + try { | |
68 | + processSaveOrUpdate(entity, UPDATE_BOOL_STATEMENT, UPDATE_STR_STATEMENT, UPDATE_LONG_STATEMENT, UPDATE_DBL_STATEMENT); | |
69 | + } catch (Throwable th) { | |
70 | + log.trace("Could not execute the update statement for Entity with entityId {} and entityType {}", UUIDConverter.fromString(entity.getId().getEntityId()), entity.getId().getEntityType()); | |
71 | + transactionManager.rollback(transaction); | |
72 | + } | |
73 | + transactionManager.commit(transaction); | |
74 | + } else { | |
75 | + log.trace("Could not execute the insert statement for Entity with entityId {} and entityType {}", UUIDConverter.fromString(entity.getId().getEntityId()), entity.getId().getEntityType()); | |
76 | + } | |
77 | + } | |
78 | + } | |
79 | + | |
80 | + private static String getInsertString(String value) { | |
81 | + return "INSERT INTO attribute_kv (entity_type, entity_id, attribute_type, attribute_key, " + value + ", last_update_ts) VALUES (:entity_type, :entity_id, :attribute_type, :attribute_key, :" + value + ", :last_update_ts)"; | |
82 | + } | |
83 | + | |
84 | + private static String getUpdateString(String value) { | |
85 | + return "UPDATE attribute_kv SET " + value + " = :" + value + ", last_update_ts = :last_update_ts" + WHERE_STATEMENT; | |
86 | + } | |
87 | +} | |
\ No newline at end of file | ... | ... |
... | ... | @@ -47,6 +47,9 @@ public class JpaAttributeDao extends JpaAbstractDaoListeningExecutorService impl |
47 | 47 | @Autowired |
48 | 48 | private AttributeKvRepository attributeKvRepository; |
49 | 49 | |
50 | + @Autowired | |
51 | + private AttributeKvInsertRepository attributeKvInsertRepository; | |
52 | + | |
50 | 53 | @Override |
51 | 54 | public ListenableFuture<Optional<AttributeKvEntry>> find(TenantId tenantId, EntityId entityId, String attributeType, String attributeKey) { |
52 | 55 | AttributeKvCompositeKey compositeKey = |
... | ... | @@ -87,11 +90,12 @@ public class JpaAttributeDao extends JpaAbstractDaoListeningExecutorService impl |
87 | 90 | entity.setLongValue(attribute.getLongValue().orElse(null)); |
88 | 91 | entity.setBooleanValue(attribute.getBooleanValue().orElse(null)); |
89 | 92 | return service.submit(() -> { |
90 | - attributeKvRepository.save(entity); | |
93 | + attributeKvInsertRepository.saveOrUpdate(entity); | |
91 | 94 | return null; |
92 | 95 | }); |
93 | 96 | } |
94 | 97 | |
98 | + | |
95 | 99 | @Override |
96 | 100 | public ListenableFuture<List<Void>> removeAll(TenantId tenantId, EntityId entityId, String attributeType, List<String> keys) { |
97 | 101 | List<AttributeKvEntity> entitiesToDelete = keys | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2019 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.dao.sql.attributes; | |
17 | + | |
18 | +import org.springframework.stereotype.Repository; | |
19 | +import org.springframework.transaction.annotation.Transactional; | |
20 | +import org.thingsboard.server.dao.model.sql.AttributeKvEntity; | |
21 | +import org.thingsboard.server.dao.util.PsqlDao; | |
22 | +import org.thingsboard.server.dao.util.SqlDao; | |
23 | + | |
24 | +@SqlDao | |
25 | +@PsqlDao | |
26 | +@Repository | |
27 | +@Transactional | |
28 | +public class PsqlInsertRepository extends AttributeKvInsertRepository { | |
29 | + | |
30 | + private static final String INSERT_OR_UPDATE_BOOL_STATEMENT = getInsertOrUpdateString(BOOL_V); | |
31 | + private static final String INSERT_OR_UPDATE_STR_STATEMENT = getInsertOrUpdateString(STR_V); | |
32 | + private static final String INSERT_OR_UPDATE_LONG_STATEMENT = getInsertOrUpdateString(LONG_V); | |
33 | + private static final String INSERT_OR_UPDATE_DBL_STATEMENT = getInsertOrUpdateString(DBL_V); | |
34 | + | |
35 | + @Override | |
36 | + public void saveOrUpdate(AttributeKvEntity entity) { | |
37 | + processSaveOrUpdate(entity, INSERT_OR_UPDATE_BOOL_STATEMENT, INSERT_OR_UPDATE_STR_STATEMENT, INSERT_OR_UPDATE_LONG_STATEMENT, INSERT_OR_UPDATE_DBL_STATEMENT); | |
38 | + } | |
39 | + | |
40 | + private static String getInsertOrUpdateString(String value) { | |
41 | + return "INSERT INTO attribute_kv (entity_type, entity_id, attribute_type, attribute_key, " + value + ", last_update_ts) VALUES (:entity_type, :entity_id, :attribute_type, :attribute_key, :" + value + ", :last_update_ts) ON CONFLICT (entity_type, entity_id, attribute_type, attribute_key) DO UPDATE SET " + value + " = :" + value + ", last_update_ts = :last_update_ts"; | |
42 | + } | |
43 | +} | |
\ No newline at end of file | ... | ... |