最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MyBatis的SQL執(zhí)行結(jié)果和客戶端執(zhí)行結(jié)果不一致問題排查

 更新時(shí)間:2023年04月10日 09:24:52   作者:modelmd  
本文主要介紹了MyBatis的SQL執(zhí)行結(jié)果和客戶端執(zhí)行結(jié)果不一致問題排查,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

最近遇到一個(gè)調(diào)試很久的問題,MyBatis 查詢 Oracle 數(shù)據(jù)庫查詢結(jié)果與在客戶端查詢結(jié)果不一致。

問題引入

測(cè)試表、測(cè)試數(shù)據(jù)

創(chuàng)建測(cè)試表、序列

CREATE TABLE t_test_table (
"ID" NUMBER(18,0), 
"CREATE_TIME" TIMESTAMP(6),
"FIELD_TYPE" CHAR(20),
CONSTRAINT pk_id PRIMARY KEY(ID)
)

CREATE SEQUENCE seq_t_test_table;

插入測(cè)試數(shù)據(jù)

INSERT INTO t_test_table ("ID", "CREATE_TIME", "FIELD_TYPE") VALUES (SEQ_T_TEST_TABLE.nextval, SYSDATE - NUMTODSINTERVAL(1, 'DAY'), 'Integer');
INSERT INTO t_test_table ("ID", "CREATE_TIME", "FIELD_TYPE") VALUES (SEQ_T_TEST_TABLE.nextval, SYSDATE - NUMTODSINTERVAL(1, 'HOUR'), 'Double');
INSERT INTO t_test_table ("ID", "CREATE_TIME", "FIELD_TYPE") VALUES (SEQ_T_TEST_TABLE.nextval, SYSDATE - NUMTODSINTERVAL(1, 'MINUTE'), 'Long');

查詢數(shù)據(jù)是否插入成功

問題介紹

MyBatis xml 配置

<select id="selectByFieldType" resultType="com.scd.model.po.TestTable">
        SELECT * FROM T_TEST_TABLE WHERE FIELD_TYPE = #{filedType}
</select>

運(yùn)行輸出的日志

20:26:08.678 [main] DEBUG com.scd.mapper.OracleBatchSeqMapper.selectByFieldType - ==>  Preparing: SELECT * FROM T_TEST_TABLE WHERE FIELD_TYPE = ?
20:26:08.906 [main] DEBUG com.scd.mapper.OracleBatchSeqMapper.selectByFieldType - ==> Parameters: Double(String)
20:26:09.013 [main] DEBUG com.scd.mapper.OracleBatchSeqMapper.selectByFieldType - <==      Total: 0

這里顯示輸出的結(jié)果為0條,之前有插入數(shù)據(jù)的,明顯出錯(cuò)了,于是把sql語句復(fù)制到DBeaver客戶端執(zhí)行的時(shí)候,是可以查詢數(shù)據(jù)的

排查問題

日志中的SQL 和 客戶端的 SQL 一致的,唯一不同的就是日志中是使用占位符形式,也就是預(yù)編譯的SQL, 而客戶端直接執(zhí)行的SQL。首先第一步就是把xml中的預(yù)編譯SQL修改成字符串拼接的形式

  <select id="selectByFieldType" resultType="com.scd.model.po.TestTable">
        SELECT * FROM T_TEST_TABLE WHERE FIELD_TYPE = '${filedType}'
    </select>

執(zhí)行輸出的結(jié)果確實(shí)有一條,和客戶端的一致,運(yùn)行日志結(jié)果如下

20:38:45.603 [main] DEBUG com.scd.mapper.OracleBatchSeqMapper.selectByFieldType - ==>  Preparing: SELECT * FROM T_TEST_TABLE WHERE FIELD_TYPE = 'Double'
20:38:45.747 [main] DEBUG com.scd.mapper.OracleBatchSeqMapper.selectByFieldType - ==> Parameters: 
20:38:45.844 [main] DEBUG com.scd.mapper.OracleBatchSeqMapper.selectByFieldType - <==      Total: 1

用這種方式雖然可以解決,但是很多編碼規(guī)范在 xml 中不允許配置 $,防止SQL注入。還需要找一下為啥 # 的形式不能得到正確的結(jié)果。

