如何在spring boot中使用环境变量动态设置tableName?

时间:2022-05-29 23:17:08

I am using AWS ECS to host my application and using DynamoDB for all database operations. So I'll have same database with different table names for different environments. Such as "dev_users" (for Dev env), "test_users" (for Test env), etc.. (This is how our company uses same Dynamo account for different environments)

我使用AWS ECS来托管我的应用程序并使用DynamoDB进行所有数据库操作。所以我将为不同的环境提供具有不同表名的相同数据库。例如“dev_users”(对于Dev env),“test_users”(对于测试环境)等。(这就是我们公司在不同环境中使用相同的Dynamo帐户的方式)

So I would like to change the "tableName" of the model class using the environment variable passed through "AWS ECS task definition" environment parameters.

所以我想使用通过“AWS ECS任务定义”环境参数传递的环境变量来更改模型类的“tableName”。

For Example.

My Model Class is:

我的模型类是:

@DynamoDBTable(tableName = "dev_users")
public class User {

Now I need to replace the "dev" with "test" when I deploy my container in test environment. I know I can use

现在,当我在测试环境中部署容器时,我需要用“test”替换“dev”。我知道我可以用

@Value("${DOCKER_ENV:dev}")

to access environment variables. But I'm not sure how to use variables outside the class. Is there any way that I can use the docker env variable to select my table prefix?

访问环境变量。但我不确定如何在课外使用变量。有什么办法可以使用docker env变量来选择我的表前缀吗?

My Intent is to use like this:

我的意图是这样使用:

如何在spring boot中使用环境变量动态设置tableName?

I know this not possible like this. But is there any other way or work around for this?

我知道这不可能是这样的。但有没有其他方法或解决这个问题?

Edit 1:

I am working on the Rahul's answer and facing some issues. Before writing the issues, I'll explain the process I followed.

我正在研究Rahul的答案并面临一些问题。在写这些问题之前,我将解释我遵循的过程。

Process:

  1. I have created the beans in my config class (com.myapp.users.config).
  2. 我在我的配置类(com.myapp.users.config)中创建了bean。

  3. As I don't have repositories, I have given my Model class package name as "basePackage" path. (Please check the image)
  4. 由于我没有存储库,因此我将Model类包名称作为“basePackage”路径。 (请查看图片)

如何在spring boot中使用环境变量动态设置tableName?

  • For 1) I have replaced the "table name over-rider bean injection" to avoid the error.
  • 对于1)我已经替换了“表名over-rider bean injection”以避免错误。

  • For 2) I printed the name that is passing on to this method. But it is Null. So checking all the possible ways to pass the value here.
  • 对于2)我打印了传递给此方法的名称。但它是空的。所以检查所有可能的方法来传递值。

Check the image for error:

检查图像是否有错误:

如何在spring boot中使用环境变量动态设置tableName?

I haven't changed anything in my user model class as beans will replace the name of the DynamoDBTable when the beans got executed. But the table name over riding is happening. Data is pulling from the table name given at the Model Class level only.

我没有更改我的用户模型类中的任何内容,因为bean将在执行bean时替换DynamoDBTable的名称。但是骑行的桌名正在发生。数据仅从模型类级别给出的表名中提取。

What I am missing here?

我在这里缺少什么?

3 个解决方案

#1


1  

The table names can be altered via an altered DynamoDBMapperConfig bean.

可以通过更改的DynamoDBMapperConfig bean更改表名。

For your case where you have to Prefix each table with a literal, you can add the bean as such. Here the prefix can be the environment name in your case.

对于必须使用文字前缀每个表的情况,可以添加bean。这里的前缀可以是您案例中的环境名称。

 @Bean
public TableNameOverride tableNameOverrider() {
    String prefix = ... // Use @Value to inject values via Spring or use any logic to define the table prefix
    return TableNameOverride.withTableNamePrefix(prefix);
}

For more details check out the complete details here: https://github.com/derjust/spring-data-dynamodb/wiki/Alter-table-name-during-runtime

有关详细信息,请查看完整详细信息:https://github.com/derjust/spring-data-dynamodb/wiki/Alter-table-name-during-runtime

#2


1  

I up voted the other answer but here is an idea:

我投了另一个答案,但这是一个想法:

Create a base class with all your user details:

创建一个包含所有用户详细信息的基类:

@MappedSuperclass
public abstract class AbstractUser {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;
    private String firstName;
    private String lastName;

Create 2 implentations with different table names and spirng profiles:

使用不同的表名和spirng配置文件创建2个实现:

@Profile(value= {"dev","default"})
@Entity(name = "dev_user")
public class DevUser extends AbstractUser {
}

@Profile(value= {"prod"})
@Entity(name = "prod_user")
public class ProdUser extends AbstractUser {
}

Create a single JPA respository that uses the mapped super classs

创建一个使用映射超类的JPA存储库

public interface UserRepository extends CrudRepository<AbstractUser, Long> {
}

Then switch the implentation with the spring profile

然后使用弹簧轮廓切换实施

@RunWith(SpringJUnit4ClassRunner.class)
@DataJpaTest
@Transactional
public class UserRepositoryTest {

    @Autowired
    protected DataSource dataSource;

    @BeforeClass
    public static void setUp() {
        System.setProperty("spring.profiles.active", "prod");
    }

    @Test
    public void test1() throws Exception {

        DatabaseMetaData metaData = dataSource.getConnection().getMetaData();
        ResultSet tables = metaData.getTables(null, null, "PROD_USER", new String[] { "TABLE" });
        tables.next();
        assertEquals("PROD_USER", tables.getString("TABLE_NAME"));
    }
}

#3


0  

We have the same issue with regards to the need to change table names during runtime. We are using Spring-data-dynamodb 5.0.2 and the following configuration seems to provide the solutions that we need.

关于在运行时更改表名的需要,我们遇到了同样的问题。我们正在使用Spring-data-dynamodb 5.0.2,以下配置似乎提供了我们需要的解决方案。

First I annotated my bean accessor

首先,我注释了我的bean访问器

@EnableDynamoDBRepositories(dynamoDBMapperConfigRef = "getDynamoDBMapperConfig", basePackages = "my.company.base.package")

I also setup an environment variable called ENV_PREFIX which is Spring wired via SpEL.

我还设置了一个名为ENV_PREFIX的环境变量,它是通过SpEL连接的Spring。

@Value("#{systemProperties['ENV_PREFIX']}")
private String envPrefix;

Then I setup a TableNameOverride bean:

然后我设置一个TableNameOverride bean:

@Bean
public DynamoDBMapperConfig.TableNameOverride getTableNameOverride() {
    return DynamoDBMapperConfig.TableNameOverride.withTableNamePrefix(envPrefix);
}

Finally, I setup the DynamoDBMapperConfig bean using TableNameOverride injection. In 5.0.2, we had to setup a standard DynamoDBTypeConverterFactory in the DynamoDBMapperConfig builder to avoid NPE.:

最后,我使用TableNameOverride注入设置DynamoDBMapperConfig bean。在5.0.2中,我们必须在DynamoDBMapperConfig构建器中设置标准DynamoDBTypeConverterFactory以避免NPE:

@Bean
public DynamoDBMapperConfig getDynamoDBMapperConfig(DynamoDBMapperConfig.TableNameOverride tableNameOverride) {
    DynamoDBMapperConfig.Builder builder = new DynamoDBMapperConfig.Builder();
    builder.setTableNameOverride(tableNameOverride);
    builder.setTypeConverterFactory(DynamoDBTypeConverterFactory.standard());
    return builder.build();
}

In hind sight, I could have setup a DynamoDBTypeConverterFactory bean that returns a standard DynamoDBTypeConverterFactory and inject that into the getDynamoDBMapperConfig() method using the DynamoDBMapperConfig builder. But this will also do the job.

在后面的视线中,我可以设置一个DynamoDBTypeConverterFactory bean,它返回一个标准的DynamoDBTypeConverterFactory,并使用DynamoDBMapperConfig构建器将其注入到getDynamoDBMapperConfig()方法中。但这也将起到作用。

#1


1  

The table names can be altered via an altered DynamoDBMapperConfig bean.

可以通过更改的DynamoDBMapperConfig bean更改表名。

For your case where you have to Prefix each table with a literal, you can add the bean as such. Here the prefix can be the environment name in your case.

对于必须使用文字前缀每个表的情况,可以添加bean。这里的前缀可以是您案例中的环境名称。

