欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring項目里將SQL語句寫在.sql文件中的方法

 更新時間:2017年01月19日 08:44:22   作者:隔葉黃鶯  
這篇文章主要介紹了Spring項目里如何將SQL語句寫在.sql文件中的方法,文中給出了詳細(xì)的介紹和示例代碼,相信對大家的學(xué)習(xí)或者工作具有一定的參考借鑒價值,有需要的朋友們下面來一起看看吧。

前言

我們在使用 JDBC 時, 如果把所有的 SQL 語句全寫在 Java 文件中, 由于 Java 不支持 Here Document, 多行字符串要么用加號, 要么用 Java 8 的 String.join() 方法來連接, 同時不能對 SQL 語句進(jìn)行語法加亮, 所以這樣的 SQL 字符串閱讀性很差. 別說為何不用 Hibernate 之類的而不直接寫原始的 SQL 語句, 在操作復(fù)雜的系統(tǒng)時還是會用到 JdbcTemplate 吧.

所以我們希望能把 SQL 語句寫在單獨的 *.sql 文件里, 這樣很多編輯器就能語法高亮顯示, 或在輸入時還能得到智能提示.

 有種辦法是把 *.sql 用作為屬性文件, 那么在其中定義多行的 SQL 語句時就得這樣

select.user=select id, firstname, lastname, address \
 from users \
 where id=?

加載后就能用 getProperty("select.user") 來引用相應(yīng)的語句了. 屬性文件的換行與 Bash  一樣, 也是用  \, 但如此, 則 *.sql 并非一個純粹的 SQL 文件, 不能正確的進(jìn)行語法加亮, 一旦寫上 SQL 的注釋 -- 就更是在添亂了.

所以我們的第二個方案是: 首先 *.sql 就該是一個真正的  SQL 文件, 而不是偽裝的屬性文件, 為了能在程序中引用每一條 SQL 語句, 我們該如何表示各自的 Key 呢? 這里的靈感仍然是來自于 Linux Shell, 在 Linux Shell 中指定執(zhí)行環(huán)境的用了特殊的注釋方式 #!, 如

#!/bin/bash
#!/usr/bin/env python

依葫蘆畫瓢, SQL 的標(biāo)準(zhǔn)單注釋是 --, 因而我們也創(chuàng)建一個特別的注釋 --!, , 其后的字符串就是接下來 SQL 語句的 Key.

舉例如下

--!select.user
select id, firstname, lastname, address
 from users
 where id=?

--!update.user
update ........

--! 之后是 key select.user, 往下在未到文件結(jié)束, 或是遇到下一個 --! 之前就是這個 key 對應(yīng)的完整 SQL 語句的內(nèi)容.

本文以 Spring 項目為例來演示如何應(yīng)這個 SQL 文件, 其實在其他類型的 Java 項目中同樣可以借鑒.

因為這是一個真正的 SQL 文件, 所以在 Spring 中我們無法直接作為屬性文件來加載. 假設(shè)我們把該文件存儲為 src/resources/sql/queries.sql, 因此我們不能直接用

@PropertySource(value = "classpath:sql/queries.sql")
public class AppConfig { ...... }

加載該文件.

幸好 PropertySource 注解還有一個屬性 factory, 類型為 PropertySourceFactory, 這就是我們作文章的地方, 馬上著手自定義一個 SqlPropertySourceFactory, 在其中總有辦法把一個 *.sql 的內(nèi)容轉(zhuǎn)換為 Properties. 因此將來我們要加載  sql/queries.sql 文件所用的注解形式就會是

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

接下來就是本文的關(guān)鍵, 看看 SqlPropertySourceFactory 的實現(xiàn)

SqlPropertySourceFactory.java

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 文件內(nèi)容如下:

--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=?

最后是如何應(yīng)用它, 我們以 SpringBoot 的方式來啟動一個 Spring 項目

DemoApplication.java

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;
 }
}

既然已轉(zhuǎn)換為普通的屬性了, 所以可以通過表達(dá)式 ${key} env.getProperty("key") 來引用它們.

執(zhí)行上面的代碼, 輸出如下:

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, ?, ?, ?)

就這么簡單. 當(dāng)然那個 *.sql 文件最好是寫得嚴(yán)謹(jǐn)一些, 我們可以將來對 SqlPropertySourceFactory 進(jìn)行逐步完善以應(yīng)對更多的可能. 不管怎么說它是一個真正的 SQL 文件, 在代碼中也能像任何別的屬性那么方便的引用其中定義的  SQL 語句了.

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流。

相關(guān)文章

  • 一文詳解Java中的注解(Annotation)

    一文詳解Java中的注解(Annotation)

    在Java中注解(Annotation)引入始于Java5,用來描述Java代碼的元信息,通常情況下注解不會直接影響代碼的執(zhí)行,盡管有些注解可以用來做到影響代碼執(zhí)行,這篇文章主要給大家介紹了關(guān)于Java中注解(Annotation)的相關(guān)資料,需要的朋友可以參考下
    2024-03-03
  • SpringBoot+Hutool實現(xiàn)圖片驗證碼的示例代碼

    SpringBoot+Hutool實現(xiàn)圖片驗證碼的示例代碼

    圖片驗證碼在注冊、登錄、交易、交互等各類場景中都發(fā)揮著巨大作用,本文主要介紹了SpringBoot+Hutool實現(xiàn)圖片驗證碼的示例代碼,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • Java小程序賽馬游戲?qū)崿F(xiàn)過程詳解

    Java小程序賽馬游戲?qū)崿F(xiàn)過程詳解

    這篇文章主要介紹了Java小程序賽馬游戲?qū)崿F(xiàn)過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-03-03
  • Java調(diào)用JavaScript實現(xiàn)字符串計算器代碼示例

    Java調(diào)用JavaScript實現(xiàn)字符串計算器代碼示例

    這篇文章主要介紹了Java調(diào)用JavaScript實現(xiàn)字符串計算器代碼示例,具有一定參考價值,需要的朋友可以了解下。
    2017-12-12
  • Spring Boot統(tǒng)一異常處理最佳實踐(拓展篇)

    Spring Boot統(tǒng)一異常處理最佳實踐(拓展篇)

    這篇文章主要給大家介紹了關(guān)于Spring Boot統(tǒng)一異常處理最佳實踐(拓展篇)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-02-02
  • mybatis中的緩存機(jī)制

    mybatis中的緩存機(jī)制

    這篇文章主要介紹了mybatis中的緩存機(jī)制用法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • Java網(wǎng)絡(luò)IO模型詳解(BIO、NIO、AIO)

    Java網(wǎng)絡(luò)IO模型詳解(BIO、NIO、AIO)

    Java支持BIO、NIO和AIO三種網(wǎng)絡(luò)IO模型,BIO是同步阻塞模型,適用于連接數(shù)較少的場景,NIO是同步非阻塞模型,適用于處理多個連接,支持自JDK1.4起,AIO是異步非阻塞模型,適用于異步操作多的場景,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-10-10
  • springboot swagger不顯示接口的問題及解決

    springboot swagger不顯示接口的問題及解決

    這篇文章主要介紹了springboot swagger不顯示接口的問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • java線程同步操作實例詳解

    java線程同步操作實例詳解

    這篇文章主要介紹了java線程同步操作,結(jié)合實例形式分析了Java線程同步與鎖機(jī)制相關(guān)原理、操作技巧與注意事項,需要的朋友可以參考下
    2018-09-09
  • 詳解Java注解知識點

    詳解Java注解知識點

    這篇文章主要介紹了詳解Java注解知識點,文中有非常詳細(xì)的代碼示例,對正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-05-05

最新評論