調(diào)試 MyBatis源碼

對(duì)比拼接 SQL 和 預(yù)編譯的 SQL,區(qū)別在于設(shè)置參數(shù)填充,找到 MyBatis中這一塊的執(zhí)行邏輯,經(jīng)過調(diào)試,定位到設(shè)置參數(shù)的代碼在 org.apache.ibatis.scripting.defaults.DefaultParameterHandler#setParameters

由于xml中未指定TypeHandler,程序使用默認(rèn)的 UnknownTypeHandler。根據(jù)參數(shù)的類型去匹配TypeHandler

參數(shù) “Double” 是字符串,匹配到了 StringTypeHandler

繼續(xù)調(diào)試,發(fā)現(xiàn)設(shè)置參數(shù)的代碼段如下

發(fā)現(xiàn)整個(gè)設(shè)置數(shù)據(jù)的過程沒有啥問題呀,于是把問題簡化一下,弄成JDBC的方式執(zhí)行看看。

JDBC 執(zhí)行 SQL

按照 MyBtatis 的執(zhí)行過程,把代碼簡化成如下

import org.junit.Test;
import java.sql.*;
import java.util.Properties;

/**
 * @author James
 * @date 2022/12/10 19:02
 */
public class OracleJdbc {

    private static final String driver = "oracle.jdbc.driver.OracleDriver";

    private static final String url = "jdbc:oracle:thin:@localhost:1521/TEST";

    private static final String userName = "TEST_USER";

    private static final String password = "TEST_USER";

