Commit 03631c83b0b6f982c7dcd1f284c12534bf74026f

Authored by ShvaykaD
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
  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;
... ...
  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
... ...