Какую ошибку возвращает spring если бд недоступна
Перейти к содержимому

Какую ошибку возвращает spring если бд недоступна

  • автор:

Ошибка при подключении базы данных через Spring Boot

Добавил в gradle проект runtimeOnly mysql:mysql-connector-java и org.springframework.boot:spring-boot-starter-data-jpa И теперь после сборки выдаёт следующие ошибки :

Caused by: org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment] Caused by: org.hibernate.HibernateException: Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set 

Вот код:

package com.example.MySpringFrame; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class MySpringFrameApplication < public static void main(String[] args) < SpringApplication.run(MySpringFrameApplication.class, args); >> 
package com.example.MySpringFrame.controller; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/users") public class UserController < @GetMapping("/") public ResponseEntity getUsers()< try< return ResponseEntity.ok("Сервер работает!"); >catch (Exception e) < return ResponseEntity.badRequest().body("Произошла ошибка"); >> > 

и мой application.properties :

spring.jpa.hibernate.ddl-auto=update spring.datasource.url=jdbc:mysql://localhost:3306/my_base?useUnicode=true&useSSL=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC spring.datasource.username=root spring.datasource.password=root 

Указанная база данных создана но выдаёт данную ошибку и я не понимаю почему.

10 самых распространенных ошибок Spring Framework

Привет, Хабр! Представляю вашему вниманию перевод статьи «Top 10 Most Common Spring Framework Mistakes» автора Toni Kukurin.

Spring, вероятно, один из самых популярных Java-фреймворков, а также могучий зверь для укрощения. Хотя его базовые концепции довольно легко понять, для того, чтобы стать сильным Spring разработчиком, нужно время и усилия.

В этой статье мы рассмотрим некоторые из наиболее распространенных ошибок в Spring, особенно касающихся веб-приложений и Spring Boot. Как говорится на сайте Spring Boot, он навязывает представление о том, как должны быть построены промышленные приложения, поэтому в этой статье мы попытаемся продемонстрировать это представление и дать обзор некоторых советов, которые хорошо вольются в стандартный процесс разработки веб-приложений на Spring Boot.
Если вы не очень хорошо знакомы со Spring Boot, но все же хотели бы попробовать некоторые из упомянутых вещей, я создал репозиторий GitHub, сопровождающий эту статью. Если в любом месте статьи вы почувствуете что потерялись, я рекомендую склонировать репозиторий на локальный компьютер и поиграть с кодом.

Распространенная ошибка №1: спускаться на слишком низкий уровень

Мы сталкиваемся с этой распространенной ошибкой, потому что синдром ”изобретено за границей (not invented here)» — довольно распространен в мире разработки программного обеспечения. Симптомы включают в себя регулярное переписывание фрагментов часто используемого кода, и многие разработчики, похоже, страдают этим.

Хотя понимание внутренностей конкретной библиотеки и ее реализации по большей части хорошо и необходимо (и может быть отличным процессом обучения), но постоянно решать одни и те же низкоуровневые детали реализации — вредно для вашего развития как инженера-программиста. Есть причина, по которой существуют абстракции и фреймворки, такие как Spring, строго отделяющие вас от повторяющейся ручной работы и позволяющие сосредоточиться на деталях более высокого уровня — ваших доменных объектах и бизнес-логике.

Поэтому пользуйтесь абстракциями — в следующий раз, когда вы столкнетесь с конкретной проблемой, сначала выполните быстрый поиск и определите, интегрирована ли библиотека, решающая эту проблему, в Spring. В настоящее время вы, скорее всего, найдете существующее подходящее решение. Как пример полезной библиотеки, в примерах остальной части этой статьи я буду использовать аннотации проекта Lombok. Lombok используется в качестве генератора шаблонного кода и ленивый разработчик внутри вас, надеюсь, не должен иметь проблем с представлением об этой библиотеке. В качестве примера, посмотрите, как выглядит «стандартный Java бин» с Ломбоком:

@Getter @Setter @NoArgsConstructor public class Bean implements Serializable

Как вы можете себе представить, приведенный выше код компилируется в:

public class Bean implements Serializable < private int firstBeanProperty; private String secondBeanProperty; public int getFirstBeanProperty() < return this.firstBeanProperty; >public String getSecondBeanProperty() < return this.secondBeanProperty; >public void setFirstBeanProperty(int firstBeanProperty) < this.firstBeanProperty = firstBeanProperty; >public void setSecondBeanProperty(String secondBeanProperty) < this.secondBeanProperty = secondBeanProperty; >public Bean() < >>

Однако обратите внимание, что вам, скорее всего, придется установить плагин, если вы собираетесь использовать Lombok с вашей IDE. Версию плагина для IntelliJ IDEA можно найти здесь.

Распространенная ошибка №2: «утечка» внутреннего содержимого

Раскрытие вашей внутренней структуры — это всегда плохая идея, потому что создает негибкость в дизайне сервиса и, следовательно, способствует плохой практике кодирования. «Утечка» внутреннего содержимого проявляется в том, что структура базы данных доступна с определенных эндпоинтов API. В качестве примера предположим, что следующий POJO (”Plain Old Java Object») представляет таблицу в вашей базе данных:

@Entity @NoArgsConstructor @Getter public class TopTalentEntity < @Id @GeneratedValue private Integer id; @Column private String name; public TopTalentEntity(String name) < this.name = name; >>

Предположим, существует эндпоинт, который должен получить доступ к данным TopTalentEntity. Как бы ни было заманчиво возвращать экземпляры TopTalentEntity, более гибким решением было бы создание нового класса для отображения данных TopTalentEntity на эндпоинте API:

@AllArgsConstructor @NoArgsConstructor @Getter public class TopTalentData

Таким образом, внесение изменений в бэкенд базы данных не потребует каких-либо дополнительных изменений в слое сервиса. Подумайте, что произойдет в случае добавления поля «пароль» в TopTalentEntity для хранения хэшей паролей пользователей в базе данных — без соединителя, такого как TopTalentData, если забыть изменить сервис, фронтенд случайно покажет какую-нибудь очень нежелательную секретную информацию!

Распространенная ошибка №3: отсутствие разделения обязанностей

По мере роста вашего приложения организация кода становится все более важным вопросом. По иронии судьбы, большинство хороших принципов разработки программного обеспечения начинают повсеместно нарушаться – особенно в тех случаях, когда мало внимания уделяется проектированию архитектуры приложений. Одна из наиболее распространенных ошибок, с которыми сталкиваются разработчики — это смешивание обязанностей кода, и это очень легко сделать!

Что обычно нарушает принцип разделения обязанностей, так это просто «добавление» новой функциональности в существующие классы. Это, конечно, отличное краткосрочное решение (для начала, оно требует меньше набора текста), но оно неизбежно станет проблемой в будущем, будь то во время тестирования, сопровождения или где-то между ними. Рассмотрим следующий контроллер, который возвращает TopTalentData из своего репозитория:

@RestController public class TopTalentController < private final TopTalentRepository topTalentRepository; @RequestMapping("/toptal/get") public ListgetTopTalent() < return topTalentRepository.findAll() .stream() .map(this::entityToData) .collect(Collectors.toList()); >private TopTalentData entityToData(TopTalentEntity topTalentEntity) < return new TopTalentData(topTalentEntity.getName()); >>

Сначала не заметно, что с этим фрагментом кода что-то не так. Он предоставляет список TopTalentData, который извлекается из экземпляров TopTalentEntity. Однако, если присмотреться, мы увидим, что на самом деле TopTalentController выполняет здесь несколько вещей. А именно: он маппит запросы на конкретный эндпоинт, извлекает данные из репозитория и преобразует сущности, полученные из TopTalentRepository, в другой формат. «Более чистым» решением было бы разделение этих обязанностей по их собственным классам. Это может выглядеть примерно так:

@RestController @RequestMapping("/toptal") @AllArgsConstructor public class TopTalentController < private final TopTalentService topTalentService; @RequestMapping("/get") public ListgetTopTalent() < return topTalentService.getTopTalent(); >> @AllArgsConstructor @Service public class TopTalentService < private final TopTalentRepository topTalentRepository; private final TopTalentEntityConverter topTalentEntityConverter; public ListgetTopTalent() < return topTalentRepository.findAll() .stream() .map(topTalentEntityConverter::toResponse) .collect(Collectors.toList()); >> @Component public class TopTalentEntityConverter < public TopTalentData toResponse(TopTalentEntity topTalentEntity) < return new TopTalentData(topTalentEntity.getName()); >>

Дополнительным преимуществом этой иерархии является то, что она позволяет нам определить, где находится функциональность, просто проверяя имя класса. Кроме того, во время тестирования мы можем легко заменить любой из классов мок-реализацией, если возникнет такая необходимость.

Распространенная ошибка №4: несогласованность (Inconsistency) и плохая обработка ошибок

