diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/NamedParameterJdbcTemplateConfiguration.java b/dao/src/main/java/org/thingsboard/server/dao/sql/NamedParameterJdbcTemplateConfiguration.java new file mode 100644 index 0000000000..ef8d0ed064 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/NamedParameterJdbcTemplateConfiguration.java @@ -0,0 +1,43 @@ +/** + * Copyright © 2016-2025 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.sql; + +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.stereotype.Component; + +import java.util.concurrent.TimeUnit; + +@Component +@RequiredArgsConstructor +@Slf4j +public class NamedParameterJdbcTemplateConfiguration { + + @Value("${spring.jpa.properties.javax.persistence.query.timeout:30000}") + private int queryTimeout; + + private final NamedParameterJdbcTemplate namedParameterJdbcTemplate; + + @PostConstruct + private void init() { + int timeout = Math.max(1, (int) TimeUnit.MILLISECONDS.toSeconds(queryTimeout)); + log.info("Set jdbcTemplate query timeout [{}] second(s)", timeout); + namedParameterJdbcTemplate.getJdbcTemplate().setQueryTimeout(timeout); + } +} diff --git a/dao/src/test/java/org/thingsboard/server/dao/sql/JdbcTemplateTest.java b/dao/src/test/java/org/thingsboard/server/dao/sql/JdbcTemplateTest.java new file mode 100644 index 0000000000..d0af99021a --- /dev/null +++ b/dao/src/test/java/org/thingsboard/server/dao/sql/JdbcTemplateTest.java @@ -0,0 +1,39 @@ +/** + * Copyright © 2016-2025 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.dao.sql; + +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessResourceFailureException; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.test.context.TestPropertySource; +import org.thingsboard.server.dao.AbstractJpaDaoTest; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +@TestPropertySource(properties = { + "spring.jpa.properties.javax.persistence.query.timeout=500" +}) +public class JdbcTemplateTest extends AbstractJpaDaoTest { + + @Autowired + private NamedParameterJdbcTemplate jdbcTemplate; + + @Test + public void queryTimeoutTest() { + assertThrows(DataAccessResourceFailureException.class, () -> jdbcTemplate.query("SELECT pg_sleep(10)", rs -> {})); + } +}