解決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)容長(zhǎng)度不夠,會(huì)自動(dòng)以空格方式補(bǔ)足長(zhǎng)度。如字段 name char(5),若值為sgl,那么oracle會(huì)自動(dòng)用空格補(bǔ)足長(zhǎng)度,最終值為sgl。
一、解決方法:
方法1:先用trim()函數(shù)把值去掉兩邊空格再作為條件查詢,如:
select * from data where data.name=#{name}
改為:
select * from data where trim(data.name)=#{name}
方法2:將字段類型char()改為varchar2()類型。一般情況下,只有所有值長(zhǎng)度都一樣時(shí)才用char()類型,比如性別字段,用0表示男和1表示女時(shí),就可以用char(1),如果值的長(zhǎng)度不固定,有長(zhǎng)有短,最好別用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位長(zhǎng)度
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)值長(zhǎ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中的形式參數(shù)和實(shí)際參數(shù)案例詳解
這篇文章主要介紹了Java中的形式參數(shù)和實(shí)際參數(shù),形參和實(shí)參間的關(guān)系,兩者是在調(diào)用的時(shí)候進(jìn)行結(jié)合的,通常實(shí)參會(huì)將取值傳遞給形參,形參去之后進(jìn)行函數(shù)過程運(yùn)算,然后可能將某些值經(jīng)過參數(shù)或函數(shù)符號(hào)返回給調(diào)用者,需要的朋友可以參考下2023-10-10
詳解如何使用java實(shí)現(xiàn)Open Addressing
這篇文章主要介紹了詳解如何使用java實(shí)現(xiàn)Open Addressing,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
Java統(tǒng)計(jì)字符串中字符出現(xiàn)次數(shù)的方法示例
這篇文章主要介紹了Java統(tǒng)計(jì)字符串中字符出現(xiàn)次數(shù)的方法,涉及Java針對(duì)字符串的遍歷、查找、計(jì)算等相關(guān)操作技巧,需要的朋友可以參考下2017-12-12
java雙端隊(duì)列之ArrayDequeue原理講解
這篇文章主要為大家介紹了java雙端隊(duì)列之ArrayDequeue原理講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06
Java?web實(shí)現(xiàn)頭像上傳以及讀取顯示
這篇文章主要為大家詳細(xì)介紹了Java?web實(shí)現(xiàn)頭像上傳以及讀取顯示,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06
java面向?qū)ο笤O(shè)計(jì)原則之合成復(fù)用原則示例詳解
這篇文章主要介紹了java面向?qū)ο笤O(shè)計(jì)原則之合成復(fù)用原則的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2021-10-10
SpringBoot整合PowerJob實(shí)現(xiàn)定時(shí)任務(wù)調(diào)度
最近項(xiàng)目需要使用定時(shí)任務(wù),而使用了PowerJob做任務(wù)調(diào)度模塊,感覺這個(gè)框架真香,今天我們就來深入了解一下新一代的定時(shí)任務(wù)框架——PowerJob,需要的朋友可以參考下2024-03-03