Тема обеспечения согласованности не обязательно является эксклюзивной для Spring (или Java, если на то пошло), но все же является важным аспектом, который следует учитывать при работе над проектами Spring. В то время как стиль написания кода может быть предметом обсуждения (и обычно это вопрос соглашения в команде или в рамках всей компании), наличие общего стандарта оказывается большим подспорьем в производительности. Это особенно верно для команд из нескольких человек. Согласованность позволяет осуществлять передачу кода без больших затрат ресурсов на сопровождение или предоставление подробных объяснений относительно обязанностей различных классов.

Рассмотрим проект Spring с различными файлами конфигурации, сервисами и контроллерами. Будучи семантически последовательными в их именовании, создается легко доступная для поиска структура, в которой любой новый разработчик может управлять способами работы с кодом: например, добавляется суффикс Config к классам конфигурации, суффикс Service к сервисам и суффикс Controller к контроллерам.

Тесно связанная с темой согласованности, обработка ошибок на стороне сервера заслуживает особого внимания. Если вам когда-либо приходилось обрабатывать ответы-исключения из плохо написанного API, вы, вероятно, знаете, почему может быть болезненно правильно парсить исключения, а еще сложнее определить причину, по которой эти исключения возникли первоначально.

Как разработчик API, вы в идеале хотите охватить все пользовательские эндпоинты и перевести их на общий формат ошибок. Это обычно означает, что у вас есть общий код ошибки и описание, а не просто отмазка в виде: a) возврат сообщения “500 Internal Server Error” или b) просто сброс стэктрейса пользователю (чего следует избегать любой ценой, поскольку он показывает ваши внутренности в дополнение к сложности обработки на стороне клиента).
Примером распространенного формата ответа на ошибку может быть:

@Value public class ErrorResponse

Нечто подобное обычно встречается в большинстве популярных API и, как правило, хорошо работает, поскольку это можно легко и систематически документировать. Перевод исключений в этот формат можно выполнить, предоставив методу аннотацию @ExceptionHandler (пример аннотации приведен в Распространенной Ошибке №6).

Распространенная ошибка №5: неправильная работа с многопоточностью

Независимо от того, встречается ли она в десктопных или веб-приложениях, в Spring или не в Spring, многопоточность может оказаться непростой для решения задачей. Проблемы, вызванные параллельным выполнением программ, являются до нервозности неуловимыми и зачастую чрезвычайно сложными для отладки — фактически, из-за природы проблемы, как только вы понимаете, что имеете дело с проблемой параллельного выполнения, вам, вероятно, следует полностью отказаться от отладчика и начать проверять свой код «вручную», пока не найдете причину ошибки. К сожалению, для решения таких проблем не существует шаблонного решения. В зависимости от конкретного случая вам придется оценить ситуацию, а затем атаковать проблему под углом, который вы считаете наилучшим.

В идеале вам, конечно же, хотелось бы полностью избежать багов, связанных с многопоточностью. Опять же, для этого не существует единого подхода, но приведем некоторые практические соображения для отладки и предотвращения ошибок многопоточности:

Избегайте глобального состояния

Во-первых, всегда помните о проблеме “глобального состояния”. Если вы создаете многопоточное приложение, абсолютно все, что можно изменить глобально, должно быть тщательно отслежено и, если это возможно, полностью удалено. Если есть причина, по которой глобальная переменная должна оставаться изменяемой, тщательно используйте синхронизацию и отслеживайте производительность вашего приложения, чтобы подтвердить, что оно не замедляется из-за новых периодов ожидания.

Избегайте изменчивости (Mutability)

Это следует прямо из функционального программирования и, в соответствии с ООП, гласит, что следует избегать изменчивости класса и изменения состояния. Вкратце, вышесказанное означает наличие сеттеров и приватных финальных полей во всех классах модели. Их значения меняются только во время конструирования. Таким образом, вы можете быть уверены, что проблем гонки за ресурсы не возникнет и что обращение к свойствам объекта будет всегда обеспечивать правильные значения.

Логгируйте критические данные

Оцените, где ваше приложение может вызвать проблемы, и заранее логгируйте все важные данные. Если произойдет ошибка, вы будете благодарны за информацию о том, какие запросы были получены и сможете лучше понять, почему ваше приложение плохо себя ведет. Опять же необходимо отметить, что логгирование увеличивает файловый ввод-вывод, поэтому не следует им злоупотреблять, поскольку это может серьезно повлиять на производительность вашего приложения.

Переиспользуйте существующие реализации

Всякий раз, когда вам нужно создать свои собственные потоки (например, для выполнения асинхронных запросов к различным службам), переиспользуйте существующие безопасные реализации, а не создавайте свои собственные решения. По большей части это будет означать использование ExecutorServices и CompletableFutures в аккуратном функциональном стиле Java 8 для создания потоков. Spring также позволяет осуществлять асинхронную обработку запросов через класс DeferredResult.

Распространенная ошибка № 6: неиспользование валидации на основе аннотаций

Давайте представим, что нашему сервису TopTalent, упомянутому выше, требуется эндпоинт для добавления новых Супер Талантов. Кроме того, допустим, что по какой-то действительно веской причине каждое новое имя должно быть длиной ровно 10 символов. Один из способов сделать это может быть следующим:

@RequestMapping("/put") public void addTopTalent(@RequestBody TopTalentData topTalentData) < boolean nameNonExistentOrHasInvalidLength = Optional.ofNullable(topTalentData) .map(TopTalentData::getName) .map(name ->name.length() == 10) .orElse(true); if (nameNonExistentOrInvalidLength) < // throw some exception >topTalentService.addTopTalent(topTalentData); >

Однако вышеизложенное (в дополнение к тому, что оно плохо сконструировано) на самом деле не является «чистым» решением. Мы проверяем более одного типа валидности (а именно, что TopTalentData не null, и что TopTalentData.name не null, и что TopTalentData.name имеет длину 10 символов), а также бросает исключение, если данные недействительны.

Это можно сделать гораздо более чисто, используя Hibernate validator со Spring. Сначала перепишем метод addTopTalent для поддержки валидации:

@RequestMapping("/put") public void addTopTalent(@Valid @NotNull @RequestBody TopTalentData topTalentData) < topTalentService.addTopTalent(topTalentData); >@ExceptionHandler @ResponseStatus(HttpStatus.BAD_REQUEST) public ErrorResponse handleInvalidTopTalentDataException(MethodArgumentNotValidException methodArgumentNotValidException) < // handle validation exception >

Кроме того, мы должны указать, какое свойство мы хотим проверить в классе TopTalentData:

public class TopTalentData

Теперь Spring перехватит запрос и проверит его перед вызовом метода – нет необходимости использовать дополнительные ручные тесты.

Другой способ, которым мы могли бы достичь того же — это создание собственных аннотаций. Хотя обычно пользовательские аннотации используются только тогда, когда ваши потребности превышают встроенный набор констрейнов Hibernate, для этого примера давайте представим, что аннотации Length не существует. Вы должны создать валидатор, который проверяет длину строки, создав два дополнительных класса, один для проверки, а другой для аннотирования свойств:

@Target() @Retention(RetentionPolicy.RUNTIME) @Documented @Constraint(validatedBy = < MyAnnotationValidator.class >) public @interface MyAnnotation < String message() default "String length does not match expected"; Class[] groups() default <>; Class[] payload() default <>; int value(); > @Component public class MyAnnotationValidator implements ConstraintValidator  < private int expectedLength; @Override public void initialize(MyAnnotation myAnnotation) < this.expectedLength = myAnnotation.value(); >@Override public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) < return s == null || s.length() == this.expectedLength; >>

Обратите внимание, что в этих случаях лучшие практики по разделению обязанностей требуют, чтобы вы отметили свойство как валидное, если оно равно null (s == null в методе isValid), а затем использовали аннотацию NotNull, если это является дополнительным требованием для свойства:

public class TopTalentData

Распространенная ошибка № 7: использование (все ещё) XML-конфигурации

Хотя XML был необходим для предыдущих версий Spring, в настоящее время большая часть конфигурации может быть выполнена исключительно с помощью кода Java / аннотаций. Конфигурации XML просто представляют собой дополнительный и ненужный бойлерплейт.
Эта статья (а также сопровождающий ее репозиторий GitHub) использует аннотации для конфигурирования Spring и Spring знает, какие бины он должен подключить, потому что корневой пакет был аннотирован с помощью составной аннотации @SpringBootApplication, например:

@SpringBootApplication public class Application < public static void main(String[] args) < SpringApplication.run(Application.class, args); >>

Эта составная аннотация (вы можете узнать больше о ней в документации Spring) просто дает Spring подсказку о том, какие пакеты должны быть просканированы для извлечения бинов. В нашем конкретном случае это означает, что для подключения бинов будут использоваться следующие классы, начиная с пакета верхнего уровня (co.kukurin):

  • @Component (TopTalentConverter, MyAnnotationValidator)
  • @RestController (TopTalentController)
  • @Repository (TopTalentRepository)
  • @Service (TopTalentService)

Распространенная ошибка № 8: забывать о профилях

