问题一:字段名不存在
背景是:进行mapper的insert单元测试的时候出了问题
执行如下语句的时候出现了问题:
Test entity = new Test();
entity.setName(new RandomString().nextString());
entity.setFatherTestId(new RandomString().nextString());
Integer insNum = testMapper.insert(entity);
这里运用了mapper自带的insert方法向数据库中插入数据。
在用mapper进行插入的时候后,报了这样的错误: 字段名不存在。
但是去数据表中查看,实际上是有fatherTestId这个字段的。
就疑惑为什么后台会找不到这个字段
?
并仔细看红色的的报错,后台说fatherid
这个字段找不到。
这里我发现了端倪,数据库中表定义的是fatherTestId, i和T字母是大写的。
猜测是由于数据库字段大小写的问题。
之后去谷歌之后找到了答案:
原因:在于PostgreSQL对表名、字段名都是区分大小写的。在执行SQL时,那么不管你的SQL中字段是大写还是小写,最后都会默认转为小写去执行。
解决:
1. 数据库字段名改为小写。或者用下划线_分割。
后来改为下划线后运行正常
2. 写sql语句的时候,对表名或者字段名加上双引号
定义SQL的时候,对表名及字段名加上双引号,可以防止大写字段被转为小写去执行。
因为在PGSQL中,默认对SQL语句进行抹去双引号和大写转小写的其中一个,且抹去双引号优先级比较高,因此当大写字段被加上双引号,只进行了抹去双引号的处理而不会再被转为小写了。
例如这样, 加上双引号。
最后由于我这里使用的是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");
在后台单元测试的时候,进行了断言:插入的数据和查询出来的数据相同。
也就是说,将一条数据插入到数据库中,再将其查询出来,判断这两个数据的属性都相同。
但是单元测试一直没通过。
在代码中打断点测试中发现,发现从数据库中查询出来的数据都带有空格。如下图。
猜测是因为postgresql在保存的时候会,自动将数据长度用空格补充至32位。
结果用testMapper自带的selectById方法查询出数据的时候,就会带有空格。
如果是这样的话,用mapper查询数据出来之后,还需要用trim()函数将空格逐个去除。
同时我找到了一篇使用了postgreSql的建议, 里面也提到了使用char(n)的一些弊端。
https://juejin.cn/post/684490...
同时也提到了不要使用大写字母作为表名
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有了值。
所以可以猜想到,在执行完insert函数之后,数据库的值会同步到实体中。 也就是说我们得到了id
即便我们不放心,既然我们已经获取到了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>