解决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问题,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

时间: 2018-06-10

Mybatis查询语句结果集的总结大全

简单查询-resultType 数据准备 字段 注释 SNO 学号 SNAME 学生名字 SSEX 性别 SBIRITHDAY 生日 CLASS 班级 <!--建表语句:--> create table TEST.STUDENT ( SNO varchar(3) not null, SNAME varchar(4) not null, SSEX varchar(2) not null, SBIRTHDAY datetime null, CLASS varchar(5) null ) <!

Mybatis传递多个参数进行SQL查询的用法

PS:ibatis3如何传递多个参数有两个方法:一种是使用java.Map,另一种是使用JavaBean. 当只向xxxMapper.xml文件中传递一个参数时,可以简单的用"_parameter"来接收xxxMapper.java传递进来的参数,并代入查询,比如说这样: (1)xxxMapper.java文件中这样定义: List<String> selectAllAirportCode(Boolean mapping); (2)这时在对应的xxxMapper.xml文件

Mybatis使用MySQL模糊查询时输入中文检索不到结果怎么办

项目开发中,在做Mybatis动态查询时,遇到了一个问题:MySQL在进行LIKE模糊查询时,输入英文可以正常检索出结果,但是输入中文后检索得到的结果为空. 由于是使用GET方式请求,所以为了确保中文不乱码,在控制台接收到请求参数后,对中文进行了一次编码. try { realName = new String(realName.getBytes("GBK"), "UTF-8"); } catch (UnsupportedEncodingException exce

Mybatis实现增删改查及分页查询的方法

MyBatis的前身就是iBatis.是一个数据持久层(ORM)框架. MyBatis是支持普通SQL查询,存储过程和高级映射的优秀持 久层框架.MyBatis消除了几乎所有的JDBC 代码和参数的手工 设置以及结果集的检索.MyBatis使用简单的XML或注解用于 配置和原始映射,将接口和Java 的POJOs(Plan Old Java Objects,普通的Java 对象)映射成数据库中的记录.每个 MyBatis应用程序主要都是使用SqlSessionFactory实例的,一个 SqlS

详解MyBatis直接执行SQL查询及数据批量插入

一.直接执行SQL查询: 1.mappers文件节选 <resultMap id="AcModelResultMap" type="com.izumi.InstanceModel"> <result column="instanceid" property="instanceID" jdbcType="VARCHAR" /> <result column="insta

Mybatis 一对多和多对一关联查询问题

首先  数据库量表之间字段关系(没有主外键) studentmajor表的id字段对应student表里major字段 两个实体类 package com.model; import java.util.Date; public class Student { private Integer sno; private String sname; private String ssex; private Integer sclass; private StudentMajor studentmaj

Mybatis查不到数据查询返回Null问题

mybatis突然查不到数据,查询返回的都是Null,但是 select count(*) from xxx查询数量,返回却是正常的. Preparing: SELECT id,a9004,a9005,a9015 FROM a90 where a9010 = ? ORDER BY id LIMIT 1 [DEBUG] org.apache.ibatis.logging.jdbc.BaseJdbcLogger.debug(BaseJdbcLogger.java:139):http-bio-8080

Java的MyBatis框架中实现多表连接查询和查询结果分页

实现多表联合查询 还是在david.mybatis.model包下面新建一个Website类,用来持久化数据之用,重写下相应toString()方法,方便测试程序之用. package david.mybatis.model; import java.text.SimpleDateFormat; import java.util.Date; public class Website { private int id; private String name; private int visito

mybatis interceptor 处理查询参数及查询结果的实例代码

下面给大家介绍mybatis interceptor 处理查询参数及查询结果,具体代码如下所示: /** * Created by windwant on 2017/1/12. */ @Intercepts({ @Signature(type=Executor.class,method="update",args={MappedStatement.class,Object.class}), @Signature(type=Executor.class,method="quer

MyBatis拦截器:给参数对象属性赋值的实例

该拦截器的作用:在进行增加.修改等操作时,给数据模型的一些通用操作属性(如:创建人.创建时间.修改人.修改时间等)自动赋值. 该实现是在DAO层拦截,即存入DB前最后一层.后经分析,不是很合理,改为在service层拦截,用spring AOP来实现了,该代码遂弃用.不过已经测试可用,记录备忘. package com.development; import java.lang.reflect.InvocationTargetException; import java.util.Date; i

Oracle + mybatis实现对数据的简单增删改查实例代码

什么是 MyBatis? MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架. MyBatis 消除了几乎所有的 JDBC 代码和参数的手工设置以及对结果集的检索.MyBatis 可以使用简单的XML 或注解用于配置和原始映射,将接口和 Java 的 POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录. 本文将详细介绍利用Oracle + mybatis实现对数据的简单增删改查的相关内容,下面话不多说了,来一起看看详细的介绍

C++详解默认参数的构造函数及简单实例代码

现在给大家介绍下 有默认参数的构造函数: 大家知道函数获取形参的时候是通过函数调用时在实参里获得的,因此我们必须保证 实参的个数 和 形参的个数必须相同.而且有些情况下我们对于实参或许都是个固定的值.例如 我们需要计算长方形的面积 长x宽 但是用户可以不输入长 而且如果用户指定的情况下默认的长为 3,但是如果用户指定了则使用用户指定的宽 这就是用到默认参数了! 代码: #include <iostream> using namespace std; int area(int l,int w=3

mybatis利用association或collection传递多参数子查询

有时候我们在查询数据库时,需要以查询结果为查询条件进行关联查询. 在mybatis 中通过 association 标签(一对一查询,collection 一对多 查询) 实现延迟加载子查询 <resultMap id="xxxMap" type="xxxx.bean.xxx" extends="zzzzMap"> <association property="destName" javaType="

Mybatis查询记录条数的实例代码

这几天在学SSM框架,今天在SSM框架中根据某个条件查询MySQL数据库中的记录条数,碰到一些问题,记录一下 User.xml <select id="userNameValidate" parameterType="String" resultType="Integer"> select count(*) from user where username like #{value} </select> <selec

Mybatis基于注解实现多表查询功能

对应的四种数据库表关系中存在四种关系:一对多,多对应,一对一,多对多.在前文中已经实现了xml配置方式实现表关系的查询,本文记录一下Mybatis怎么通过注解实现多表的查询,算是一个知识的补充. 同样的先介绍一下Demo的情况:存在两个实体类用户类和账户类,用户类可能存在多个账户,即一对多的表关系.每个账户只能属于一个用户,即一对一或者多对一关系.我们最后实现两个方法,第一个实现查询所有用户信息并同时查询出每个用户的账户信息,第二个实现查询所有的账户信息并且同时查询出其所属的用户信息. 1.项目

MyBatis Plus 实现多表分页查询功能的示例代码

在Mybatis Plus 中,虽然IService 接口帮我们定义了很多常用的方法,但这些都是 T 对象有用,如果涉及到 多表的查询,还是需要自定义Vo 对象和自己编写sql 语句,Mybatis Plus提供了一个Page 对象,查询是需要设置其中的 size 字段 和 current 字段的值 一.分页配置 可以直接使用selectPage这样的分页,但返回的数据确实是分页后的数据,但在控制台打印的SQL语句其实并没有真正的物理分页,而是通过缓存来获得全部数据中再进行的分页,这样对于大数据

JavaScript获得url查询参数的方法

本文实例讲述了JavaScript获得url查询参数的方法.分享给大家供大家参考.具体实现方法如下: function getQueryVariable(variable) { var query = window.location.search.substring(1); var vars = query.split("&"); for (var i=0;i<vars.length;i++) { var pair = vars[i].split("="