Проблема, с которой часто сталкиваются при разработке серверов, заключается в различии между различными типами конфигурации, обычно это промышленная и девелоперская конфигурации. Вместо того чтобы вручную заменять различные конфигурационные параметры при каждом переходе от тестирования к развертыванию приложения, более эффективным способом было бы использование профилей.

Рассмотрим случай, когда вы используете in-memory базу данных для локальной разработки и базу данных MySQL в ПРОМе. По сути, это будет означать, что вы будете использовать разные URL и (надеюсь) разные учетные данные для доступа к каждой из них. Давайте посмотрим, как это можно сделать двумя разными конфигурационными файлами:

ФАЙЛ APPLICATION.YAML
# set default profile to 'dev' spring.profiles.active: dev # production database details spring.datasource.url: 'jdbc:mysql://localhost:3306/toptal' spring.datasource.username: root spring.datasource.password:
ФАЙЛ APPLICATION-DEV.YAML
spring.datasource.url: 'jdbc:h2:mem:' spring.datasource.platform: h2

По-видимому, вы не хотите случайно выполнить какие-либо действия на своей промышленной базе данных пока вы возитесь с кодом, поэтому имеет смысл установить профиль по умолчанию в dev. Затем на сервере можно вручную переопределить профиль конфигурации, указав параметр -Dspring.profiles.active=prod для JVM. Кроме того, вы также можете установить переменную среды ОС в нужный профиль по умолчанию.

Распространенная ошибка №9: неспособность принять инъекцию зависимостей

Правильное использование внедрения зависимостей в Spring означает, что он позволяет связывать все ваши объекты вместе путем сканирования всех требуемых классов конфигурации; это оказывается полезным для расцепления (decoupling) связей, а также значительно облегчает тестирование. Вместо жесткой связи классов, сделав что-то вроде этого:

public class TopTalentController < private final TopTalentService topTalentService; public TopTalentController() < this.topTalentService = new TopTalentService(); >>

Мы позволяем Spring сделать для нас связывание:

public class TopTalentController < private final TopTalentService topTalentService; public TopTalentController(TopTalentService topTalentService) < this.topTalentService = topTalentService; >>

Misko Hevery в Google talk подробно объясняет «причины» внедрения зависимости, поэтому давайте вместо этого посмотрим, как это используется на практике. В разделе о разделении обязанностей (Распространенные Ошибки №3) мы создали классы сервиса и контроллера. Допустим, мы хотим протестировать контроллер в предположении, что TopTalentService ведет себя правильно. Мы можем вставить мок-объект вместо фактической реализации сервиса, предоставив отдельный класс конфигурации:

@Configuration public class SampleUnitTestConfig < @Bean public TopTalentService topTalentService() < TopTalentService topTalentService = Mockito.mock(TopTalentService.class); Mockito.when(topTalentService.getTopTalent()).thenReturn( Stream.of("Mary", "Joel") .map(TopTalentData::new).collect(Collectors.toList())); return topTalentService; >>

Затем мы можем внедрить мок-объект, сказав Spring использовать SampleUnitTestConfig в качестве поставщика конфигурации:

@ContextConfiguration(classes = < SampleUnitTestConfig.class >)

Потом это позволит нам использовать конфигурацию контектса для внедрения пользовательского бина в юнит-тест.

Распространенная ошибка № 10: отсутствие тестирования или неправильное тестирование

Несмотря на то, что идея юнит-тестирования с нами уже давно, многие разработчики, похоже, «забывают» сделать это (особенно если это не обязательно), или просто оставляют его на потом. Очевидно, что это нежелательно, поскольку тесты должны не только проверять правильность вашего кода, но и служить документацией о том, как приложение должно вести себя в разных ситуациях.

При тестировании web-сервисов, вы редко делаете исключительно «чистые» юнит-тесты, так как взаимодействие через HTTP, как правило, требует вызвать DispatcherServlet Spring’а и посмотреть, что происходит, когда получен фактический HttpServletRequest (что делает его интеграционным тестом, с использованием валидации, сериализации и т.д.). REST Assured — Java DSL для легкого тестирования REST-сервисов поверх MockMVC оказался очень элегантным решением. Рассмотрим следующий фрагмент кода с инъекцией зависимостей:

@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = < Application.class, SampleUnitTestConfig.class >) public class RestAssuredTestDemonstration < @Autowired private TopTalentController topTalentController; @Test public void shouldGetMaryAndJoel() throws Exception < // given MockMvcRequestSpecification givenRestAssuredSpecification = RestAssuredMockMvc.given() .standaloneSetup(topTalentController); // when MockMvcResponse response = givenRestAssuredSpecification.when().get("/toptal/get"); // then response.then().statusCode(200); response.then().body("name", hasItems("Mary", "Joel")); >>

SampleUnitTestConfig подключает мок-реализацию TopTalentService в TopTalentController, в то время как все другие классы связываются с использованием стандартной конфигурации, полученной путем сканирования пакетов, имеющих корни в пакете класса Application. RestAssuredMockMvc просто используется для создания легковесной среды и отправки GET запроса в эндпоинт /toptal/get.

Стать мастером Spring

Spring — это мощный фреймворк, с которым легко начать работу, но который требует некоторой самоотдачи и времени для достижения полного мастерства. Если вы потратите время на знакомство с фреймворком, это, безусловно, повысит вашу производительность в долгосрочной перспективе и в конечном итоге поможет вам писать более чистый код и стать лучшим разработчиком.

Если вы ищете дополнительные ресурсы, Spring In Action — это хорошая практическая книга, охватывающая многие темы core Spring.

ТЕГИ
Java SpringFramework

Комментарии

Timothy Schimandle
На №2 я думаю, что возвращение доменного объекта является предпочтительным в большинстве случаев. Ваш пример пользовательского объекта — один из нескольких классов, в которых есть поля, которые мы хотим скрыть. Но подавляющее большинство объектов, с которыми я работал, не имеют такого ограничения, и добавление класса dto — просто ненужный код.
В целом хорошая статья. Хорошая работа.

SPIRITED to Timothy Schimandle
Я вполне согласен. Похоже, что добавлен ненужный дополнительный слой кода, я думаю, что @JsonIgnore поможет игнорировать поля (хотя и с недостатками стратегий обнаружения репозитория по умолчанию), но в целом это отличный пост в блоге. Горд, что наткнулся…

Arokiadoss Asirvatham
Чувак, Еще одна распространенная ошибка начинающих: 1) Циклическая Зависимость и 2) несоблюдение основных доктрин объявления Класса Singleton, таких как использование переменной экземпляра в бинах с областью видимости singleton.

Hlodowig
Относительно №8, я считаю, что подходы к профилям очень неудовлетворительные. Давайте посмотрим:

  • Безопасность: некоторые люди говорят: если бы ваш репозиторий был общедоступным, открылись бы какие-нибудь секретные ключи / пароли? Скорее всего, так и будет, следуя такому подходу. Если, конечно, вы не добавите файлы config в .gitignore, но это не серьезный вариант.
  • Дублирование: каждый раз, когда у меня разные настройки, мне нужно создать новый файл свойств, что довольно раздражает.
  • Переносимость: я знаю, что это всего лишь один аргумент JVM, но ноль лучше, чем один. Бесконечно меньше подвержено ошибкам.

Отличная статья Тони, продолжай в том же духе!

Перевод выполнен: tele.gg/middle_java

Spring — это не страшно, или как задать вопрос БД

Java-университет

СОДЕРЖАНИЕ ЦИКЛА СТАТЕЙ Сегодня мы доразбираем работу с базой в рамках нашего проекта. Если вы все делали правильно, то у вас должен быть pom вот с такими зависимостями:

  1.8 1.8 1.8  org.springframework.boot spring-boot-starter-parent 2.2.0.RELEASE   org.springframework.boot spring-boot-starter-web  org.springframework.boot spring-boot-starter-data-jpa  com.h2database h2  org.projectlombok lombok   

Spring — это не страшно, или как задать вопрос БД - 1

И вот такая структура проекта: Знаете кого мы давно не вспоминали? Это application.yml, мы поговорили не много о нем в одной из прошлых статей. А теперь давайте возьмем и удалим его! Да, да delete и все! Если мы запустим сейчас проект, то все будет работать как и раньше, попробуйте это сделать. Это произошло по тому, что Spring сам сконфигурировался на дефолных настройках. Теперь надо вернуть наш ямл файл обратно в папку ресурсы, он нам еще пригодиться: application.yml (наименование должно быть таким же)

 spring: datasource: driverClassName: org.h2.Driver url: jdbc:h2:mem:test; username: sa password: h2: console: enabled: true jpa: hibernate.ddl-auto: create generate-ddl: true show-sql: false properties: hibernate: dialect: org.hibernate.dialect.H2Dialect 

В прошлый раз мы с помощью методов интерфейса JpaRepository<> реализовали несколько запросов к базе:

 //сохранить одну запись в таблицу фруктов public void save(FruitEntity fruitEntity) < fruitRepository.save(fruitEntity); >//получить все записи из таблицы фруктов public List getAll() < return fruitRepository.findAll(); >//сохранить несколько записей в таблицу фруктов public void saveAll(List fruits)

