前言
为了让我的SqlUtil用起来更香,我准备将SqlHelper中的saveOrUpdateBatch方法的参数从Class<?> mapper换成mapper的实体类,再通过mapper.getClass()的方式获取其真实类。
报错信息
如果是批量插入会报:
Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for com.sun.proxy.$Proxy129.insert
如果是执行批量更新则会报:
Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for com.sun.proxy.$Proxy129.updateById
代码如下:
public static <T extends BaseEntity, R extends BaseMapper<T>> void saveBatch(Class<R> mapperClass, List<T> entityList, Long userId) {
saveBatch(mapperClass, entityList, userId, 10000);
}
public static <T extends BaseEntity, R extends BaseMapper<T>> void saveBatch(R mapper, List<T> entityList, Long userId) {
saveBatch(mapper.getClass(), entityList, userId, 10000);
}
public static <T extends BaseEntity, R extends BaseMapper<T>> void saveBatch(Class<R> mapperClass, List<T> entityList, Long userId, int batchSize) {
if (entityList.size() == 0) {
return;
}
T t = entityList.get(0);
Class<T> entityClass = (Class<T>) t.getClass();
SqlHelper.saveOrUpdateBatch(entityClass, mapperClass, log, entityList, batchSize, (sqlSession, entity) -> {
// INFO: DCTANT: 2021/12/27 insert判断,返回true则是走insert代码,返回false则会走后面的update代码
if (entity == null) {
return false;
}
Long id = entity.getId();
if (id == null) {
// INFO: DCTANT: 2021/12/27 insert前加一些自己必要的业务逻辑,如setCreateTime、setDel、setVersion等等
insertNecessaryField(entity, userId);
return true;
} else {
// INFO: DCTANT: 2021/12/27 去执行update的代码
return false;
}
}, (sqlSession, entity) -> {
// INFO: DCTANT: 2021/12/27 判断为update,然后执行必要操作
if (entity == null) {
return;
}
// INFO: DCTANT: 2021/12/27 update前加一些自己的业务逻辑,如setUpdateTime等等
updateNecessaryField(entity, userId);
MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
// INFO: DCTANT: 2022/8/22 参数需要为Constants.ENTITY,也就是里面的et,否则会报et这个参数无法找到
param.put(Constants.ENTITY, entity);
String sqlStatement = SqlHelper.getSqlStatement(mapperClass, SqlMethod.UPDATE_BY_ID);
sqlSession.update(sqlStatement, param);
});
}
这个问题一开始报的让人摸不着头脑,若不是开了上帝视角,从前言中已经知道大概的问题原由,真是让人一头雾水,proxy类是哪来的,insert和updateById方法这两个方法在mapper中本来就有,凭什么会找不到!
这里一共三种写法,其中2、3是等价的
第一种写法打断点可得知拿到的就是Mapper它自己本身的类
这种写法能够反射获取其中的insert和updateById方法。
而第二、三种方法打断点获得的类是
实际是Java的代理类,Proxy类,这里面哪会存在insert和updateById方法,这就是报错的原因。所以方法不能胡乱抽取,这种就属于得不偿失,且无解。只能将本身的Class传入才能不报错,删除刚才的saveBatch(Class<R> mapperClass, List<T> entityList, Long userId)这个方法即可。
如果大家有什么其他解法可以指出,本人虚心接受。