Можно ли использовать MongoDB и PostgreSQL для одной и той же модели в Spring boot?

#java #mongodb #postgresql #spring-boot

#java #mongodb #postgresql #spring-boot

Вопрос:

Я создал службу управления пользователями, в которой я использую MongoDB (spring data). У меня есть две модели User и Role.

 package com.userservice.usermanagement.models;

import java.util.HashSet;
import java.util.Set;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.mapping.Document;

@Document(collection = "user_data")

public class User {
    /**
     * User model
     */
    
      @Id
      private String id;

      
      private String username;

     
      private String email;

      
      private String password;
      
      private String customername;
      
      private String customerid;
      
      private String description;
      

      public String getCustomerid() {
        return customerid;
    }

    public void setCustomerid(String customerid) {
        this.customerid = customerid;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getCustomername() {
        return customername;
    }

    public void setCustomername(String customername) {
        this.customername = customername;
    }

    @DBRef
      private Set<Role> roles = new HashSet<>();

      public User() {
      }

      public User(String username, String email, String customername,String customerid,String description, String password) {
        this.username = username;
        this.email = email;
        this.customername = customername;
        this.customerid = customerid;
        this.description = description;
        this.password = password;
      }

      public String getId() {
        return id;
      }

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

      public String getUsername() {
        return username;
      }

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

      public String getEmail() {
        return email;
      }

      public void setEmail(String email) {
        this.email = email;
      }

      public String getPassword() {
        return password;
      }

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

      public Set<Role> getRoles() {
        return roles;
      }

      public void setRoles(Set<Role> roles) {
        this.roles = roles;
      }
    }
  

Ролевая модель —

 package com.userservice.usermanagement.models;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

@Document(collection = "roles")
public class Role {
    /**
     * Model for role with all the attributes
     */
      @Id
      private String id;

      private URole name;

      public Role() {

      }

      public Role(URole name) {
        this.name = name;
      }

      public String getId() {
        return id;
      }

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

      public URole getName() {
        return name;
      }

      public void setName(URole name) {
        this.name = name;
      }
    }
  

и перечислитель ролей-

 package com.userservice.usermanagement.models;

public enum URole {
    ROLE_USER,  
    ROLE_ADMIN
}
  

У пользователя есть атрибут роли, который у меня есть @Dbref для коллекции ролей. Моя проблема в том, что я хочу иметь возможность использовать PostgreSQL и MongoDB в одном приложении для этих моделей. Я реализовал это для MongoDB, но я не уверен, как сделать это для PostgreSQL в том же приложении в качестве опции. Один из способов, я думаю, состоит в том, чтобы иметь пользователя интерфейса и роль и создать два разных класса для модели User_mongo и сущности User_postgre (аналогично для роли). Я застрял здесь, и я попытался провести определенные исследования, но большую часть времени я нахожу учебные пособия, в которых есть отдельные базы данных одного и того же типа (обе базы данных PostgreSQL). Приветствуется любое направление. PS Я новичок в spring boot и Java.

Мой контроллер AddUser, который на данный момент использует Mongorepository

 @PostMapping("/adduser")
//  @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<?> registerUser(@Valid @RequestBody SignupRequest signUpRequest) {
        /*
         * This controller Creates new user based on all the entities for the user
         * 
         */
        if (userRepository.existsByUsername(signUpRequest.getUsername())) {
            return ResponseEntity
                    .badRequest()
                    .body(new MessageResponse("Error: Username is already taken!"));
        }

        if (userRepository.existsByEmail(signUpRequest.getEmail())) {
            return ResponseEntity
                    .badRequest()
                    .body(new MessageResponse("Error: Email is already in use!"));
        }

        // Create new user's account
        User user = new User(signUpRequest.getUsername(), 
                             signUpRequest.getEmail(),
                             signUpRequest.getCustomername(),
                             signUpRequest.getCustomerid(),
                             signUpRequest.getDescription(),
                             encoder.encode(signUpRequest.getPassword()));
        

        Set<String> strRoles = signUpRequest.getRoles();
        Set<Role> roles = new HashSet<>();
      
