Не удается подключиться к удаленной базе данных через Spring Boot JpaRepository

Делаю авторизацию для своего web-приложения по туториалу с YouTube и столкнулся с проблемой того, что не могу подключиться к БД. Сам туториал.

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

MyUser - файл сущности БД (пользователь):

package WayFinder.WayFinder_l.model;

import jakarta.persistence.*;

@Entity
public class MyUser {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String username;
    private String password;
    private String role; //Eg: ADMIN,USER

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getRole() {
        return role;
    }

    public void setRole(String role) {
        this.role = role;
    }
}

MyUserDetailService - сервис для получения имени пользователя и данных по нему:

package WayFinder.WayFinder_l.model;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.Optional;

@Service
public class MyUserDetailService implements UserDetailsService {

    @Autowired
    private MyUserRepository repository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Optional<MyUser> user = repository.findByUsername(username);
        if (user.isPresent()) {
            var userObj = user.get();
            return User.builder()
                    .username(userObj.getUsername())
                    .password(userObj.getPassword())
                    .roles(getRoles(userObj))
                    .build();
        } else {
            throw new UsernameNotFoundException(username);
        }
    }

    private String[] getRoles(MyUser user) {
        if (user.getRole() == null) {
            return new String[]{"USER"};
        }
        return user.getRole().split(",");
    }
}

MyUserRepository - интерфейс репозитория:

package WayFinder.WayFinder_l.model;

import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface MyUserRepository extends JpaRepository<MyUser, Long> {

    Optional<MyUser> findByUsername(String username);
}

RegistrationController - файл контроллера запросов для регистрации:

package WayFinder.WayFinder_l;

import WayFinder.WayFinder_l.model.MyUser;
import WayFinder.WayFinder_l.model.MyUserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class RegistrationController {

    @Autowired
    private MyUserRepository myUserRepository;
    @Autowired
    private PasswordEncoder passwordEncoder;

    @PostMapping("/register/user")
    public MyUser createUser(@RequestBody MyUser user) {
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        return myUserRepository.save(user);
    }
}

Файл application.properties:

# MySQL BD CONNECTION
spring.jpa.database=mysql
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://remoteHost:3306/usernames?createDatabaseIfNotExist=true&autoReconnect=true
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.show-sql=false
spring.jpa.hibernate.ddl-auto=none

Файл pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>WayFinder</groupId>
    <artifactId>WayFinder_l</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>WayFinder_l</name>
    <description>Project  new version</description>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>21</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-security -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
            <version>3.3.4</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
            <version>3.3.5</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.mysql/mysql-connector-j -->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>9.1.0</version>
        </dependency>


    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

Ниже привёл заголовки ошибок, судя по всему, сервер не может установить соединение и пытается достучаться до БД, но безуспешно. Проект по итогу запускается, но запросы при регистрации сразу зависают и вылетает та же ошибка в терминале:

org.hibernate.exception.JDBCConnectionException: unable to obtain isolated JDBC connection [Could not create connection to database server. Attempted reconnect 3 times. Giving up.] [n/a]

Caused by: java.sql.SQLNonTransientConnectionException: Could not create connection to database server. Attempted reconnect 3 times. Giving up.

Caused by: com.mysql.cj.exceptions.CJCommunicationsException: Communications link failure

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:62) ~[na:na]

Caused by: java.net.ConnectException: Connection timed out: getsockopt
    at java.base/sun.nio.ch.Net.pollConnect(Native Method) ~[na:na]
    at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:682) ~[na:na]
    at java.base/sun.nio.ch.NioSocketImpl.timedFinishConnect(NioSocketImpl.java:549) ~[na:na]
    at java.base/sun.nio.ch.NioSocketImpl.connect(NioSocketImpl.java:592) ~[na:na]
    at java.base/java.net.SocksSocketImpl.connect(SocksSocketImpl.java:327) ~[na:na]
    at java.base/java.net.Socket.connect(Socket.java:760) ~[na:na]
    at com.mysql.cj.protocol.StandardSocketFactory.connect(StandardSocketFactory.java:144) ~[mysql-connector-j-9.1.0.jar:9.1.0]
    at com.mysql.cj.protocol.a.NativeSocketConnection.connect(NativeSocketConnection.java:53) ~[mysql-connector-j-9.1.0.jar:9.1.0]
    ... 51 common frames omitted

Пробовал менять параметры в application.properties у url, но всё безуспешно. Не хватает знаний в этой теме, поэтому крайне нужна помощь. Буду крайне благодарен за обширные ответы, с пояснениями.
Заранее спасибо!


Ответы (3 шт):

Автор решения: iramm

Установите MySQL Workbench. Создайте новое соединение (MySQL New Connection +). В открывшемся окне введите имя хоста MySQL-сервера, к которому вы обращаетесь, логин и пароль, которые указаны в вашем application.properties файле.Окно создания нового соединения в MySQL Workbench Протестируйте соединение. Если у вас не получится установить соединение с сервером таким образом, то не получится и изнутри вашего приложения.

Вызывает подозрения хост remotehost. Возможно, должен быть localhost или, что то же самое, ip-адрес 127.0.0.1 , то есть ваш компьютер. Во всяком случае в учебном видео использован localhost.

→ Ссылка
Автор решения: Guzya

Посмотрите логи на стороне mysql. В строке подключения должно быть так mysql://remoteHost:3306/<БАЗА_ДАННЫХ> Верно ли указана БД.

→ Ссылка
Автор решения: Artem37

Решил данную проблему добавлением в переменную окружения Path пути к SQL Server, который лежит в ProgramFiles.

→ Ссылка