Spring項目中自動列印執行sql和耗時,這款神級插件你值得擁有

程序員拾山 發佈 2022-12-04T08:42:48.743083+00:00

簡介P6Spy是一個輕量級框架,只需簡單配置,就可以無縫地攔截和記錄資料庫執行sql以及耗時,而無需對現有應用程式進行代碼更改。其原理是包裝原有的數據源,在sql執行前後做一些功能增強。

簡介

P6Spy是一個輕量級框架,只需簡單配置,就可以無縫地攔截和記錄資料庫執行sql以及耗時,而無需對現有應用程式進行代碼更改。其原理是包裝原有的數據源,在sql執行前後做一些功能增強。

集成方式

P6Spy提供了3種集成方式:

  1. Datasource way:如果我們的項目中使用了自定義的DataSource,可以使用P6DataSource對原有的數據源進行包裝,只需將自定義的DataSource傳入P6DataSource的構造函數中即可,這也是使用P6Spy最簡單的一種方式。
  2. Connection URL way:由於我們一般都是用框架提供的數據源,所以P6Spy也提供了對連結進行包裝的功能。只要在配置數據源時,稍微修改配置的屬性,即可使用P6Spy的功能。
  3. Spring Boot autoconfiguration:隨著Spring boot的流行,P6Spy還提供了基於Springboot的自動配置。

如何使用

本節主要針對第2種方式的使用進行講解。

步驟一,引入P6Spy。

<dependency>
  <groupId>p6spy</groupId>
  <artifactId>p6spy</artifactId>
  <version>3.9.1</version>
</dependency>

步驟二,修改數據源的配置。

spring:
  datasource:
                //此處的URL增加了p6spy
    url: jdbc:p6spy:MySQL://127.0.0.1:3306/dbName
    username: username
    password: pwd123456
    //將普通的mysql驅動替換為P6SpyDriver
    driver-class-name: com.p6spy.engine.spy.P6SpyDriver

步驟三,新建spy.properties文件,放在resources目錄下。

module.log=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
//注意此行配置
logMessageFormat=com.shishan.demo2023.bean.P6SpyMessageFormattingStrategy
appender=com.p6spy.engine.spy.appender.Slf4JLogger
deregisterdrivers=true
useprefix=true
excludecategories=info,debug,result,resultset
dateformat=yyyy-MM-dd HH:mm:ss
outagedetection=true
outagedetectioninterval=2
filter=true
exclude=QRTZ_JOB_DETAILS,QRTZ_TRIGGERS,QRTZ_CRON_TRIGGERS,QRTZ_LOCKS,QRTZ_FIRED_TRIGGERS,QRTZ_PAUSED_TRIGGER_GRPS,QRTZ_SCHEDULER_STATE

需要注意配置參數logMessageFormat,這裡需要指定一個類,這個類實現MessageFormattingStrategy即可自由列印我們的sql。

步驟四,新建一個類實現MessageFormattingStrategy,並重寫formatMessage方法。

@Slf4j
public class P6SpyMessageFormattingStrategy implements MessageFormattingStrategy {

    @Override
    public String formatMessage(int connectionId, String now, long elapsed, 
                                String category, String prepared, String sql, String url) {
      //執行時間大於1000ms時,列印慢sql  
      if (elapsed > 1000) {
            log.warn("slow sql,耗時:{}ms,sql:{}", elapsed, sql.replaceAll("[\\s]+", " "));
        }
        return StrUtil.format("耗時:{}ms,Sql:{}",
                elapsed,
                category.equals("commit") || category.equals("rollback") ? category :
                        sql.replaceAll("[\\s]+", " "));
    }
}

formatMessage方法提供了7個參數,這7個參數大家可以自由組合,其中常用的參數有elapsed和sql。

簡單介紹一下這7個參數的具體含義:
1,connectionId:當前connection的id。

2,now:當前時間,毫秒值。

3,elapsed:sql執行的耗時。需要注意的是這裡的耗時指的是從發送sql到伺服器截止到收到伺服器響應結果的總耗時,而不是sql本身在伺服器的執行時間。

4,category:操作的類型,比如查詢,更新,commit,rollback等。

5,prepared:編譯後的sql,不列印具體的參數。

6,sql:具體的執行sql,參數占位符會被真正的參數值替換。

7,url:當前的資料庫連接。

效果

經過以上4個步驟,P6Spy就可以幫助我們自動列印執行的sql了。我們新建一個controller看看具體的效果。

@RestController
@RequestMapping(value = "/demo")
public class DemoController {

    @Resource
    private UserRepository userRepository;

    @RequestMapping(value = "/test")
    public ResponseEntity<Object> test() {
        User user = new User();
        user.setName("張三");
        user.setPwd("123");
        User save = this.userRepository.save(user);
        System.out.println(JSON.toJSONString(save));

        Iterable<User> all = this.userRepository.findAll();
        all.forEach(value -> System.out.println(JSON.toJSONString(value)));
        return ResponseEntity.ok().build();
    }
}

啟動項目,訪問http://localhost:8080/demo/test,看一下控制台的列印效果:

與Mybatis Plus的集成

由於很多的Spring項目也使用了Mybatis Plus,所以MP也提供了對P6Spy的支持。使用方式也很簡單,只需對步驟二稍微做一點修改即可。

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/db
    username: username
    password: pwd123456
    driver-class-name: com.mysql.cj.jdbc.Driver
  //增加一個配置即可使用p6spy的功能
  p6spy:true


最後

P6Spy通過對數據源的包裝,進而實現了一系列的功能增強,讓我們可以方便的列印sql執行情況。但是相應的,如果在生產環境開啟p6spy的列印功能,對性能還是由一定的影響的。

建議大家在測試環境開啟此功能,對跟蹤、修復bug都很有幫助。

學習技術,分享技術,期待與大家共同進步,也感謝您的點讚與關注。

關鍵字: