解決mybatis使用char類型字段查詢oracle數(shù)據(jù)庫時(shí)結(jié)果返回null問題
同事在學(xué)mybatis時(shí),遇到了一個(gè)問題就是,使用char類型字段作為查詢條件時(shí)一直都查不出數(shù)據(jù),其他類型的則可以。
使用的數(shù)據(jù)庫是oracle,查詢條件字段類型是char(50),java代碼對(duì)應(yīng)的是String類型。
后來經(jīng)過排查,是由于在oracle中,char類型字段,如果內(nèi)容長度不夠,會(huì)自動(dòng)以空格方式補(bǔ)足長度。如字段 name char(5),若值為sgl,那么oracle會(huì)自動(dòng)用空格補(bǔ)足長度,最終值為sgl。
一、解決方法:
方法1:先用trim()函數(shù)把值去掉兩邊空格再作為條件查詢,如:
select * from data where data.name=#{name}
改為:
select * from data where trim(data.name)=#{name}
方法2:將字段類型char()改為varchar2()類型。一般情況下,只有所有值長度都一樣時(shí)才用char()類型,比如性別字段,用0表示男和1表示女時(shí),就可以用char(1),如果值的長度不固定,有長有短,最好別用char()類型。
二、深入了解mybatis返回null
拋開mybatis框架,回到原始的jdbc查詢,當(dāng)使用oracle的char類型作為條件查詢數(shù)據(jù)時(shí),只有值完全一樣時(shí)才能查到數(shù)據(jù)。
如創(chuàng)建一個(gè)測(cè)試表:
create table t_user( user_name char(5) ); insert into t_user (user_name)values('sgl');
select '"'||user_name||'"' from t_user
; -- 查詢結(jié)果為"sgl ",可以看出oracle自動(dòng)補(bǔ)了兩個(gè)空格
通過jdbc的PreparedStatement方式查詢數(shù)據(jù):
conn=getConnection(); ps=conn.prepareStatement("select * from t_user where user_name=?"); ps.setString(1,"sgl"); ResultSet rs = ps.executeQuery();
通過上面方式是無法查到數(shù)據(jù)的,因?yàn)椴樵儣l件值”sgl”和數(shù)據(jù)庫中值”sgl “是不相等的。
如果值用“sgl ”可以查到數(shù)據(jù):
conn=getConnection(); ps=conn.prepareStatement("select * from t_user where user_name=?"); ps.setString(1,"sgl "); -- 增加兩個(gè)空格不足5位長度 ResultSet rs = ps.executeQuery();
如果使用trim()方式也可以查詢到數(shù)據(jù),如:
conn=getConnection(); ps=conn.prepareStatement("select * from t_user where trim(user_name)=?"); -- 先對(duì)數(shù)據(jù)庫中user_name進(jìn)行去空格,然后再比較 ps.setString(1,"sgl"); ResultSet rs = ps.executeQuery();
現(xiàn)在回到mybatis,同事的Mapper文件里查詢sql如下:
<select id="selectByName" resultType="com.entity.Data" parameterType="java.lang.String"> select * from data where data.name=#{name} </select>
main方法內(nèi)容為:
public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); DataService d = (DataService) ctx.getBean("dataServiceImpl"); Data data = d.selectByName("sgl"); System.out.println(data); }
其實(shí),通過查看源碼或?qū)⑷罩靖臑閐ebug級(jí)別,可以看出在mybatis底層,會(huì)將查詢語句使用PreparedStatement預(yù)編譯,然后再將參數(shù)設(shè)置進(jìn)去。如下面是mybatis打印出來的日志:
==> Preparing: select * from data where data.name=?
==> Parameters: sgl(String)
根據(jù)前面的jdbc查詢,我們知道原因,所以很容易理解mybatis中的問題。
另外,mysql下面,當(dāng)char類型字段的值不足時(shí),好像并不自動(dòng)將值以空格補(bǔ)足,盡管如此,當(dāng)值長度不固定時(shí),也不推薦使用char類型。
jdbc查詢完整的代碼如下:
jdbc工具類:
package com.songguoliang.url; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.List; import java.util.ResourceBundle; /** * 純jdbc連接數(shù)據(jù)類 * @author sgl * */ public class PureJdbcDao { private static ResourceBundle bundle = ResourceBundle.getBundle("jdbc"); private static int reCount = 0; /** * 獲取連接 * @return */ private static Connection getConnection(){ Connection conn=null; try { Class.forName(bundle.getString("driverClassName")); conn = DriverManager.getConnection(bundle.getString("url") , bundle.getString("username") , bundle.getString("password")); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); }finally{ if(null==conn&&reCount<5){ try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } reCount++; System.out.println("數(shù)據(jù)庫第"+reCount+"次重連"); conn = getConnection(); } } return conn; } /** * 查詢數(shù)據(jù) * @param sql * @return */ public static List<String[]>query(String sql){ List<String[]>result=new ArrayList<String[]>(); Connection conn=null; Statement stmt=null; try { //System.out.println("[PureJdbcDao]查詢語句:" + sql); conn=getConnection(); stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql); ResultSetMetaData rsMeta = rs.getMetaData(); while(rs.next()){ int columnNum=rsMeta.getColumnCount(); String []field=new String[columnNum]; String fieldValue=null; for(int i=1;i<=columnNum;i++){ fieldValue=rs.getString(i); if(fieldValue==null){ fieldValue=""; } field[i-1]=fieldValue; } result.add(field); } } catch (SQLException e) { e.printStackTrace(); }finally{ try { if(stmt!=null){ stmt.close(); } if(conn!=null){ conn.close(); } } catch (SQLException e) { e.printStackTrace(); } } return result; } public static List<String[]>query(String sql,List<String>params){ List<String[]>result=new ArrayList<String[]>(); Connection conn=null; PreparedStatement ps=null; try { conn=getConnection(); ps=conn.prepareStatement(sql); for(int i=0;i<params.size();i++){ ps.setString(i+1,params.get(i)); } ResultSet rs = ps.executeQuery(); ResultSetMetaData rsMeta = rs.getMetaData(); while(rs.next()){ int columnNum=rsMeta.getColumnCount(); String []field=new String[columnNum]; String fieldValue=null; for(int i=1;i<=columnNum;i++){ fieldValue=rs.getString(i); if(fieldValue==null){ fieldValue=""; } field[i-1]=fieldValue; } result.add(field); } } catch (SQLException e) { e.printStackTrace(); }finally{ try { if(ps!=null){ ps.close(); } if(conn!=null){ conn.close(); } } catch (SQLException e) { e.printStackTrace(); } } return result; } /** * 執(zhí)行sql語句 * @param sql */ public static void execute(String sql){ Connection conn=null; Statement stmt=null; try { //System.out.println("[PureJdbcDao]sql語句:" + sql); conn = getConnection(); conn.setAutoCommit(false); stmt = conn.createStatement(); stmt.execute(sql); conn.commit(); } catch (SQLException e) { try { conn.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } e.printStackTrace(); }finally{ try { if(stmt!=null){ stmt.close(); } if(conn!=null){ conn.close(); } } catch (SQLException e) { e.printStackTrace(); } } } }
測(cè)試類:
package com.songguoliang; import java.util.Arrays; import java.util.List; import com.songguoliang.url.PureJdbcDao; public class Test { public static void main(String[] args) { //List<String[]>list=PureJdbcDao.query("select * from t_user where user_name=?",Arrays.asList("sgl")); // 查詢到條數(shù):0 //List<String[]>list=PureJdbcDao.query("select * from t_user where user_name=?",Arrays.asList("sgl ")); //查詢到條數(shù):1 List<String[]>list=PureJdbcDao.query("select * from t_user where trim(user_name)=?",Arrays.asList("sgl")); //查詢到條數(shù):1 System.out.println("查詢到條數(shù):"+list.size()); } }
總結(jié)
以上所述是小編給大家介紹的解決mybatis使用char類型字段查詢oracle數(shù)據(jù)庫時(shí)結(jié)果返回null問題,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
java?-jar/-cp啟動(dòng)添加外部的依賴包方式
這篇文章主要介紹了java?-jar/-cp啟動(dòng)添加外部的依賴包方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01基于java Springboot實(shí)現(xiàn)教務(wù)管理系統(tǒng)詳解
這篇文章主要介紹了Java 實(shí)現(xiàn)簡易教務(wù)管理系統(tǒng)的代碼,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-08-08java設(shè)計(jì)模式-代理模式(實(shí)例講解)
下面小編就為大家?guī)硪黄猨ava設(shè)計(jì)模式-代理模式(實(shí)例講解)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-09-09Springboot-admin整合Quartz實(shí)現(xiàn)動(dòng)態(tài)管理定時(shí)任務(wù)的過程詳解
Quartz是一款Java編寫的開源任務(wù)調(diào)度框架,同時(shí)它也是Spring默認(rèn)的任務(wù)調(diào)度框架,它的作用其實(shí)類似于Timer定時(shí)器以及ScheduledExecutorService調(diào)度線程池,這篇文章主要介紹了Springboot-admin整合Quartz實(shí)現(xiàn)動(dòng)態(tài)管理定時(shí)任務(wù),需要的朋友可以參考下2023-04-04Spring Task定時(shí)任務(wù)的實(shí)現(xiàn)詳解
這篇文章主要介紹了SpringBoot定時(shí)任務(wù)功能詳細(xì)解析,這次的功能開發(fā)過程中也算是對(duì)其內(nèi)涵的進(jìn)一步了解,以后遇到定時(shí)任務(wù)的處理也更清晰,更有效率了,對(duì)SpringBoot定時(shí)任務(wù)相關(guān)知識(shí)感興趣的朋友一起看看吧2022-08-08maven配置多個(gè)鏡像的實(shí)現(xiàn)方法
這篇文章主要介紹了maven配置多個(gè)鏡像的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06java中對(duì)象轉(zhuǎn)json字符串的幾種常用方式舉例
這篇文章主要給大家介紹了關(guān)于java中對(duì)象轉(zhuǎn)json字符串的幾種常用方式,在Java中可以使用許多庫將對(duì)象轉(zhuǎn)換為JSON字符串,其中最常用的是Jackson和Gson,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-10-10