解决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问题,希望对大家有所帮助