Если вы почитали про SQL, как я вас просил в прошлый раз, то вы должны знать, что такие действия с БД должны выполняться с помощью запросов SQL . Но в проекте на это нет и намека, даже в логах консоли нет ни чего похожего. Давайте их найдем, открываем application.yml, находим там срочку show-sql: (показать sql) и меняем false на true. Запускаем проект и смотрим в консоль, логи наполнились новыми записями очень похожими на SQL, на самом деле большинство из них понять не мудрено, например:

 Hibernate: drop table fruit_table if exists //удалить таблицу fruit_table если она есть Hibernate: drop table provider_table if exists Hibernate: create table fruit_table (id_fruit integer not null, fruit_name varchar(255), provider_code integer, primary key (id_fruit))//создать таблицу fruit_table с полями id_fruit тип integer not null, fruit_name тип varchar(255), provider_code тип integer, назначить первичным ключем поле id_fruit Hibernate: create table provider_table (id_provider integer not null, provider_name varchar(255), primary key (id_provider)) 

Но вот эта запись, может вызвать много вопросов из-за своих знаков вопросов:

 Hibernate: insert into fruit_table (fruit_name, provider_code, id_fruit) values (?, ?, ?) 

Давайте мыслить логически: Во-первых мы видим слово Hibernate, значит этот скрытный парень приложил тут свою мохнатую лапу. Прочитав про него в интернете, мы узнаем, что мистер Hiber это реализация ORM-модели. Объектно-реляционная модель описывает отношения между программными объектами и записями в БД. Зафиксировали эту мысль, продолжаем мыслить логически: С одной стороны, у нас есть объект FruitEntity у него есть три поля: Integer id; String fruitName; Integer providerCode. С другой стороны, у нас есть таблица в БД fruit_table с полями id_fruit тип integer, fruit_name тип varchar(255), provider_code тип integer. Грубо говоря Hibernate берет объект FruitEntity, вытаскивает значения полей объекта и записывает их в соответствующие поля таблицы. У меня к вам вопрос: Смотрите, в классе InitiateUtils мы реализовали заполнение таблицы фруктов, но почему то мы тут задали значение только двум полям, где третье?

 new FruitEntity() .setFruitName("Fruit1")//раз .setProviderCode(Math.abs(new Random().nextInt() % 10)),//два //три. 

Уверен вы разберетесь в этом сами, к тому же мы мельком касались этого вопроса в позапрошлой статье. Для начала разберитесь какого поля тут нет, а дальше вы все поймете. Ну что ж, Hiber молодец, нагенерировал за нас кучу запросов. Но и мы не лыком шиты, давайте в классе FruitService реализуем еще несколько методов из интерфейса JpaRepository<>

 //возвращает запись из таблицы по id public Optional getById(Integer id) < return fruitRepository.findById(id); >//удаляет запись из таблицы по id public void delById(Integer id) < fruitRepository.deleteById(id); >//возвращает true или false при поиске в таблице Фруктов объекта который соответствует типу FruitEntity или принадлежит к типу объекта который наследуется от FruitEntity public Boolean exist(Example example)

Spring — это не страшно, или как задать вопрос БД - 2

Реализуйте такие же методы в классе ProviderService. Затем используйте их в классе InitiateUtils для FruitEntity и ProviderEntity, результат выведете в консоль. (Кстати, если вы не знали то быстро написать “System.out.println()” можно если набрать sout и нажать ентер, таже штука работает с “public static void main(String[] args)<>” достаточно набрать psvm ну и так далее). Я думаю вы уже справились и мы готовы идти дальше. Давайте зайдем в интерфейс FruitRepository и начнем в нем набирать (именно набирать а не копировать) следующий метод: List f Должна получиться следующая штука Просто называете метод как будто составляете запрос: findById(Integer id) — найдет объект по id; countFruitEntityByFruitName(String name) — посчитает количество фруктов с определенным именем; Это запросы, генерируемые по имени метода обязательно почитайте про них и реализуйте в классе FruitService метод between(Integer from, Integer to) для поиска List по значениям поля provider_code входящим в определенный интервал, результат работы выведете в консоль. Например: найти все фрукты, у которых номер поставщика находиться между 5 и 7. Не торопитесь читать дальше, пока не реализуете метод, это не долго. Как вы могли прочитать в статье про запросы по имени метода: «Все запросы так не напишешь, но простые можно.» Для более сложных запросов используется аннотация @Query и вместо SQL здесь используется JPQL(тоже возмите на заметку эту статью), для нашего проекта можно сделать JOIN запросы, так:

 package ru.java.rush.repositories; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; import ru.java.rush.entities.FruitEntity; import java.util.List; @Repository public interface FruitRepository extends JpaRepository  < @Query("select f.fruitName, p.providerName from FruitEntity f left join ProviderEntity p on f.providerCode = p.id") ListjoinSting(); > 

Стандартный SQL запрос был бы таким: «select fruit_table.fruit_name, provider_table.provider_name from fruit_table left join provider_table on fruit_table.provider_сode = provider_table.id». Здесь легко можно установить соответствие: fruit_table это FruitEntiy f, где FruitEntiy это тип переменной, f это ее наименование, то есть SQL работает с таблицами и полями, а JPQL с объектами и их полями. Опять же fruit_table.fruit_name это f.fruitName; Так как мы работаем с объектами то можем и объект вывести: Напишем еще один метод FruitRepository

 @Query("select f from FruitEntity f join ProviderEntity p on f.providerCode = p.id") List joinFruit(); 

Реализуем оба метода в классе FruitService

 public List joinString() < return fruitRepository.joinSting(); >public List joinFruit()

Звучит не плохо, но все равно для сложных запросов используют старый добрый SQL

 @Query( value = "select fruit_table.fruit_name, provider_table.provider_name from fruit_table join provider_table on fruit_table.provider_code = provider_table.id_provider", //по идее эту портянку надо засунуть в какой нибудь Enum nativeQuery = true) //нужно только пометить только nativeQuery = true ListList joinSqlFruit(); 

И используем их всех в классе InitiateUtils

 System.out.println("\nТаблица фруктов и их поставщиков"); for (String join : fruitService.joinString()) < System.out.println(join); >System.out.println("\nТаблица фруктов и их поставщиков"); for (FruitEntity join : fruitService.joinFruit()) < System.out.println(join); >System.out.println("\nТаблица фруктов и их поставщиков"); for (String join : fruitService.joinSqlFruit())

Устранение неполадок подключения и других ошибок Базы данных SQL Azure и Управляемого экземпляра SQL Azure

Вы получаете сообщения об ошибках при сбое подключения к базе данных SQL Azure или управляемому экземпляру SQL Azure. Эти проблемы подключения могут быть вызваны изменением конфигурации, настроек брандмауэра, истечением времени ожидания подключения, неверными сведениями для входа или несоблюдением рекомендаций и инструкций по разработке в процессе разработки приложения . Кроме того, при достижении максимального объема по некоторым ресурсам для баз данных SQL Azure или управляемого экземпляра SQL, вы больше не сможете подключаться.

С помощью средства проверки Подключение эффективности SQL Azure можно обнаруживать и устранять различные ошибки подключения для База данных SQL Azure, Управляемый экземпляр SQL Azure и в средах Azure Synapse Analytics.

Сообщения о временных ошибках (40197, 40613 и др.)

Инфраструктура Azure способна динамически изменять конфигурацию серверов при высокой рабочей нагрузке на службу баз данных SQL. Такое динамическое поведение может привести к разрыву подключения между клиентской программой и базой данных или экземпляром. Такое состояние называется временной ошибкой. События перенастройки базы данных обычно происходят в запланированном случае (например, при обновлении программного обеспечения) или в незапланированном случае (например, при сбое процесса или балансировке нагрузки). Большей частью события перенастройки кратковременные и должны завершаться в течение 60 секунд максимум. Тем не менее завершение этих событий иногда может занимать больше времени, например когда большая транзакция приводит к длительному восстановлению. В следующей таблице перечислены различные временные ошибки, которые могут отображаться в приложениях при подключении к Базе данных SQL Azure.

Список кодов ошибок для временных сбоев

Код ошибки Статус Description
926 14 Невозможно открыть базу данных replicatedmaster. Она была отмечена как подозрительная (SUSPECT) операцией восстановления. Дополнительные сведения см. в журнале ошибок SQL Server.

Эта ошибка возникает, если служба не работает по причине обновления программного или аппаратного обеспечения, аппаратных ошибок или проблем при отработке отказа. Код ошибки (%d), указанный в сообщении об ошибке 40197, содержит дополнительные сведения о характере сбоя или отработки отказа. В сообщении об ошибке 40197 может быть указан код ошибки 40020, 40143, 40166 или 40540.

Входы SQL используют кэш в памяти для сопоставления имен и идентификаторов баз данных. Кэш должен быть синхронизирован с внутренней базой данных и обновляться при каждом подключении базы данных к экземпляру сервера SQL и при каждом отключении от него.
Вы получаете эту ошибку, если рабочий процесс отключения не очищает вовремя кэш в памяти, и из-за этого последующие операции поиска возвращают устаревший идентификатор базы данных.

Порядок устранения временных проблем подключения

  1. Проверьте панель мониторинга служб Microsoft Azure на наличие каких-либо известных сбоев, произошедших в то время, когда приложение сообщало об ошибках.
  2. Приложения, подключающиеся к облачной службе, такой как база данных SQL Azure, должны ожидать периодические события перенастройки и реализовывать логику повторов для обработки этих ошибок, а не отображать ошибки приложения пользователям.
  3. Если база данных близка к исчерпанию доступных ресурсов, может возникать временная проблема подключения. Дополнительные сведения см. в статье Обзор ограничений ресурсов базы данных SQL Azure.
  4. Если проблемы подключения остаются или интервал, во время которого приложение обнаруживает ошибку, превышает 60 секунд, а также если в определенный день такая ошибка возникает многократно, зарегистрируйте запрос на поддержку Azure, нажав Получить поддержку на сайте Поддержка Azure .
Реализация логики повторов

Настоятельно рекомендуем включить в клиентской программе логику повторных попыток, чтобы программа смогла восстановить подключение после определенного периода, позволяющего временной ошибке самоустраниться. Рекомендуется подождать 5 секунд, прежде чем выполнять первую повторную попытку. Повторная попытка после ожидания менее 5 секунд может привести к перегрузке облачной службы. Для каждой последующей повторной попытки ожидание должно увеличиваться экспоненциально, но не более чем до 60 секунд.

Примеры кода с логикой повторных попыток см. в следующих статьях:

  • Выполнение устойчивого подключения к SQL с помощью ADO.NET
  • Выполнение устойчивого подключения к SQL с помощью PHP

Дополнительные сведения об обработке временных ошибок в приложении см. в статье Устранение временных ошибок подключения к базе данных SQL

Обсуждение периода блокировки для клиентов, которые используют ADO.NET, см. в статье Организация пулов соединений (ADO.NET).

При установке соединения с вашим сервером возникла ошибка, связанная с сетью или экземпляром.

Эта проблема возникает в том случае, если приложению не удается подключиться к серверу.

Чтобы устранить эту проблему, попробуйте выполнить действия (в указанном порядке), описанные в разделе Инструкции по устранению распространенных неполадок с подключением.

Сервер/экземпляр не найден или недоступен (ошибки 26, 40, 10053)

Ошибка 26: ошибка при поиске указанного сервера

System.Data.SqlClient.SqlException: A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections.(provider: SQL Network Interfaces, error: 26 – Error Locating Server/Instance Specified)

Ошибка 40: невозможно открыть соединение с сервером.

A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: Named Pipes Provider, error: 40 — Could not open a connection to SQL Server)

