前言
工作的时候,有线上问题反馈有很少量数据库问题,而且不好解决,后面发现是在封装数据库的时候出了问题。先解释下问题,然后再解决。
数据库封装中的问题
private int updateIfValueNotNull(T t) {
int result = 0;
UpdateBuilder updateBuilder = this.ormLiteDao.updateBuilder();
Map<String, Object> map = this.getFieldsIfValueNotNull(t);
if(map.isEmpty()) {
LogUtil.w("all field value is null.");
return 0;
} else if(map.get("id") == null) {
return 0;
} else {
try {
updateBuilder.where().idEq(map.get("id"));
Iterator var5 = map.entrySet().iterator();
while(var5.hasNext()) {
Entry<String, Object> entry = (Entry)var5.next();
if(!((String)entry.getKey()).equals("id")) {
updateBuilder.updateColumnValue((String)entry.getKey(), entry.getValue());
}
}
result = updateBuilder.update();
} catch (SQLException var7) {
LogUtil.e(var7);
} catch (java.sql.SQLException var8) {
LogUtil.e(var8);
}
return result;
}
}
这里封装存在两个问题:
1、数据库bean当中,可能有些字段属性并不一定是和数据库对应。
private Map<String, Object> getFieldsIfValueNotNull(Object obj) {
Map<String, Object> map = new HashMap<>();
Field[] fields = obj.getClass().getDeclaredFields();
for (Field field : fields) {
LogUtil.d("getFieldsIfValueNotNull + " + field.getName());
field.setAccessible(true);
Object valueObj = null;
try {
valueObj = field.get(obj);
} catch (IllegalAccessException e) {
LogUtil.e(TAG, e);
}
if (valueObj != null) {
map.put(field.getName(), valueObj);
}
}
return map;
}
使用上面的方法去全匹配字段,如果映射数据库表的Bean中包含某个字段 int age 但是 age字段并没有数据库注解,没有映射到数据表的时候,那么我们在进行更新操作的时候,会去全匹配,当匹配到age的时候就会出错。因为数据库表中并无该属性。
2、我们可以看到代码中去匹配主键时候,全部是写死的id,这样的话当某些表的主键字段并不是id的时候就会出错。
解决办法:
对于第一个问题,我们在进行更新操作的时候,并不要去全匹配,而是只匹配数据库对应的bean中加了DatabaseField注解的字段。代码如下:
public static void showAnnotationWrodOther(Object object){
Field[] fields = object.getClass().getDeclaredFields();
for(Field field : fields){
boolean fieldHasAnno = field.isAnnotationPresent(DatabaseField.class);
//是否有DatabaseField注解
if(fieldHasAnno) {
DatabaseField fieldAnno = field.getAnnotation(DatabaseField.class);
//这里可以输出注解的属性
boolean b = fieldAnno.generatedId();
System.out.println(field.getName() + ",isgeneratedId = " + b);
}
}
}
上面的方法就可以筛选出有注解的字段,并对其进行操作。
对于第二个问题,我们就需要一个拿到主键的方法,然后再去匹配。方法如下:
//获取数据库表封装的bean的主键
private String getDbPrimarykey(Object obj) {
Field[] fields = obj.getClass().getDeclaredFields();
String primaryKey = "";
for (Field field : fields) {
String name = field.getName();
//1、获取属性上的指定类型的注解
Annotation annotation = field.getAnnotation(DatabaseField.class);
if (null != annotation) {
DatabaseField databaseField = (DatabaseField) annotation;
//通过注解判断是否是主键
if (databaseField.generatedId() || databaseField.id() || !TextUtils.isEmpty(databaseField.generatedIdSequence())) {
primaryKey = name;
break;
}
}
}
return primaryKey;
}
小节:
本文为自己工作中发现的问题,并作出些许优化,如果存在问题,欢迎大家不佞指出。谢谢,希望大家一起进步