    static {
        // 加載驅(qū)動(dòng)
        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public Connection createConnection(String url, String userName, String password) {
        Connection connection = null;
        try {
            connection = DriverManager.getConnection(url, userName, password);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }

    @Test
    public void testStrQuery() {
        try (Connection connection = createConnection(url, userName, password)) {
            String sql = "SELECT * FROM T_TEST_TABLE WHERE FIELD_TYPE = ?";
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1, "Double");
            preparedStatement.execute();
            while (preparedStatement.getMoreResults()) {
                System.out.println(preparedStatement.getResultSet());
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

運(yùn)行測(cè)試用例,發(fā)現(xiàn)使用JDBC也無法獲取到正確的結(jié)果。于是打算看看Oracle的SQL執(zhí)行日志,看預(yù)編譯的SQL與直接拼接的SQL有啥區(qū)別

select * from  v$sql WHERE SQL_TEXT LIKE '%T_TEST_TABLE%'
ORDER BY FIRST_LOAD_TIME DESC;

根據(jù)運(yùn)行的時(shí)間點(diǎn),找到預(yù)編譯的 SQL為

SELECT * FROM T_TEST_TABLE WHERE FIELD_TYPE = :1 

直接拼接的SQL為

SELECT * FROM T_TEST_TABLE WHERE FIELD_TYPE = 'Double'

預(yù)編譯的SQL在客戶端中運(yùn)行也沒問題

說明代碼沒問題,是不是字段里面有空格導(dǎo)致查詢不到的呢?于是把字段直接復(fù)制出來。復(fù)制出來果然發(fā)現(xiàn)了空格

但是運(yùn)行這個(gè)也不對(duì)。這個(gè)時(shí)候思考著為啥有空格呢?于是百度看了一下CHAR字段的介紹,原來Oracle的 CHAR字段長度不夠的用空格填充,輸出上面的字符長度看看

解決問題

由于Oracle的CHAR類型在插入的數(shù)據(jù)長度不夠的情況下會(huì)用空格填充,于是把字段類型修改成 VARCHAR2

ALTER TABLE T_TEST_TABLE MODIFY "FIELD_TYPE" VARCHAR2(20)

把之前的數(shù)據(jù)空格清除

UPDATE T_TEST_TABLE SET FIELD_TYPE = TRIM(FIELD_TYPE)

再次執(zhí)行 MyBatis 的測(cè)試方法,可以發(fā)現(xiàn)查出數(shù)據(jù)

待解決問題

為啥用JDBC 預(yù)編譯 SQL 查詢 CHAR 類型的字段會(huì)有空格匹配問題?

到此這篇關(guān)于MyBatis的SQL執(zhí)行結(jié)果和客戶端執(zhí)行結(jié)果不一致問題排查的文章就介紹到這了,更多相關(guān)MyBatis SQL和客戶端執(zhí)行結(jié)果不一致內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java獲取本機(jī)IP地址的三種方法總結(jié)

    Java獲取本機(jī)IP地址的三種方法總結(jié)

    這篇文章主要為大家詳細(xì)介紹了java獲取本機(jī)IP地址的三種方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • gateway與spring-boot-starter-web沖突問題的解決

    gateway與spring-boot-starter-web沖突問題的解決

    這篇文章主要介紹了gateway與spring-boot-starter-web沖突問題的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • SpringBoot結(jié)合Mybatis實(shí)現(xiàn)創(chuàng)建數(shù)據(jù)庫表的方法

    SpringBoot結(jié)合Mybatis實(shí)現(xiàn)創(chuàng)建數(shù)據(jù)庫表的方法

    本文主要介紹了SpringBoot結(jié)合Mybatis實(shí)現(xiàn)創(chuàng)建數(shù)據(jù)庫表的方法,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • SpringBoot上傳圖片與視頻不顯示問題的解決方案

    SpringBoot上傳圖片與視頻不顯示問題的解決方案

    這篇文章主要介紹了關(guān)于springboot上傳圖片與視頻不顯示問題,最近做畢設(shè)時(shí)候需要上傳視頻的圖片與視頻,但是每次都需要重啟前端才能展示出此圖片,所以本文給大家介紹了SpringBoot上傳圖片與視頻不顯示問題的解決方案,需要的朋友可以參考下
    2024-03-03
  • springboot使用Mybatis-plus分頁插件的案例詳解

    springboot使用Mybatis-plus分頁插件的案例詳解

    這篇文章主要介紹了springboot使用Mybatis-plus分頁插件的相關(guān)知識(shí),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-05-05
  • SpringBoot自定義Redis實(shí)現(xiàn)緩存序列化詳解

    SpringBoot自定義Redis實(shí)現(xiàn)緩存序列化詳解

    Spring提供了一個(gè)RedisTemplate來進(jìn)行對(duì)Redis的操作,但是RedisTemplate默認(rèn)配置的是使用Java本機(jī)序列化。如果要對(duì)對(duì)象操作,就不是那么的方便。所以本文為大家介紹了另一種SpringBoot結(jié)合Redis實(shí)現(xiàn)序列化的方法,需要的可以參考一下
    2022-07-07
  • Java?天生就是多線程

    Java?天生就是多線程

    這篇文章主要介紹了Java天生就是多線程,程序天生就是多線程程序,因?yàn)閳?zhí)行main()方法的是一個(gè)名稱為main的線程,更多相關(guān)內(nèi)容需要的小伙伴可以參考一下
    2022-07-07
  • java 中 poi解析Excel文件版本問題解決辦法

    java 中 poi解析Excel文件版本問題解決辦法

    這篇文章主要介紹了java 中 poi解析Excel文件版本問題解決辦法的相關(guān)資料,需要的朋友可以參考下
    2017-08-08
  • MyBatis版本升級(jí)導(dǎo)致OffsetDateTime入?yún)⒔馕霎惓栴}復(fù)盤

    MyBatis版本升級(jí)導(dǎo)致OffsetDateTime入?yún)⒔馕霎惓栴}復(fù)盤

    這篇文章主要介紹了MyBatis版本升級(jí)導(dǎo)致OffsetDateTime入?yún)⒔馕霎惓栴}復(fù)盤,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • MybatisPlus之likeRight的用法

    MybatisPlus之likeRight的用法

    這篇文章主要介紹了MybatisPlus之likeRight的用法說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06

最新評(píng)論

湘潭市| 耿马| 乳山市| 赣榆县| 五华县| 肥乡县| 班戈县| 桂东县| 临洮县| 道孚县| 广河县| 秦皇岛市| 万全县| 饶平县| 上高县| 保德县| 福州市| 萝北县| 定结县| 湖州市| 剑阁县| 名山县| 铜梁县| 滕州市| 大埔县| 鄄城县| 西平县| 大关县| 通海县| 武定县| 双桥区| 桐柏县| 江门市| 舒城县| 根河市| 高陵县| 罗田县| 宣武区| 勐海县| 肥东县| 金秀|