Ошибка 10053: ошибка на транспортном уровне при получении результатов с сервера

10053: A transport-level error has occurred when receiving results from the server. (Provider: TCP Provider, error: 0 — An established connection was aborted by the software in your host machine)

Эти проблемы возникают в том случае, если приложению не удается подключиться к серверу.

Чтобы устранить эти проблемы, попробуйте выполнить действия (в указанном порядке), описанные в разделе Инструкции по устранению распространенных неполадок с подключением.

Не удается подключиться к серверу из-за проблем с брандмауэром

Ошибка 40615: не удается подключиться к серверу
Ошибка 5: не удается подключиться к серверу

Чтобы устранить эту ошибку, откройте порт 1433 для исходящих соединений на всех брандмауэрах между клиентом и Интернетом.

Не удалось войти на сервер (ошибки 18456, 40531)

Пользователю ‘< имя_пользователя>‘ не удалось войти в систему

Login failed for user ».This session has been assigned a tracing ID of ». Provide this tracing ID to customer support when you need assistance. (Microsoft SQL Server, Error: 18456)

Чтобы устранить эту проблему, обратитесь к администратору служб, чтобы он дал вам допустимое имя пользователя и пароль.

Как правило, администратор службы может выполнить следующие действия, чтобы добавить данные для входа:

  1. Войдите на сервер с помощью SQL Server Management Studio (SSMS).
  2. Отправьте следующий SQL-запрос в базе данных master , чтобы проверить, отключено ли имя для входа:

SELECT name, is_disabled FROM sys.sql_logins; 
ALTER LOGIN ENABLE; 
CREATE LOGIN WITH PASSWORD = ''; GO 
CREATE USER [] FOR LOGIN [] WITH DEFAULT_SCHEMA = []; GO -- Add user to the database owner role EXEC sp_addrolemember N'db_owner', N''; GO 

Также можно использовать sp_addrolemember , чтобы сопоставить данные определенных пользователей с конкретными ролями базы данных.

Примечание. В базе данных SQL Azure рассмотрите новый синтаксис ALTER ROLE для управления членством в роли базы данных.

Ошибки, связанные с истечением времени ожидания подключения.

System. Data. SqlClient. SqlException (0x80131904): время ожидания подключения истекло

System.Data.SqlClient.SqlException (0x80131904): Connection Timeout Expired. The timeout period elapsed while attempting to consume the pre-login handshake acknowledgement. This could be because the pre-login handshake failed or the server was unable to respond back in time. The duration spent while attempting to connect to this server was — [Pre-Login] initialization=3; handshake=29995;

System. Data. SqlClient. SqlException (0x80131904): время ожидания истекло

System.Data.SqlClient.SqlException (0x80131904): Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.

System.Data.Entity.Core.EntityException: произошла ошибка базового поставщика при открытии

System.Data.Entity.Core.EntityException: The underlying provider failed on Open. -> System.Data.SqlClient.SqlException: Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. -> System.ComponentModel.Win32Exception: The wait operation timed out

Не удается подключиться к серверу

Cannot connect to .ADDITIONAL INFORMATION:Connection Timeout Expired. The timeout period elapsed during the post-login phase. The connection could have timed out while waiting for server to complete the login process and respond; Or it could have timed out while attempting to create multiple active connections. The duration spent while attempting to connect to this server was — [Pre-Login] initialization=231; handshake=983; [Login] initialization=0; authentication=0; [Post-Login] complete=13000; (Microsoft SQL Server, Error: -2) For help, click: http://go.microsoft.com/fwlink?ProdName=Microsoft%20SQL%20Server&EvtSrc=MSSQLServer&EvtID=-2&LinkId=20476 The wait operation timed out

Такие исключения могут возникать из-за проблем с подключением или запросами. Чтобы убедиться, что эта ошибка вызвана проблемами подключения, см. статью Проверьте, вызвана ли ошибка проблемой подключения.

Ошибки, связанные с истечением времени ожидания подключения, возникают из-за того, что приложению не удается подключиться к серверу. Чтобы устранить эту проблему, попробуйте выполнить действия (в указанном порядке), описанные в разделе Инструкции по устранению распространенных неполадок с подключением.

Ошибки завершения сетевого подключения

Клиентские библиотеки SQL подключаются к База данных SQL Azure и Управляемый экземпляр SQL Azure с помощью протокола TCP. Клиентская библиотека использует компонент более низкого уровня, называемый поставщиком TCP для управления TCP-подключениями. Когда поставщик TCP обнаруживает, что удаленный узел неожиданно завершил существующее TCP-подключение, клиентская библиотека вызывает ошибку. Так как ошибка является клиентской ошибкой, а не ошибкой SQL Server, номер ошибки SQL не включен. Вместо этого номер ошибки равен 0, а используется сообщение об ошибке от поставщика TCP.

Ниже приведены примеры ошибок завершения сетевого подключения:

A connection was successfully established with the server, but then an error occurred during the pre-login handshake. (provider: TCP Provider, error: 0 — An existing connection was forcibly closed by the remote host.) An existing connection was forcibly closed by the remote host

A transport-level error has occurred when sending the request to the server. (provider: TCP Provider, error: 0 — An existing connection was forcibly closed by the remote host.)

The client was unable to establish a connection because of an error during connection initialization process before login. Possible causes include the following: the client tried to connect to an unsupported version of SQL Server; the server was too busy to accept new connections; or there was a resource limitation (insufficient memory or maximum allowed connections) on the server. (provider: TCP Provider, error: 0 — An existing connection was forcibly closed by the remote host.)

A connection was successfully established with the server, but then an error occurred during the login process. (provider: TCP Provider, error: 0 — An existing connection was forcibly closed by the remote host.)

ошибки завершения Подключение случаев могут возникать из-за временной недоступности базы данных или эластичного пула. Они также могут возникать из-за различных проблем в сетевой инфраструктуре между сервером базы данных и клиентским приложением, включая брандмауэры, сетевые (модуль) и т. д. Эти проблемы могут быть временными или постоянными. В качестве общего руководства приложения должны использовать фиксированное количество попыток повторных попыток для этих ошибок, прежде чем рассматривать их постоянные сбои.

Ошибки управления ресурсами

Благодаря реализации системы управления ресурсами, основанной на Resource Governor, в Базе данных SQL Azure применяются ограничения ресурсов. См. подробные сведения об управлении ресурсами в Базе данных SQL Azure.