        if (strRoles == null) {
            Role userRole = roleRepository.findByName(URole.ROLE_USER)
                    .orElseThrow(() -> new RuntimeException("Error: Role is not found."));
            roles.add(userRole);
        } else {
            strRoles.forEach(role -> {
                switch (role) {
                case "admin":
                    Role adminRole = roleRepository.findByName(URole.ROLE_ADMIN)
                            .orElseThrow(() -> new RuntimeException("Error: Role is not found."));
                    roles.add(adminRole);

                    break;
                
                default:
                    Role userRole = roleRepository.findByName(URole.ROLE_USER)
                            .orElseThrow(() -> new RuntimeException("Error: Role is not found."));
                    roles.add(userRole);
                }
            });
        }

        user.setRoles(roles);
        userRepository.save(user);

        return ResponseEntity.ok(new MessageResponse("User Added successfully!"));
    }
    ```
  

Комментарии:

1. Зачем вам нужна база данных 2 для ваших моделей. Я имею в виду, что на земле может быть причиной этого? Вы можете сохранить все свойства, связанные с БД, в своем приложении. файл yaml. Прокомментируйте тот, который вам не нужен. И когда вам это понадобится, раскомментируйте его и закомментируйте другие свойства БД. На самом деле это делается через config server. Где вы храните разные наборы свойств для разных сред, таких как Production, Dev, QA и т.д…. В какой бы среде вы ни нуждались, просто добавьте значение в spring.profile. Spring boot считает значение с сервера конфигурации.

2. Правильно, я понимаю, так что это требование от разных клиентов, в которых некоторым из них нужен Mongo, а другим нужен PostgreSQL. Проблема с вашим приложением заключается в том, что на основе этих моделей я буду правильно создавать репозитории? Например, служба реализации UserService использует Userepository, построенный на модели пользователя mongo, для извлечения данных из БД. Я не могу продолжать комментировать свой код и там. Должно быть лучшее решение. В этой статье кое-что выглядит актуальным, но не уверен. dzone.com/articles/how-springboot-autoconfiguration-magic-works

3. Да .. это то, что я вам говорил. Используйте spring.profiles.active, чтобы указать на БД в соответствии с вашими требованиями. Как правило, в Dev env и prod env могут быть разные базы данных. По этой причине вы используете профили. но в том же приложении spring boot, если разные модели используют разные базы данных, вам необходимо настроить класс для чтения разных свойств источника данных для разных БД и соответствующим образом инициализировать ваш репозиторий. @Conditional также можно использовать.

4. Отлично, похоже, я в правильном направлении, но у меня все еще есть блок в моем понимании. Я отредактировал свой вопрос с помощью контроллера «addUser», который я использую. Как вы можете видеть, у меня там есть пользовательское хранилище. Мой вопрос в том, когда у меня есть база данных PostGres, о которой идет речь, тогда мне нужно будет создать репозиторий для этого и в этом сценарии, как изменится этот код? Извините, если это должен быть вопрос новичка. но я зациклен на этой части

Ответ №1:

Я бы использовал аннотацию @ConditonalOnProperty здесь для двух конфигураций (одна для Mongo и одна для PostgerSql) и добавил enabled config-property во время выполнения (для конфигурации, которую вы хотите загрузить)

Вот упрощенный пример.

  public static void main(String[] args) {
        SpringApplication application = new SpringApplication(DemoApplication.class);
        Properties properties = new Properties();
        properties.put("databaseFoo.enabled", "true");
        application.setDefaultProperties(properties);
        application.run(args);
    }
    then on the config needed when run time is databaseFoo you can annotate the bean as such
    
        @ConditionalOnProperty(
            value="databaseFoo.enabled",
            havingValue = "true")
    public class DatabaseFooConfig {
    Then the other bean could have the following conditional properties
    
            @ConditionalOnProperty(
            value="databaseBar.nabled",
            havingValue = "false",
            matchIfMissing= true)
    public class DataBaseBarConfig {
  

Комментарии:

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

2. В DatabaseBarConfig вы создаете необходимые вам компоненты конфигурации. Например, один компонент конфигурации для предоставления источника данных, другой для управления транзакциями .. и т.д. Компоненты будут созданы «зарегистрированными в springContext», если для флага установлено значение true. Иначе они не будут созданы,