欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

解决mybatis使用char类型字段查询oracle数据库时结果返回null问题

程序员文章站 2023-12-20 20:41:22
同事在学mybatis时,遇到了一个问题就是,使用char类型字段作为查询条件时一直都查不出数据,其他类型的则可以。  使用的数据库是oracle,查询条件字段...

同事在学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());
  }
}

总结

以上所述是小编给大家介绍的解决mybatis使用char类型字段查询oracle数据库时结果返回null问题,希望对大家有所帮助

上一篇:

下一篇: