3

问题一:字段名不存在

背景是:进行mapper的insert单元测试的时候出了问题
执行如下语句的时候出现了问题:

Test entity = new Test();
entity.setName(new RandomString().nextString());
entity.setFatherTestId(new RandomString().nextString());

Integer insNum = testMapper.insert(entity);

这里运用了mapper自带的insert方法向数据库中插入数据。

在用mapper进行插入的时候后,报了这样的错误: 字段名不存在。

image.png

但是去数据表中查看,实际上是有fatherTestId这个字段的

就疑惑为什么后台会找不到这个字段


并仔细看红色的的报错,后台说fatherid这个字段找不到。
这里我发现了端倪,数据库中表定义的是fatherTestId, i和T字母是大写的。

猜测是由于数据库字段大小写的问题

之后去谷歌之后找到了答案:

原因:在于PostgreSQL对表名、字段名都是区分大小写的。在执行SQL时,那么不管你的SQL中字段是大写还是小写,最后都会默认转为小写去执行。

解决:

1. 数据库字段名改为小写。或者用下划线_分割。
后来改为下划线后运行正常

2. 写sql语句的时候,对表名或者字段名加上双引号

定义SQL的时候,对表名及字段名加上双引号,可以防止大写字段被转为小写去执行。

因为在PGSQL中,默认对SQL语句进行抹去双引号和大写转小写的其中一个且抹去双引号优先级比较高,因此当大写字段被加上双引号,只进行了抹去双引号的处理而不会再被转为小写了。

image.png

例如这样, 加上双引号。


最后由于我这里使用的是mapper自带的insert函数来进行数据插入,并没有自己写sql语句。
所以最后采用了第一种方式解决。

问题二:char(32)类型字段,查询出来的数据带有空格

Integer insNum = testMapper.insert(entity);
Assert.isTrue(insNum.equals(1), "insert success");

String id = entity.getId();
Test getEntity = testMapper.selectById(id);;
Assert.isTrue(getEntity.getName().equals(entity.getName()), "name not equal");

在后台单元测试的时候,进行了断言:插入的数据和查询出来的数据相同。

也就是说,将一条数据插入到数据库中,再将其查询出来,判断这两个数据的属性都相同。

但是单元测试一直没通过

在代码中打断点测试中发现,发现从数据库中查询出来的数据都带有空格。如下图。

lQLPJxaVNsYH3cXMxM0DSLAY8phzlKKHQAL1idguAKIA_840_196.png

猜测是因为postgresql在保存的时候会,自动将数据长度用空格补充至32位。

结果用testMapper自带的selectById方法查询出数据的时候,就会带有空格。

如果是这样的话,用mapper查询数据出来之后,还需要用trim()函数将空格逐个去除。

同时我找到了一篇使用了postgreSql的建议, 里面也提到了使用char(n)的一些弊端。
https://juejin.cn/post/684490...

image.png

image.png


同时也提到了不要使用大写字母作为表名
image.png

mybatis + spring boot 的基本使用

以新建为例:

controller层:与以前使用差不多,都是直接调用serivice层

  @Autowired
  DictionaryService dictionaryService;

  @ApiOperation(value = "新建字典")
  @PostMapping("")
  public Dictionary addDictionary(@RequestBody Dictionary dictionary) {
   return dictionaryService.saveDictionary(dictionary);
  }

serivce层:

@Service
public class DictionaryServiceImpl extends ServiceImpl<DictionaryMapper, Dictionary> implements DictionaryService {

  @Autowired
  DictionaryMapper dictionaryMapper;

  @Override
  public Dictionary saveDictionary(Dictionary dictionary) {
    Integer insNum = dictionaryMapper.insert(dictionary);
    Assert.isTrue(insNum.equals(1), "insert success");

    String id = dictionary.getId();
    Dictionary getDictionary = dictionaryMapper.selectById(id);
    return  getDictionary;
  }

在使用Mapper内置的insert函数的时候,insert函数返回的是:插入该数据后受影响的数据条数。 而不是像jpa那样, 返回的是插入后的实体。

所以,如何使它返回插入后的实体呢?

在经过单元测试时,发现

在执行insert函数之前,实体的id为null。在执行完insert函数之后,实体的id有了值。

image.png

image.png

所以可以猜想到,在执行完insert函数之后,数据库的值会同步到实体中。 也就是说我们得到了id

image.png

即便我们不放心,既然我们已经获取到了id的值。 我们还可以用selectById函数,再从数据库查询一遍,来确保它是数据库保存的值。

String id = dictionary.getId();
Dictionary getDictionary = dictionaryMapper.selectById(id);

整体的单元测试如下:

@Autowired
  DictionaryMapper dictionaryMapper;

  Dictionary getDictionary() {
    Dictionary dictionary = new Dictionary();
    dictionary.setKey(new RandomString().nextString());
    dictionary.setRemarks(new RandomString().nextString());
    dictionary.setValue(new RandomString().nextString());
    dictionary.setName(new RandomString().nextString());

    return dictionary;
  }

  @Test
  @DisplayName("插入一条记录并获取")
  void insertOne() {
    Dictionary dictionary = getDictionary();

    Integer insNum = dictionaryMapper.insert(dictionary);
    Assert.isTrue(insNum.equals(1), "insert success");

    String id = dictionary.getId();
    Dictionary getDictionary = dictionaryMapper.selectById(id);

    Assert.isTrue(getDictionary.getName().trim().equals(dictionary.getName()), "Name not equal");
    Assert.isTrue(getDictionary.getRemarks().trim().equals(dictionary.getRemarks()), "remarks not equal");
    Assert.isTrue(getDictionary.getValue().trim().equals(dictionary.getValue()), "value not equal");
    Assert.isTrue(getDictionary.getKey().trim().equals(dictionary.getKey()), "key not equal");

  }

自定义综合查询

Dao层: 定义根据name模糊查询,获取所有实体

public interface DictionaryMapper extends BaseMapper<Dictionary> {

  List<Dictionary> getByName(String name);

}

xml文件:
使用xml查询,与jpa的区别就是需要自己写sql语句。 虽然不方便,但是留给了我们很大的操作空间。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.record.server.mapper.DictionaryMapper">

    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.record.server.model.Dictionary">
        <id column="id" property="id" />
        <result column="key" property="key" />
        <result column="name" property="name" />
        <result column="remarks" property="remarks" />
        <result column="value" property="value" />
    </resultMap>

    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List">
        id, key, name, remarks, value
    </sql>

    <select id="getByName" resultMap="BaseResultMap">
        select *
        from t_dictionary
        WHERE name LIKE '%${name}%'
    </select>


</mapper>

weiweiyi
1k 声望123 粉丝