 @Bean
public TableNameOverride tableNameOverrider() {
    String prefix = ... // Use @Value to inject values via Spring or use any logic to define the table prefix
    return TableNameOverride.withTableNamePrefix(prefix);
}

For more details check out the complete details here: https://github.com/derjust/spring-data-dynamodb/wiki/Alter-table-name-during-runtime

有关详细信息,请查看完整详细信息:https://github.com/derjust/spring-data-dynamodb/wiki/Alter-table-name-during-runtime

#2


1  

I up voted the other answer but here is an idea:

我投了另一个答案,但这是一个想法:

Create a base class with all your user details:

创建一个包含所有用户详细信息的基类:

@MappedSuperclass
public abstract class AbstractUser {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;
    private String firstName;
    private String lastName;

Create 2 implentations with different table names and spirng profiles:

使用不同的表名和spirng配置文件创建2个实现:

@Profile(value= {"dev","default"})
@Entity(name = "dev_user")
public class DevUser extends AbstractUser {
}

@Profile(value= {"prod"})
@Entity(name = "prod_user")
public class ProdUser extends AbstractUser {
}

Create a single JPA respository that uses the mapped super classs

创建一个使用映射超类的JPA存储库

public interface UserRepository extends CrudRepository<AbstractUser, Long> {
}

Then switch the implentation with the spring profile

然后使用弹簧轮廓切换实施

@RunWith(SpringJUnit4ClassRunner.class)
@DataJpaTest
@Transactional
public class UserRepositoryTest {

    @Autowired
    protected DataSource dataSource;

    @BeforeClass
    public static void setUp() {
        System.setProperty("spring.profiles.active", "prod");
    }

    @Test
    public void test1() throws Exception {

        DatabaseMetaData metaData = dataSource.getConnection().getMetaData();
        ResultSet tables = metaData.getTables(null, null, "PROD_USER", new String[] { "TABLE" });
        tables.next();
        assertEquals("PROD_USER", tables.getString("TABLE_NAME"));
    }
}

#3


0  

We have the same issue with regards to the need to change table names during runtime. We are using Spring-data-dynamodb 5.0.2 and the following configuration seems to provide the solutions that we need.

关于在运行时更改表名的需要,我们遇到了同样的问题。我们正在使用Spring-data-dynamodb 5.0.2,以下配置似乎提供了我们需要的解决方案。

First I annotated my bean accessor

首先,我注释了我的bean访问器

@EnableDynamoDBRepositories(dynamoDBMapperConfigRef = "getDynamoDBMapperConfig", basePackages = "my.company.base.package")

I also setup an environment variable called ENV_PREFIX which is Spring wired via SpEL.

我还设置了一个名为ENV_PREFIX的环境变量,它是通过SpEL连接的Spring。

@Value("#{systemProperties['ENV_PREFIX']}")
private String envPrefix;

Then I setup a TableNameOverride bean:

然后我设置一个TableNameOverride bean:

@Bean
public DynamoDBMapperConfig.TableNameOverride getTableNameOverride() {
    return DynamoDBMapperConfig.TableNameOverride.withTableNamePrefix(envPrefix);
}

Finally, I setup the DynamoDBMapperConfig bean using TableNameOverride injection. In 5.0.2, we had to setup a standard DynamoDBTypeConverterFactory in the DynamoDBMapperConfig builder to avoid NPE.:

最后,我使用TableNameOverride注入设置DynamoDBMapperConfig bean。在5.0.2中,我们必须在DynamoDBMapperConfig构建器中设置标准DynamoDBTypeConverterFactory以避免NPE:

@Bean
public DynamoDBMapperConfig getDynamoDBMapperConfig(DynamoDBMapperConfig.TableNameOverride tableNameOverride) {
    DynamoDBMapperConfig.Builder builder = new DynamoDBMapperConfig.Builder();
    builder.setTableNameOverride(tableNameOverride);
    builder.setTypeConverterFactory(DynamoDBTypeConverterFactory.standard());
    return builder.build();
}

In hind sight, I could have setup a DynamoDBTypeConverterFactory bean that returns a standard DynamoDBTypeConverterFactory and inject that into the getDynamoDBMapperConfig() method using the DynamoDBMapperConfig builder. But this will also do the job.

在后面的视线中,我可以设置一个DynamoDBTypeConverterFactory bean,它返回一个标准的DynamoDBTypeConverterFactory,并使用DynamoDBMapperConfig构建器将其注入到getDynamoDBMapperConfig()方法中。但这也将起到作用。