Сначала перечислены самые распространенные ошибки системы управления ресурсами с подробными сведениями. Затем следуют сообщения об ошибках системы управления ресурсами.

Ошибки 10928 и 10936: идентификатор ресурса : 1. Ограничение запроса для [базы данных или эластичного пула] равно %d и достигнуто

Если достигнуто ограничение уровня базы данных, подробное сообщение об ошибке в этом случае считывается: Resource ID : 1. The request limit for the database is %d and has been reached. See ‘http://go.microsoft.com/fwlink/?LinkId=267637’ for assistance.

Если ограничение эластичного пула достигнуто, подробное сообщение об ошибке в этом случае считывается: Resource ID : 1. The request limit for the elastic pool is %d and has been reached. See ‘http://go.microsoft.com/fwlink/?LinkId=267637’ for assistance. ограничения эластичного пула превышают ограничения базы данных, дополнительные сведения см. в разделе «Ограничения ресурсов». Их можно достичь, когда несколько баз данных в пуле используют ресурс (например, рабочие) одновременно.

Это сообщение об ошибке указывает, что достигнуто ограничение рабочей роли для базы данных или эластичного пула. Максимальное значение параллельных рабочих ролей для цели службы базы данных или эластичного пула будет присутствовать вместо заполнителя %d.

В первоначальном предложении для Базы данных SQL Azure поддерживались только запросы с одним потоком. В то время число запросов всегда было равнозначно числу рабочих ролей. Сообщения об ошибках 10928 и 10936 в База данных SQL Azure содержат слово «Ограничение запроса [. ] значение N и достигнуто» для обратной совместимости. Фактически, достигнутое ограничение представляет собой число рабочих ролей. Если параметр максимальной степени параллелизма (MAXDOP) равен нулю или больше единицы, число рабочих ролей может быть значительно больше числа запросов, а ограничение может быть достигнуто гораздо раньше, чем когда значение MAXDOP равно 1.

Установка выделенного подключения администратора (DAC) (при необходимости)

Если в текущий момент происходит инцидент достижения предельного числа рабочих ролей или приближения к этому пределу, может поступить сообщение об ошибке 10928, когда вы подключаетесь с использованием SQL Server Management Studio (SSMS) или Azure Data Studio. Установка подключения диагностики для администраторов баз данных (DAC) для одного сеанса возможна даже при достижении максимального порога для рабочих ролей.

Подключение с использованием DAC из SSMS:

  • В меню выберите элементы Файл > Создать > Запрос ядра СУБД.
  • В диалоговом окне подключения в поле «Имя сервера» введите admin: (формат будет приблизительно таким: admin:servername.database.windows.net ).
  • Выберите элемент Параметры>>.
  • Выберите вкладку Свойства подключения.
  • В поле Подключение к базе данных: введите имя базы данных.
  • Нажмите Подключиться.

Если вы получили сообщение об ошибке 40613 Database ‘%.*ls’ on server ‘%.*ls’ is not currently available. Please retry the connection later. If the problem persists, contact customer support, and provide them the session tracing ID of ‘%.*ls’ , это может означать, что к DAC уже подключен другой сеанс. К DAC за раз можно подключать только один сеанс для отдельной базы данных или эластичного пула.

Если после выбора элемента Подключиться поступает сообщение об ошибке «Failed to connect to server» (Не удалось подключиться к серверу), возможно, сеанс DAC все же успешно установлен, если вы используете версию SSMS, предшествующую 18.9. В ранних версиях SSMS выполнялась попытка предоставить Intellisense для подключений к DAC. Это не удавалось сделать, так как DAC поддерживает только одну рабочую роль, а Intellisense требуется отдельная рабочая роль.

Подключение к DAC нельзя использовать в обозревателе объектов.

Просмотр сведений об использовании max_worker_percent

Чтобы найти статистику потребления ресурсов для базы данных за 14 дней, подайте запрос к представлению каталога системы sys.resource_stats. В столбце max_worker_percent показано количество используемых рабочих ролей относительно предельного количества рабочих ролей для вашей базы данных. Подключение в master базу данных на логическом сервере для запроса sys.resource_stats .

SELECT start_time, end_time, database_name, sku, avg_cpu_percent, max_worker_percent, max_session_percent FROM sys.resource_stats; 

Кроме того, вы можете запросить статистику по потреблению ресурсов за последний час в динамическом административном представлении sys.dm_db_resource_stats. Подключитесь непосредственно к своей базе данных, чтобы запросить sys.dm_db_resource_stats .

SELECT end_time, avg_cpu_percent, max_worker_percent, max_session_percent FROM sys.dm_db_resource_stats; 
Снижение показателя использования рабочих ролей при возможности

Блокирование цепочек может привести к внезапному увеличению количества рабочих ролей в базе данных. Большое количество одновременных параллельных запросов может привести к использованию большого количества рабочих ролей. Увеличив максимальный уровень параллелизма (MAXDOP) или установив нулевой уровень MAXDOP, можно увеличить число активных рабочих ролей.

Рассмотрите инцидент недостаточного числа рабочих ролей, следуя этим инструкциям:

    Определите, есть ли блокировка или большое число одновременно используемых рабочих ролей. Чтобы изучить текущие запросы и проверить, нет ли блокировки, когда из базы данных поступает сообщение об ошибке 10928, выполните следующий запрос. Возможно, для выполнения запроса вам потребуется выделенное подключение администратора (DAC).

SELECT r.session_id, r.request_id, r.blocking_session_id, r.start_time, r.status, r.command, DB_NAME(r.database_id) AS database_name, (SELECT COUNT(*) FROM sys.dm_os_tasks AS t WHERE t.session_id=r.session_id and t.request_id=r.request_id) AS worker_count, i.parameters, i.event_info AS input_buffer, r.last_wait_type, r.open_transaction_count, r.total_elapsed_time, r.cpu_time, r.logical_reads, r.writes, s.login_time, s.login_name, s.program_name, s.host_name FROM sys.dm_exec_requests as r JOIN sys.dm_exec_sessions as s on r.session_id=s.session_id OUTER APPLY sys.dm_exec_input_buffer (r.session_id,r.request_id) AS i WHERE s.is_user_process=1; GO 
  1. Выполните поиск строк с blocking_session_id , чтобы определить заблокированные сеансы. Найдите каждый blocking_session_id в списке, чтобы определить, заблокирован ли также этот сеанс. В конечном итоге это приведет вас к главной причине блокировки. Настройка запроса по главной причине блокировки.

Примечание. Дополнительные сведения об устранении неполадок, связанных с длительным выполнением ил блокировкой запросов, см. в статье Изучение и устранение проблем блокировок в Базе данных SQL Azure.

Увеличение предельных значений числа рабочих ролей

Если база данных или эластичного пула последовательно достигает своего рабочего предела, несмотря на блокировку, оптимизацию запросов и проверку параметра MAXDOP, рассмотрите возможность увеличения масштаба базы данных или эластичного пула, чтобы увеличить предел рабочей роли.

Сведения об ограничениях ресурсов с учетом уровня служб и объема вычислительных ресурсов см. в следующих статьях:

  • Ограничения ресурсов для отдельных баз данных с использованием модели приобретения виртуального ядра
  • Ограничения ресурсов для эластичных пулов в рамках модели приобретения на основе виртуальных ядер
  • Resource limits for single databases using the DTU purchasing model (Ограничения ресурсов для отдельных баз данных при использовании модели приобретения DTU)
  • Ограничения ресурсов для эластичных пулов в модели приобретения на основе единиц DTU

Ошибка 10929: идентификатор ресурса: 1

10929: Resource ID: 1. The %s minimum guarantee is %d, maximum limit is %d and the current usage for the database is %d. However, the server is currently too busy to support requests greater than %d for this database. See http://go.microsoft.com/fwlink/?LinkId=267637 for assistance. Otherwise, please try again later.

Ошибка 40501: служба сейчас перегружена

40501: The service is currently busy. Retry the request after 10 seconds. Incident ID: %ls. Code: %d.

Это ошибка регулирования ресурсов ядра, которая указывает на превышение ограничений по ресурсам.

Дополнительные сведения об ограничениях ресурсов см. в статье Ограничения ресурсов логического сервера SQL.

Ошибка 40544: база данных достигла предельного размера

40544: The database has reached its size quota. Partition or delete data, drop indexes, or consult the documentation for possible resolutions. Incident ID: . Code: .

Эта ошибка возникает в тех случаях, когда база данных достигает предельного размера.

Следующие инструкции помогут вам решить эту проблему или получить больше возможностей:

    Проверьте текущий размер базы данных с помощью панели мониторинга на портале Azure.

Примечание. Чтобы узнать, какие таблицы потребляют наибольшее пространство, и, следовательно, являются потенциальными претендентами на очистку, отправьте следующий SQL-запрос:

SELECT o.name, SUM(p.row_count) AS 'Row Count', SUM(p.reserved_page_count) * 8.0 / 1024 AS 'Table Size (MB)' FROM sys.objects o JOIN sys.dm_db_partition_stats p on p.object_id = o.object_id GROUP BY o.name ORDER BY [Table Size (MB)] DESC; GO 
  • Выполните обычные действия по очистке базы данных. Например, можно очистить ненужные данные с помощью функции усечения/ удаления или переместить данные при помощи служб SQL Server Integration Services (SSIS) или программы для массового копирования (bcp).
  • Разделите или удалите данные, удалите индексы или просмотрите документацию, чтобы найти возможные решения проблемы.
  • Сведения о масштабирования баз данных см. в статье Масштабирование ресурсов отдельной базы данных и Масштабирование ресурсов эластичного пула.

Ошибка 40549: сеанс завершен по причине долго выполняющейся транзакции

40549: Session is terminated because you have a long-running transaction. Try shortening your transaction.

Если эта ошибка повторяется, попробуйте устранить проблему, выполнив описанные ниже действия.

    Выполните следующий запрос, чтобы получить сведения об открытых сеансах, имеющих высокое значение в столбце duration_ms :

SELECT r.start_time, DATEDIFF(ms,start_time, SYSDATETIME()) as duration_ms, r.session_id, r.request_id, r.blocking_session_id, r.status, r.command, DB_NAME(r.database_id) AS database_name, i.parameters, i.event_info AS input_buffer, r.last_wait_type, r.open_transaction_count, r.total_elapsed_time, r.cpu_time, r.logical_reads, r.writes, s.login_time, s.login_name, s.program_name, s.host_name FROM sys.dm_exec_requests as r JOIN sys.dm_exec_sessions as s on r.session_id=s.session_id OUTER APPLY sys.dm_exec_input_buffer (r.session_id,r.request_id) AS i WHERE s.is_user_process=1 ORDER BY start_time ASC; GO 

Примечание. Дополнительные сведения об устранении неполадок с блокировкой в базе данных SQL Azure см. в статье Изучение и устранение проблем с блокировкой в базе данных SQL Azure.

Ошибка 40551: сеанс был завершен из-за чрезмерного использования tempdb

40551: The session has been terminated because of excessive TEMPDB usage. Try modifying your query to reduce the temporary table space usage.

Чтобы устранить эту проблему, выполните следующие действия:

  1. Измените запросы, чтобы уменьшить использование временного пространства таблицы.
  2. Удалите временные объекты, которые вам уже не нужны.
  3. Выполните усечение таблиц или удалите неиспользуемые таблицы.

Ошибка 40552: сеанс был завершен в связи с чрезмерным использованием объема журнала транзакций

40552: The session has been terminated because of excessive transaction log space usage. Try modifying fewer rows in a single transaction.

Устранить эту проблему можно с помощью следующих методов.

  • Эта проблема может возникать из-за операций вставки, обновления или удаления. Попробуйте сократить количество строк, которые обрабатываются непосредственно, выполнив пакетную обработку или разделение на несколько меньших транзакций.
  • Эта проблема может возникать из-за операций перестроения индекса. Чтобы решить эту проблему, убедитесь, что число затронутых строк в таблице * (средний размер обновляемого поля в байтах + 80) составляет < 2 гигабайт (ГБ).
  • Для перестроения индекса средний размер обновляемого поля должен быть заменен средним размером индекса.
  • Дополнительные сведения см. в разделе «Устранение неполадок с полным журналом транзакций» в База данных SQL Azure и устранение неполадок полного журнала транзакций в Управляемый экземпляр SQL Azure.

Ошибка 40553: сеанс был завершен в связи с чрезмерным использованием памяти

40553: The session has been terminated because of excessive memory usage. Try modifying your query to process fewer rows.

Чтобы устранить эту проблему, попробуйте оптимизировать запрос.

Подробное описание процедуры устранения неполадок см. в статье Правильно ли работает мой запрос в облаке?

Дополнительные сведения о других ошибках, связанных с нехваткой памяти, и примеры запросов об ошибке в памяти см. в Устранение ошибок нехватки памяти в базе данных Azure SQL.

Таблица сообщений об ошибках управления ресурсами

Код ошибки Статус Description
10928 20 Идентификатор ресурса: %d. Предел %s для базы данных составляет %d, и он достигнут. Дополнительные сведения см. в статье «http://go.microsoft.com/fwlink/?LinkId=267637».

Идентификатор ресурса указывает на ресурс, предел которого был достигнут. Если идентификатор ресурса = 1, это означает, что достигнуто предельное количество рабочих ролей. Дополнительные сведения см. в разделе Ошибка 10928: идентификатор ресурса: 1. Предел запросов для базы данных составляет %d, и он достигнут. Если идентификатор ресурса 2, значит, достигнуто ограничение количества сеансов.

Идентификатор ресурса указывает на ресурс, предел которого был достигнут. Если идентификатор ресурса = 1, это означает, что достигнуто предельное количество рабочих ролей. Дополнительные сведения об ошибке 10936: идентификатор ресурса: 1. Ограничение запроса для эластичного пула равно %d и достигнуто. Если идентификатор ресурса = 2, это означает, что достигнуто ограничение сеанса.

Ошибки пула эластичных БД

Приведенные ниже ошибки связаны с созданием и использованием эластичных пулов.

Код ошибки Статус Description Корректирующее действие
1132 17 Хранилище эластичного пула достигло своего предельного значения. Уровень использования хранилища для эластичного пула не может превышать (%d) МБ. Попытка записи данных в базу данных, когда было достигнуто предельное значение хранилища эластичного пула. Дополнительные сведения об ограничениях ресурсов см. в статье:
• Ограничения на основе DTU для эластичных пулов.
• Ограничения на основе виртуального ядра для пулов эластичных баз данных.
Если это возможно, попробуйте увеличить DTU эластичного пула и (или) добавить в него пространство хранения для увеличения предельного размера его хранилища, сократить объем памяти, используемой отдельными базами данных в эластичном пуле, или удалить базы данных из пула. Сведения о масштабировании эластичных пулов см. в статье Масштабирование ресурсов эластичного пула. Дополнительные сведения об удалении неиспользуемого пространства из баз данных см. в статье Управление пространством для баз данных в Базе данных SQL Azure.
10929 16 Минимальная гарантия %s составляет %d, максимальное значение равно %d, а текущее использование для базы данных — %d. Тем не менее, в настоящее время сервер слишком занят, чтобы обработать более чем %d запросов для этой базы данных. Дополнительные сведения об ограничениях ресурсов см. в статье:
• Ограничения на основе DTU для эластичных пулов.
• Ограничения на основе виртуального ядра для пулов эластичных баз данных.
В противном случае повторите попытку. Минимальное количество DTU или виртуальных ядер на базу данных; максимальное количество DTU или виртуальных ядер на базу данных. Общее количество одновременно используемых рабочих ролей по всем базам данных в эластичном пуле превысило ограничение пула.
Если это возможно, попробуйте увеличить DTU или число виртуальных ядер эластичного пула для увеличения предельно допустимого количества работников или удалить базы данных из эластичного пула.
40844 16 База данных ‘%ls’ на сервере ‘%ls’ является базой данных выпуска ‘%ls’ в эластичном пуле и не может иметь связь непрерывной копии. Н/П
40857 16 Эластичный пул для сервера ‘%ls’ не найден, имя эластичного пула: ‘%ls’. На указанном сервере указанный эластичный пул не существует. Укажите допустимое имя эластичного пула.
40858 16 Эластичный пул «%ls» на сервере «%ls» уже существует. Указанный эластичный пул уже существует на указанном сервере. Укажите новое имя эластичного пула.
40859 16 Эластичный пул не поддерживает уровень служб ‘%ls’. Для подготовки эластичного пула указанный уровень служб не поддерживается. Укажите правильный выпуск или оставьте значение уровня служб пустым, чтобы использовать значение по умолчанию.
40860 16 Недопустимая комбинация эластичного пула ‘%ls’ и цели службы ‘%ls’. Эластичный пул и уровень служб можно указать вместе только в том случае, если тип ресурса задан как ElasticPool. Укажите правильную комбинацию эластичного пула и уровня служб.
40861 16 Выпуск «%.*ls» базы данных не может отличаться от уровня служб пула эластичных БД, который равен «%.*ls». Выпуск базы данных отличается от уровня служб эластичного пула. Не указывайте выпуск базы данных, который отличается от уровня служб эластичного пула. Обратите внимание, что выпуск базы данных указывать не требуется.
40862 16 Если указана цель служб эластичного пула, то необходимо указать имя этого эластичного пула. Цель службы эластичного пула неоднозначно определяет эластичный пул. Если используется цель служб эластичного пула, укажите имя этого эластичного пула.
40864 16 Число DTU для эластичного пула должно составлять по крайней мере (%d) DTU для уровня служб «%.*ls». Попытка задать для эластичного пула DTU, значение которого ниже минимального ограничения. Повторите попытку, установив для эластичного пула DTU, значение которого хотя бы равно минимальному ограничению.
40865 16 Число DTU для эластичного пула не должно превышать (%d) DTU для уровня служб «%.*ls». Попытка задать для эластичного пула DTU, значение которого выше максимального ограничения. Повторите попытку, установив для эластичного пула DTU, значение которого не превышает максимальное ограничение.
40867 16 Максимальное количество DTU на каждую базу данных должно составлять как минимум (%d) для уровня служб «%.*ls». Попытка задать максимальное количество DTU на каждую базу данных ниже поддерживаемого ограничения. Попробуйте использовать уровень служб эластичного пула, который поддерживает желаемый параметр.
40868 16 Максимальное количество DTU на каждую базу данных не должно превышать (%d) для уровня служб «%.*ls». Попытка задать максимальное число DTU на каждую базу данных, которое находится за пределами поддерживаемого ограничения. Попробуйте использовать уровень служб эластичного пула, который поддерживает желаемый параметр.
40870 16 Минимальное количество DTU на каждую базу данных не должно превышать (%d) для уровня служб «%.*ls». Попытка задать минимальное число DTU на каждую базу, которое находится за пределами поддерживаемого ограничения. Попробуйте использовать уровень служб эластичного пула, который поддерживает желаемый параметр.
40873 16 Количество баз данных (%d) и минимальное количество DTU на каждую базу данных (%d) не может превышать DTU эластичного пула (%d). Попытка задать минимальное количество DTU для баз данных в эластичном пуле, превышающее DTU эластичного пула. Попробуйте увеличить количество DTU эластичного пула, уменьшить минимальное количество DTU на каждую базу данных или уменьшить количество баз данных в эластичном пуле.
40877 16 Эластичный пул не может быть удален до тех пор, пока он содержит какую-либо базу данных. Эластичный пул содержит одну или несколько баз данных и не может быть удален. Чтобы удалить эластичный пул, удалите из него базы данных.
40881 16 В эластичном пуле ‘%.*ls’ достигнуто предельное количество баз данных. Предельное количество баз данных не может превышать (%d) для эластичного пула с DTU (%d). Попытка создания или добавления базы данных в эластичный пул, когда было достигнуто предельное количество баз данных эластичного пула. Если это возможно, попробуйте увеличить DTU эластичного пула, чтобы увеличить предельное количество баз данных, или удалить базы данных из эластичного пула.
40889 16 Невозможно уменьшить количество DTU или размер хранилища для эластичного пула ‘%.*ls’, так как недостаточно места в хранилище баз данных. Попытка ограничить размер хранилища эластичного пула, при которой уменьшается размер используемого им хранилища. Попробуйте сократить использование хранилища отдельными базами данных в эластичном пуле или удалить базы данных из пула, чтобы уменьшить количество DTU или размер хранилища.
40891 16 Минимальное число DTU на базу данных (%d) не может превышать максимального числа DTU на базу данных (%d). Попытка задать минимальное число DTU на каждую базу данных, превышающее максимальное число DTU на каждую базу данных. Убедитесь, что минимальное число DTU на базу данных не превышает максимального числа DTU на базу данных.
Подлежит уточнению 16 Размер хранилища для отдельной базы данных в эластичном пуле не может превышать максимальный размер, допустимый уровнем служб эластичного пула «%.*ls». Максимальный размер базы данных превышает максимальный размер, допустимый уровнем служб эластичного пула. Укажите максимальный размер базы данных, который находится в пределах ограничений на максимальный размер, допустимый уровнем служб эластичного пула.

