- 错误代码
- 错误完整Java执行代码
- 问题分析
- 问题原因
- 解决方案
实体类
@Table(name = "test")
public class Test {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private Boolean status;
@Column(name = "create_time")
private Date createTime;
@Column(name = "creator_id")
private Integer creatorId;
private String creator;
@Column(name = "modify_time")
private Date modifyTime;
@Column(name = "modifier_id")
private Integer modifierId;
private String modifier;
private String remark;
// -----省略get,set方法
}
mapper文件(对应的xml文件就不在此列出了)
import tk.mybatis.mapper.common.base.update.UpdateByPrimaryKeyMapper; public interface TestMapper extends UpdateByPrimaryKeyMapper{ }
Java调用
@Resource
private TestMapper testMapper;
public void update(){
Test test = new Test();
test.setId(12);
test.setRemark("sjiji);
testMapper.updateByPrimaryKey(test);
}
上面为代码详情。在执行update的时候。发现sql语句会如下
update test set remark = 'sjiji' where id = 12 and remark = null and modifier = null and modifierId = null and modifyTime = null and creator = null and creatorId = null and createTime = null and status = null
很显然上面的sql 是错误的sql ;where条件后面包含了非id字段列;
问题分析找了很久发现原因;
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package tk.mybatis.mapper.common.base.update; import org.apache.ibatis.annotations.UpdateProvider; import tk.mybatis.mapper.annotation.RegisterMapper; import tk.mybatis.mapper.provider.base.baseUpdateProvider; @RegisterMapper public interface UpdateByPrimaryKeySelectiveMapper{ @UpdateProvider( type = baseUpdateProvider.class, method = "dynamicSQL" ) int updateByPrimaryKeySelective(T var1); }
上面的update会调用 baseUpdateProvider#updateByPrimaryKeySelective方法;实现如下
public String updateByPrimaryKeySelective(MappedStatement ms) {
Class> entityClass = this.getEntityClass(ms);
StringBuilder sql = new StringBuilder();
sql.append(SqlHelper.updateTable(entityClass, this.tableName(entityClass)));
sql.append(SqlHelper.updateSetColumns(entityClass, (String)null, true, this.isNotEmpty()));
//拼接where条件列
sql.append(SqlHelper.wherePKColumns(entityClass, true));
return sql.toString();
}
拼接where条件后面的sql处理逻辑
public static String wherePKColumns(Class> entityClass, String entityName, boolean useVersion) {
StringBuilder sql = new StringBuilder();
boolean hasLogicDelete = hasLogicDeleteColumn(entityClass);
sql.append("");
//获取全部列
Set columnSet = EntityHelper.getPKColumns(entityClass);
//当某个列有主键策略时,不需要考虑他的属性是否为空,因为如果为空,一定会根据主键策略给他生成一个值
for (EntityColumn column : columnSet) {
sql.append(" AND ").append(column.getColumnEqualsHolder(entityName));
}
if (useVersion) {
sql.append(whereVersion(entityClass));
}
if (hasLogicDelete) {
sql.append(whereLogicDelete(entityClass, false));
}
sql.append(" ");
return sql.toString();
}
设置当前实体类的id字段的方法 tk.mybatis.mapper.mapperhelper.resolve.DefaultEntityResolve#resolveEntity
public EntityTable resolveEntity(Class> entityClass, Config config) {
Style style = config.getStyle();
//style,该注解优先于全局配置
if (entityClass.isAnnotationPresent(NameStyle.class)) {
NameStyle nameStyle = entityClass.getAnnotation(NameStyle.class);
style = nameStyle.value();
}
//创建并缓存EntityTable
EntityTable entityTable = null;
if (entityClass.isAnnotationPresent(Table.class)) {
Table table = entityClass.getAnnotation(Table.class);
if (!"".equals(table.name())) {
entityTable = new EntityTable(entityClass);
entityTable.setTable(table);
}
}
if (entityTable == null) {
entityTable = new EntityTable(entityClass);
//可以通过stye控制
String tableName = StringUtil.convertByStyle(entityClass.getSimpleName(), style);
//自动处理关键字
if (StringUtil.isNotEmpty(config.getWrapKeyword()) && SqlReservedWords.containsWord(tableName)) {
tableName = MessageFormat.format(config.getWrapKeyword(), tableName);
}
entityTable.setName(tableName);
}
entityTable.setEntityClassColumns(new linkedHashSet());
entityTable.setEntityClassPKColumns(new linkedHashSet());
//处理所有列
List fields = null;
if (config.isEnableMethodAnnotation()) {
fields = FieldHelper.getAll(entityClass);
} else {
fields = FieldHelper.getFields(entityClass);
}
for (EntityField field : fields) {
//如果启用了简单类型,就做简单类型校验,如果不是简单类型,直接跳过
//3.5.0 如果启用了枚举作为简单类型,就不会自动忽略枚举类型
//4.0 如果标记了 Column 或 ColumnType 注解,也不忽略
if (config.isUseSimpleType()
&& !field.isAnnotationPresent(Column.class)
&& !field.isAnnotationPresent(ColumnType.class)
&& !(SimpleTypeUtil.isSimpleType(field.getJavaType())
||
(config.isEnumAsSimpleType() && Enum.class.isAssignableFrom(field.getJavaType())))) {
continue;
}
// 方法逻辑会执行设置主键id及其他字段信息
processField(entityTable, field, config, style);
}
//当pk.size=0的时候使用所有列作为主键
if (entityTable.getEntityClassPKColumns().size() == 0) {
entityTable.setEntityClassPKColumns(entityTable.getEntityClassColumns());
}
entityTable.initPropertyMap();
return entityTable;
}
tk.mybatis.mapper.mapperhelper.resolve.DefaultEntityResolve#processField处理的id逻辑
protected void processField(EntityTable entityTable, EntityField field, Config config, Style style) {
// 需要加上 @Id注解
if (field.isAnnotationPresent(Id.class)) {
entityColumn.setId(true);
}
}
问题原因
再看我们的实体,发现实体类没有 @ID 注解。。。。
解决方案所以此处解决方案,给实体类加上 @Id注解即可



