Spring项目里将SQL语句写在.sql文件中的方法

2025-05-29 0 64

前言

我们在使用 JDBC 时, 如果把所有的 SQL 语句全写在 Java 文件中, 由于 Java 不支持 Here Document, 多行字符串要么用加号, 要么用 Java 8 的 String.join() 方法来连接, 同时不能对 SQL 语句进行语法加亮, 所以这样的 SQL 字符串阅读性很差. 别说为何不用 Hibernate 之类的而不直接写原始的 SQL 语句, 在操作复杂的系统时还是会用到 JdbcTemplate 吧.

所以我们希望能把 SQL 语句写在单独的 *.sql 文件里, 这样很多编辑器就能语法高亮显示, 或在输入时还能得到智能提示.

有种办法是把 *.sql 用作为属性文件, 那么在其中定义多行的 SQL 语句时就得这样

?

1

2

3
select.user=select id, firstname, lastname, address \\

from users \\

where id=?

加载后就能用 getProperty("select.user") 来引用相应的语句了. 属性文件的换行与 Bash 一样, 也是用 \\, 但如此, 则 *.sql 并非一个纯粹的 SQL 文件, 不能正确的进行语法加亮, 一旦写上 SQL 的注释 — 就更是在添乱了.

所以我们的第二个方案是: 首先 *.sql 就该是一个真正的 SQL 文件, 而不是伪装的属性文件, 为了能在程序中引用每一条 SQL 语句, 我们该如何表示各自的 Key 呢? 这里的灵感仍然是来自于 Linux Shell, 在 Linux Shell 中指定执行环境的用了特殊的注释方式 #!, 如

?

1

2
#!/bin/bash

#!/usr/bin/env python

依葫芦画瓢, SQL 的标准单注释是 –, 因而我们也创建一个特别的注释 –!, , 其后的字符串就是接下来 SQL 语句的 Key.

举例如下

?

1

2

3

4

5

6

7
--!select.user

select id, firstname, lastname, address

from users

where id=?

--!update.user

update ........

–! 之后是 key select.user, 往下在未到文件结束, 或是遇到下一个 –! 之前就是这个 key 对应的完整 SQL 语句的内容.

本文以 Spring 项目为例来演示如何应这个 SQL 文件, 其实在其他类型的 Java 项目中同样可以借鉴.

因为这是一个真正的 SQL 文件, 所以在 Spring 中我们无法直接作为属性文件来加载. 假设我们把该文件存储为 src/resources/sql/queries.sql, 因此我们不能直接用

?

1

2
@PropertySource(value = "classpath:sql/queries.sql")

public class AppConfig { ...... }

加载该文件.

幸好 PropertySource 注解还有一个属性 factory, 类型为 PropertySourceFactory, 这就是我们作文章的地方, 马上着手自定义一个 SqlPropertySourceFactory, 在其中总有办法把一个 *.sql 的内容转换为 Properties. 因此将来我们要加载 sql/queries.sql 文件所用的注解形式就会是

?

1

2
@PropertySource(value = "classpath:sql/queries.sql", factory = SqlPropertySourceFactory.class)

public class AppConfig { ......}

接下来就是本文的关键, 看看 SqlPropertySourceFactory 的实现

SqlPropertySourceFactory.java

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52
package cc.unmi;

import org.springframework.core.env.MapPropertySource;

import org.springframework.core.env.PropertySource;

import org.springframework.core.io.support.EncodedResource;

import org.springframework.core.io.support.PropertySourceFactory;

import java.io.BufferedReader;

import java.io.IOException;

import java.util.*;

import java.util.stream.Collectors;

public class SqlPropertySourceFactory implements PropertySourceFactory {

private static final String KEY_LEADING = "--!";

@Override

public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {

Deque<Pair> queries = new LinkedList<>();

new BufferedReader(resource.getReader()).lines().forEach(line -> {

if (line.startsWith(KEY_LEADING)) {

queries.addLast(new Pair(line.replaceFirst(KEY_LEADING, "")));

} else if (line.startsWith("--")) {

//skip comment line

} else if (!line.trim().isEmpty()) {

Optional.ofNullable(queries.getLast()).ifPresent(pair -> pair.lines.add(line));

}

});

Map<String, Object> sqlMap = queries.stream()

.filter(pair -> !pair.lines.isEmpty())

.collect(Collectors.toMap(pair -> pair.key,

pair -> String.join(System.lineSeparator(), pair.lines),

(r, pair) -> r, LinkedHashMap::new));

System.out.println("Configured SQL statements:");

sqlMap.forEach((s, o) -> System.out.println(s + "=" + o));

return new MapPropertySource(resource.toString(), sqlMap);

}

private static class Pair {

private String key;

private List<String> lines = new LinkedList<>();

Pair(String key) {

this.key = key;

}

}

}

我们定义的 src/resources/sql/queries.sql 文件内容如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16
--external queries in this file

--!select_users_by_id

select id, firstname, lastname, address

from users where id=?

--!add_user

insert users(id, firstname, lastname, address)

values(DEFAULT, ?, ?, ?)

--

--!no_statement

---

--!update

update users set firstname=? where id=?

最后是如何应用它, 我们以 SpringBoot 的方式来启动一个 Spring 项目

DemoApplication.java

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35
package cc.unmi;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.context.EnvironmentAware;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.PropertySource;

import org.springframework.core.env.Environment;

@SpringBootApplication

@PropertySource(value = "classpath:sql/queries.sql", factory = SqlPropertySourceFactory.class)

public class DemoApplication implements EnvironmentAware {

private Environment env;

@Value("${add_user}")

private String sqlAddUser;

@Bean

public String testBean() {

System.out.println("SQL_1:" + env.getProperty("select_users_by_id"));

System.out.println("SQL_2:" + sqlAddUser);

return "testBean";

}

public static void main(String[] args) {

SpringApplication.run(DemoApplication.class, args);

}

@Override

public void setEnvironment(Environment environment) {

env = environment;

}

}

既然已转换为普通的属性了, 所以可以通过表达式 ${key} env.getProperty("key") 来引用它们.

执行上面的代码, 输出如下:

?

1

2

3

4

5

6

7

8

9

10
Configured SQL statements:

select_users_by_id=select id, firstname, lastname, address

from users where id=?

add_user=insert users(id, firstname, lastname, address)

values(DEFAULT, ?, ?, ?)

update=update users set firstname=? where id=?

SQL_1:select id, firstname, lastname, address

from users where id=?

SQL_2:insert users(id, firstname, lastname, address)

values(DEFAULT, ?, ?, ?)

就这么简单. 当然那个 *.sql 文件最好是写得严谨一些, 我们可以将来对 SqlPropertySourceFactory 进行逐步完善以应对更多的可能. 不管怎么说它是一个真正的 SQL 文件, 在代码中也能像任何别的属性那么方便的引用其中定义的 SQL 语句了.

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。

原文链接:http://unmi.cc/spring-external-sql-statements/

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 Spring项目里将SQL语句写在.sql文件中的方法 https://www.kuaiidc.com/119377.html

相关文章

发表评论
暂无评论