1. 程式人生 > >mybatis使用char型別欄位查詢oracle資料庫時結果返回null

mybatis使用char型別欄位查詢oracle資料庫時結果返回null

同事在學mybatis時,遇到了一個問題就是,使用char型別欄位作為查詢條件時一直都查不出資料,其他型別的則可以。
使用的資料庫是oracle,查詢條件欄位型別是char(50),java程式碼對應的是String型別。
後來經過排查,是由於在oracle中,char型別欄位,如果內容長度不夠,會自動以空格方式補足長度。如欄位 name char(5),若值為sgl,那麼oracle會自動用空格補足長度,最終值為sgl

一、解決方法:

方法1:先用trim()函式把值去掉兩邊空格再作為條件查詢,如:

select * from data where data.name=#{name}

改為:

select * from data where trim(data.name)=#{name}

方法2:將欄位型別char()改為varchar2()型別。一般情況下,只有所有值長度都一樣時才用char()型別,比如性別欄位,用0表示男和1表示女時,就可以用char(1),如果值的長度不固定,有長有短,最好別用char()型別。

二、深入瞭解mybatis返回null

拋開mybatis框架,回到原始的jdbc查詢,當使用oracle的char型別作為條件查詢資料時,只有值完全一樣時才能查到資料。
如建立一個測試表:

create table t_user(
       user_name char
(5) );
insert into t_user (user_name)values('sgl'); select '"'||user_name||'"' from t_user; -- 查詢結果為"sgl ",可以看出oracle自動補了兩個空格

通過jdbc的PreparedStatement方式查詢資料:

conn=getConnection();
ps=conn.prepareStatement("select * from t_user where user_name=?");
ps.setString(1,"sgl");
ResultSet rs = ps.executeQuery
();

通過上面方式是無法查到資料的,因為查詢條件值”sgl”和資料庫中值”sgl “是不相等的。
如果值用“sgl ”可以查到資料:

conn=getConnection();
ps=conn.prepareStatement("select * from t_user where user_name=?");
ps.setString(1,"sgl  "); -- 增加兩個空格不足5位長度
ResultSet rs = ps.executeQuery();

如果使用trim()方式也可以查詢到資料,如:

conn=getConnection();
ps=conn.prepareStatement("select * from t_user where trim(user_name)=?"); -- 先對資料庫中user_name進行去空格,然後再比較
ps.setString(1,"sgl");
ResultSet rs = ps.executeQuery();

現在回到mybatis,同事的Mapper檔案裡查詢sql如下:

<select id="selectByName" resultType="com.entity.Data" parameterType="java.lang.String">
  select * from data where data.name=#{name}
</select>

main方法內容為:

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

其實,通過檢視原始碼或將日誌改為debug級別,可以看出在mybatis底層,會將查詢語句使用PreparedStatement預編譯,然後再將引數設定進去。如下面是mybatis打印出來的日誌:

==> Preparing: select * from data where data.name=? 
==> Parameters: sgl(String)

根據前面的jdbc查詢,我們知道原因,所以很容易理解mybatis中的問題。

另外,mysql下面,當char型別欄位的值不足時,好像並不自動將值以空格補足,儘管如此,當值長度不固定時,也不推薦使用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連線資料類
 * @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("資料庫第"+reCount+"次重連");
                conn = getConnection();
            }
        }
        return conn;
    }
    /**
     * 查詢資料
     * @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;
    }
    /**
     * 執行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();
            }
        }
    }
}

測試類:

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")); // 查詢到條數:0
        //List<String[]>list=PureJdbcDao.query("select * from t_user where user_name=?",Arrays.asList("sgl  ")); //查詢到條數:1
        List<String[]>list=PureJdbcDao.query("select * from t_user where trim(user_name)=?",Arrays.asList("sgl")); //查詢到條數:1
        System.out.println("查詢到條數:"+list.size());
    }
}