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

 更新时间:2018年06月13日 09:20:19   作者:曾卫  
这篇文章主要介绍了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());
  }
}

总结

以上所述是小编给大家介绍的解决mybatis使用char类型字段查询oracle数据库时结果返回null问题,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

相关文章

  • springboot缓存的使用实践

    springboot缓存的使用实践

    这篇文章主要介绍了springboot缓存的使用,spring针对各种缓存实现,抽象出了CacheManager接口,用户使用该接口处理缓存,而无需关心底层实现,感兴趣的小伙伴们可以参考一下
    2018-06-06
  • Springboot如何设置过滤器及重复读取request里的body

    Springboot如何设置过滤器及重复读取request里的body

    这篇文章主要介绍了Springboot如何设置过滤器及重复读取request里的body,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • Java入门基础之Java的基本语法与Java所支持的数据类型

    Java入门基础之Java的基本语法与Java所支持的数据类型

    这篇文章主要介绍了Java入门基础之Java的基本语法与Java所支持的数据类型,熟悉语法和数据类型通常是了解一种编程语言的开始,需要的朋友可以参考下
    2016-02-02
  • 解密Java Map如何高效地操作键值对

    解密Java Map如何高效地操作键值对

    Map是Java中非常重要的数据结构之一,它存储键值对,可以通过键快速查找对应的值,是我们在实际开发中使用最为频繁的数据结构之一,下面小编就来和大家探讨一下Map是如何高效地操作键值对的吧
    2023-09-09
  • 使用java基础类实现zip压缩和zip解压工具类分享

    使用java基础类实现zip压缩和zip解压工具类分享

    使用java基础类写的一个简单的zip压缩解压工具类,实现了指定目录压缩到和该目录同名的zip文件和将zip文件解压到指定的目录的功能
    2014-03-03
  • Java实现的打印螺旋矩阵算法示例

    Java实现的打印螺旋矩阵算法示例

    这篇文章主要介绍了Java实现的打印螺旋矩阵算法,结合完整实例形式详细分析了java打印螺旋矩阵的算法原理与实现技巧,需要的朋友可以参考下
    2019-10-10
  • SpringAOP 设置注入的实现步骤

    SpringAOP 设置注入的实现步骤

    这篇文章主要介绍了SpringAOP 设置注入的实现步骤,帮助大家更好的理解和学习使用Spring框架,感兴趣的朋友可以了解下
    2021-05-05
  • maven打包失败踩坑的解决方式详解

    maven打包失败踩坑的解决方式详解

    最近因为新项目有很多自定义的jar包,而且占内存很多,就直接拷贝过来,新开了一个maven仓库,用的时候没有问题,但是打包一直编译不通过,下面这篇文章主要给大家介绍了关于maven打包失败踩坑的解决方式,需要的朋友可以参考下
    2023-05-05
  • java蓝桥杯历年真题及答案整理(小结)

    java蓝桥杯历年真题及答案整理(小结)

    这篇文章主要介绍了java蓝桥杯历年真题及答案整理(小结),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-02-02
  • Gateway网关源码解析

    Gateway网关源码解析

    这篇文章主要介绍了Gateway微服务网关,负载均衡,熔断和限流,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-07-07

最新评论