You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot应用中SQL脚本能否引用环境变量?如何实现?

问题

在使用JUnit的@Sql注解执行SQL测试脚本时,脚本里的用户名、密码等数据是硬编码的,想实现像Java代码中引用属性文件键值对那样的动态替换,询问是否可行及具体实现方法。

可行实现方法

方法一:Spring属性占位符替换(推荐,通用性强)

这是最常用的方案,利用Spring的属性解析能力替换SQL脚本中的占位符:

  1. 定义属性文件
    在src/test/resources下创建属性文件(比如test-accounts.properties),写入需要动态替换的变量:
test.account.mickey.username=mickey_m
test.account.mickey.password=$2y$10$ZdqfOo1vwdHJJGnkmGrw/OUelZcU9ZfRFaX/RMN3XniXH96eTkB1e
test.account.minerva.username=minerva_m
test.account.minerva.password=$2y$10$PiZxGGi904rCLdTSGY1ycuQhcEtQrP1u74KvQ2IEuk5Jh18Ml.6xO
  1. 配置测试类
    在测试类上添加@TestPropertySource加载属性文件,同时在@Sql注解中配置SqlConfig开启占位符解析:
@Sql(
    executionPhase = BEFORE_TEST_METHOD,
    value = BASE_SCRIPT_PATH + "CreateCommentTest/before.sql",
    config = @SqlConfig(
        placeholderPrefix = "${",
        placeholderSuffix = "}"
    )
)
@TestPropertySource("classpath:test-accounts.properties")
@Test
public void createCommentTest() throws Exception {
    // 测试逻辑
}
  1. 修改SQL脚本
    把硬编码的值替换成${属性键}的占位符:
INSERT INTO permissions(id, name, created_date, modified_date)
VALUES (1, 'ADMIN', current_timestamp, current_timestamp),
       (2, 'MODERATOR', current_timestamp, current_timestamp),
       (3, 'USER', current_timestamp, current_timestamp);

INSERT INTO accounts(id, username, password, enabled, created_date, modified_date)
VALUES (1, '${test.account.mickey.username}', '${test.account.mickey.password}', true, current_timestamp, current_timestamp),
       (2, '${test.account.minerva.username}', '${test.account.minerva.password}', true, current_timestamp, current_timestamp);

INSERT INTO accounts_permissions(account_id, permission_id)
VALUES (1, 3),
       (2, 3);

方法二:手动通过JdbcTemplate执行参数化SQL

如果需要更灵活的控制(比如动态生成数据),可以直接在Java代码中读取属性,用JdbcTemplate执行带参数的SQL:

  1. 注入依赖与属性
@Autowired
private JdbcTemplate jdbcTemplate;

@Value("${test.account.mickey.username}")
private String mickeyUsername;

@Value("${test.account.mickey.password}")
private String mickeyPassword;

@Value("${test.account.minerva.username}")
private String minervaUsername;

@Value("${test.account.minerva.password}")
private String minervaPassword;
  1. 在测试方法中执行初始化
@Test
public void createCommentTest() throws Exception {
    // 初始化权限数据
    String insertPermissionSql = "INSERT INTO permissions(id, name, created_date, modified_date) VALUES (?, ?, current_timestamp, current_timestamp)";
    jdbcTemplate.update(insertPermissionSql, 1, "ADMIN");
    jdbcTemplate.update(insertPermissionSql, 2, "MODERATOR");
    jdbcTemplate.update(insertPermissionSql, 3, "USER");

    // 初始化账户数据
    String insertAccountSql = "INSERT INTO accounts(id, username, password, enabled, created_date, modified_date) VALUES (?, ?, ?, ?, current_timestamp, current_timestamp)";
    jdbcTemplate.update(insertAccountSql, 1, mickeyUsername, mickeyPassword, true);
    jdbcTemplate.update(insertAccountSql, 2, minervaUsername, minervaPassword, true);

    // 关联账户与权限
    String insertAccountPermSql = "INSERT INTO accounts_permissions(account_id, permission_id) VALUES (?, ?)";
    jdbcTemplate.update(insertAccountPermSql, 1, 3);
    jdbcTemplate.update(insertAccountPermSql, 2, 3);

    // 执行测试逻辑
}

方法三:数据库原生变量替换(依赖特定数据库)

部分数据库支持自身的变量语法,比如PostgreSQL的\set命令,但这种方法通用性差,仅适合固定使用某类数据库的场景:

\set mickey_username 'mickey_m'
\set mickey_password '$2y$10$ZdqfOo1vwdHJJGnkmGrw/OUelZcU9ZfRFaX/RMN3XniXH96eTkB1e'

INSERT INTO accounts(id, username, password, enabled, created_date, modified_date)
VALUES (1, :mickey_username, :mickey_password, true, current_timestamp, current_timestamp);

注意:这种方式需要确保SQL执行器支持数据库的原生语法,Spring默认的脚本执行器可能无法解析,需额外配置。


内容的提问来源于stack exchange,提问作者Sergey Zolotarev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 23:12:41