Не удается открыть базу данных «master», запрошенную при входе в систему. Не удалось выполнить вход

Эта проблема возникает из-за того, что учетная запись не имеет разрешения на доступ к базе данных master . Но по умолчанию SQL Server Management Studio (SSMS) пытается подключиться к базе данных master .

Проблему можно устранить следующим способом.

Connection properties

  1. На экране входа SSMS выберите Параметры, а затем — Свойства подключения.
  2. В поле Подключение к базе данных введите имя базы данных пользователя по умолчанию в качестве базы данных для входа по умолчанию, а затем выберите Подключить.

Ошибки базы данных, доступной только для чтения

При попытке записи в базу данных, доступную только для чтения, появится сообщение об ошибке. В некоторых сценариях причина состояния базы данных, доступной только для чтения, может быть неясна сразу.

Ошибка 3906: не удалось обновить базу данных «Имя_базы_данных», так как она доступна только для чтения.

При попытке изменить базу данных, доступную только для чтения, возникнет следующая ошибка.

Msg 3906, Level 16, State 2, Line 1 Failed to update database "%d" because the database is read-only. 
Вы можете быть подключены к реплике только для чтения

Как для Базы данных SQL Azure, так и для Управляемого экземпляра Azure SQL вы можете быть подключены к базе данных в реплике, доступной только для чтения. В этом случае следующий запрос с использованием функции DATABASEPROPERTYEX() вернет READ_ONLY :

SELECT DATABASEPROPERTYEX(DB_NAME(), 'Updateability'); GO 

При подключении с помощью SQL Server Management Studio, убедитесь, что вы указали ApplicationIntent=ReadOnly на вкладке Дополнительные параметры подключения в параметрах подключения.

Если подключение устанавливается из приложения или клиента с использованием строки подключения, проверьте, указано ли значение ApplicationIntent=ReadOnly в строке подключения. Дополнительные сведения см. в разделе Подключение к реплике, доступной только для чтения.

База данных может быть настроена только для чтения

Если вы используете Базу данных SQL Azure, сама база данных может быть настроена только для чтения. Состояние базы данных можно проверить с помощью следующего запроса:

SELECT name, is_read_only FROM sys.databases WHERE database_id = DB_ID(); 

Вы можете изменить состояние базы данных, доступной только для чтения, в Базе данных SQL Azure с помощью инструкции ALTER DATABASE Transact-SQL. В настоящее время невозможно задать базу данных в управляемом экземпляре только для чтения.

Проверьте, вызвана ли ошибка проблемой подключения.

Чтобы проверить, вызвана ли ошибка проблемой подключения, просмотрите трассировку стека для фреймов, показывающих вызовы, чтобы открыть подключение, как показано ниже (обратите внимание на ссылку на класс SqlConnection):

System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry) at System.Data.SqlClient.SqlConnection.Open() at AzureConnectionTest.Program.Main(String[] args) ClientConnectionId:

Если исключение срабатывает из-за проблем с запросами, вы увидите стек вызовов, аналогичный приведенному ниже (обратите внимание на ссылку на класс SqlCommand). В этом случае выполните настройку запросов.

 at System.Data.SqlClient.SqlCommand.ExecuteReader() at AzureConnectionTest.Program.Main(String[] args) ClientConnectionId:

Дополнительные рекомендации по точной настройке см. в следующих ресурсах:

  • Как поддерживать актуальность статистики и индексов Azure SQL
  • Ручная настройка производительности запросов в Базе данных SQL Azure
  • Мониторинг производительности Базы данных SQL Azure с помощью динамических административных представлений
  • Управление хранилищем запросов в Базе данных SQL Azure

Инструкции по устранению распространенных неполадок с подключением

  1. Убедитесь, что протокол TCP/IP включен в качестве клиентского протокола на сервере приложений. Дополнительные сведения см. в статье Настройка клиентских протоколов. На серверах приложений, на которых не установлены средства SQL, убедитесь, что протокол TCP/IP включен, запустив cliconfg.exe (служебная программа SQL Server Client Network).
  2. Проверьте строку подключения приложения, чтобы убедиться, что она настроена правильно. Например, убедитесь, что в строке подключения указан правильный порт (1433) и полное имя сервера. См. статью Получение сведений о подключении.
  3. Попробуйте увеличить значение времени ожидания подключения. Мы рекомендуем устанавливать время ожидания подключения не менее 30 секунд.
  4. Проверьте подключение между сервером приложений и Базой данных SQL Azure с помощью SQL Server Management Studio (SSMS), файла UDL, проверки связи или telnet. Дополнительные сведения см. в статьях Устранение неполадок с подключением и Диагностика проблем с подключением.

Примечание. На этапе устранения неполадок можно также проверить возможность подключения на другом клиентском компьютере.

Если эти действия не помогли устранить проблему, попробуйте собрать дополнительные данные, а затем обратитесь в службу поддержки. Если приложение является облачной службой, включите ведение журнала. Это действие возвращает метку времени ошибки в формате UTC. Кроме того, база данных SQL возвращает идентификатор трассировки. Эти сведения могут использовать службы поддержки пользователей Майкрософт.

Следующие шаги

Дополнительные сведения о связанных темах см. в следующих статьях:

  • Архитектура подключений к Базе данных SQL Azure
  • Средства контроля сетевого доступа базы данных SQL Azure и Azure Synapse Analytics
  • Устранение неполадок полного журнала транзакций в База данных SQL Azure
  • Устранение неполадок с полным журналом транзакций в Управляемый экземпляр SQL Azure
  • Устранение временных ошибок подключения в Базе данных SQL и управляемом экземпляре SQL
  • Анализ и предотвращение взаимоблокировок в Базе данных SQL Azure

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *