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

阳光穿透心脏的1/2处 2022-06-10 08:19 304阅读 0赞

同事在学mybatis时,遇到了一个问题就是,使用char类型字段作为查询条件时一直都查不出数据,其他类型的则可以。
使用的数据库是oracle,查询条件字段类型是char(50),java代码对应的是String类型。
后来经过排查,是由于在oracle中,char类型字段,如果内容长度不够,会自动以空格方式补足长度。如字段 name char(5),若值为sgl,那么oracle会自动用空格补足长度,最终值为sgl

一、解决方法:

方法1:先用trim()函数把值去掉两边空格再作为条件查询,如:

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

改为:

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

方法2:将字段类型char()改为varchar2()类型。一般情况下,只有所有值长度都一样时才用char()类型,比如性别字段,用0表示男和1表示女时,就可以用char(1),如果值的长度不固定,有长有短,最好别用char()类型。

二、深入了解mybatis返回null

抛开mybatis框架,回到原始的jdbc查询,当使用oracle的char类型作为条件查询数据时,只有值完全一样时才能查到数据。
如创建一个测试表:

  1. create table t_user( user_name char(5) );
  2. insert into t_user (user_name)values('sgl');
  3. select '"'||user_name||'"' from t_user; -- 查询结果为"sgl ",可以看出oracle自动补了两个空格

通过jdbc的PreparedStatement方式查询数据:

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

通过上面方式是无法查到数据的,因为查询条件值”sgl”和数据库中值”sgl “是不相等的。
如果值用“sgl ”可以查到数据:

  1. conn=getConnection();
  2. ps=conn.prepareStatement("select * from t_user where user_name=?");
  3. ps.setString(1,"sgl "); -- 增加两个空格不足5位长度
  4. ResultSet rs = ps.executeQuery();

如果使用trim()方式也可以查询到数据,如:

  1. conn=getConnection();
  2. ps=conn.prepareStatement("select * from t_user where trim(user_name)=?"); -- 先对数据库中user_name进行去空格,然后再比较
  3. ps.setString(1,"sgl");
  4. ResultSet rs = ps.executeQuery();

现在回到mybatis,同事的Mapper文件里查询sql如下:

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

main方法内容为:

  1. public static void main(String[] args) {
  2. ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
  3. DataService d = (DataService) ctx.getBean("dataServiceImpl");
  4. Data data = d.selectByName("sgl");
  5. System.out.println(data);
  6. }

其实,通过查看源码或将日志改为debug级别,可以看出在mybatis底层,会将查询语句使用PreparedStatement预编译,然后再将参数设置进去。如下面是mybatis打印出来的日志:

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

根据前面的jdbc查询,我们知道原因,所以很容易理解mybatis中的问题。

另外,mysql下面,当char类型字段的值不足时,好像并不自动将值以空格补足,尽管如此,当值长度不固定时,也不推荐使用char类型。

jdbc查询完整的代码如下:
jdbc工具类:

  1. package com.songguoliang.url;
  2. import java.sql.Connection;
  3. import java.sql.DriverManager;
  4. import java.sql.PreparedStatement;
  5. import java.sql.ResultSet;
  6. import java.sql.ResultSetMetaData;
  7. import java.sql.SQLException;
  8. import java.sql.Statement;
  9. import java.util.ArrayList;
  10. import java.util.List;
  11. import java.util.ResourceBundle;
  12. /** * 纯jdbc连接数据类 * @author sgl * */
  13. public class PureJdbcDao {
  14. private static ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
  15. private static int reCount = 0;
  16. /** * 获取连接 * @return */
  17. private static Connection getConnection(){
  18. Connection conn=null;
  19. try {
  20. Class.forName(bundle.getString("driverClassName"));
  21. conn = DriverManager.getConnection(bundle.getString("url") ,
  22. bundle.getString("username") , bundle.getString("password"));
  23. } catch (ClassNotFoundException e) {
  24. e.printStackTrace();
  25. } catch (SQLException e) {
  26. e.printStackTrace();
  27. }finally{
  28. if(null==conn&&reCount<5){
  29. try {
  30. Thread.sleep(10000);
  31. } catch (InterruptedException e) {
  32. e.printStackTrace();
  33. }
  34. reCount++;
  35. System.out.println("数据库第"+reCount+"次重连");
  36. conn = getConnection();
  37. }
  38. }
  39. return conn;
  40. }
  41. /** * 查询数据 * @param sql * @return */
  42. public static List<String[]>query(String sql){
  43. List<String[]>result=new ArrayList<String[]>();
  44. Connection conn=null;
  45. Statement stmt=null;
  46. try {
  47. //System.out.println("[PureJdbcDao]查询语句:" + sql);
  48. conn=getConnection();
  49. stmt = conn.createStatement();
  50. ResultSet rs = stmt.executeQuery(sql);
  51. ResultSetMetaData rsMeta = rs.getMetaData();
  52. while(rs.next()){
  53. int columnNum=rsMeta.getColumnCount();
  54. String []field=new String[columnNum];
  55. String fieldValue=null;
  56. for(int i=1;i<=columnNum;i++){
  57. fieldValue=rs.getString(i);
  58. if(fieldValue==null){
  59. fieldValue="";
  60. }
  61. field[i-1]=fieldValue;
  62. }
  63. result.add(field);
  64. }
  65. } catch (SQLException e) {
  66. e.printStackTrace();
  67. }finally{
  68. try {
  69. if(stmt!=null){
  70. stmt.close();
  71. }
  72. if(conn!=null){
  73. conn.close();
  74. }
  75. } catch (SQLException e) {
  76. e.printStackTrace();
  77. }
  78. }
  79. return result;
  80. }
  81. public static List<String[]>query(String sql,List<String>params){
  82. List<String[]>result=new ArrayList<String[]>();
  83. Connection conn=null;
  84. PreparedStatement ps=null;
  85. try {
  86. conn=getConnection();
  87. ps=conn.prepareStatement(sql);
  88. for(int i=0;i<params.size();i++){
  89. ps.setString(i+1,params.get(i));
  90. }
  91. ResultSet rs = ps.executeQuery();
  92. ResultSetMetaData rsMeta = rs.getMetaData();
  93. while(rs.next()){
  94. int columnNum=rsMeta.getColumnCount();
  95. String []field=new String[columnNum];
  96. String fieldValue=null;
  97. for(int i=1;i<=columnNum;i++){
  98. fieldValue=rs.getString(i);
  99. if(fieldValue==null){
  100. fieldValue="";
  101. }
  102. field[i-1]=fieldValue;
  103. }
  104. result.add(field);
  105. }
  106. } catch (SQLException e) {
  107. e.printStackTrace();
  108. }finally{
  109. try {
  110. if(ps!=null){
  111. ps.close();
  112. }
  113. if(conn!=null){
  114. conn.close();
  115. }
  116. } catch (SQLException e) {
  117. e.printStackTrace();
  118. }
  119. }
  120. return result;
  121. }
  122. /** * 执行sql语句 * @param sql */
  123. public static void execute(String sql){
  124. Connection conn=null;
  125. Statement stmt=null;
  126. try {
  127. //System.out.println("[PureJdbcDao]sql语句:" + sql);
  128. conn = getConnection();
  129. conn.setAutoCommit(false);
  130. stmt = conn.createStatement();
  131. stmt.execute(sql);
  132. conn.commit();
  133. } catch (SQLException e) {
  134. try {
  135. conn.rollback();
  136. } catch (SQLException e1) {
  137. e1.printStackTrace();
  138. }
  139. e.printStackTrace();
  140. }finally{
  141. try {
  142. if(stmt!=null){
  143. stmt.close();
  144. }
  145. if(conn!=null){
  146. conn.close();
  147. }
  148. } catch (SQLException e) {
  149. e.printStackTrace();
  150. }
  151. }
  152. }
  153. }

测试类:

  1. package com.songguoliang;
  2. import java.util.Arrays;
  3. import java.util.List;
  4. import com.songguoliang.url.PureJdbcDao;
  5. public class Test {
  6. public static void main(String[] args) {
  7. //List<String[]>list=PureJdbcDao.query("select * from t_user where user_name=?",Arrays.asList("sgl")); // 查询到条数:0
  8. //List<String[]>list=PureJdbcDao.query("select * from t_user where user_name=?",Arrays.asList("sgl ")); //查询到条数:1
  9. List<String[]>list=PureJdbcDao.query("select * from t_user where trim(user_name)=?",Arrays.asList("sgl")); //查询到条数:1
  10. System.out.println("查询到条数:"+list.size());
  11. }
  12. }

发表评论

表情:
评论列表 (有 0 条评论,304人围观)

还没有评论,来说两句吧...

相关阅读