您的位置:首页 > 其它

xUtils中的dbUtils中,在应用升级的时候修改表结构

2017-02-26 19:21 501 查看
转载于_implements,原博客地址:http://blog.csdn.net/u013320868/
原文链接:http://blog.csdn.net/u013320868/article/details/51194286

我们在做数据缓存的时候经常用到数据库,数据库在进行存储的时候特别灵活也比较简单。虽然好用,但是存在一个问题,就是我们的应用在进行迭代的时候可能随着需求的变化,我们需要对表结构进行修改(一般是添加字段),这就需要我们在进行应用升级的时候,改变表结构,这样就面临一个问题,由于新表和旧表不一致,可能在存储时发生一些异常导致应用崩溃。大多数应用的解决办法是,在升级的时候,将之前所建的表删除然后重建,这样是不会崩溃,但是又出现了一个新问题,原来的数据都丢失了。最近我遇到的需求就是保存用户资料的添加了一些字段,但是在升级之后还想保存原来的用户资料。我在数据库缓存的时候用的是xUtils里的dbUtils,它是通过注解实体类来实现数据存储的,特别方便。下面我先简单介绍一下它的用法:

第一步,先创建数据库

创建数据库

  DaoConfig config = new DaoConfig(context);

  config.setDbName("xUtils-demo"); //数据库名

  config.setDbVersion(1);  //数据库版本号

  DbUtils db = DbUtils.create(config);//db还有其他的一些构造方法,比如含有更新表版本的监听器的 假如不设置监听器默认在升级的时候会将旧版本的表删掉

第二步,根据需求创建实体类,然后进行注解,注解方式如下图



下面这是常用到的一些Annotation(注解)    //注解可不等同于注释,不要混为一谈

  @Check    check约束

  @Column   列名

  @Finder   一对多、多对一、多对多关系(见sample的Parent、Child中的使用)

  @Foreign  外键

  @Id       主键,当为int类型时,默认自增。 非自增时,需要设置id的值

  @NoAutoIncrement  不自增

  @NotNull  不为空

  @Table    表名

  @Transient  不写入数据库表结构

  @Unique   唯一约束

第三步,创建实体类对象进行保存。

UserInfo userInfo=new UserInfo();

userInfo.setXX();

...

db.save(userInfo);

就这样数据库中就将你的数据保存起来了,你可能会有疑问,过程中我也没看到创建表啊,其实在save的时候,它内部会首先创建表(表名可以通过@Table来自定义 默认是你当前实体类的包名+类名,只不过将连接符"."换成了"_",例如com_example_bean_UserInfo  )

db.createTableIfNotExist(UserInfo.class); 

当然我们也可以自己先调用这个方法去创建表。其实看到上面在创建表的时候传的是Class对象,大家也可以猜到,dbUtils内部是用了反射的机制将实体类的属性保存成了表的相应字段。

我们在使用数据库的时候一般会进行一些增删改查,dbUtils都有相应的方法,用法也很简单,在这我就说几个注意点吧,在保存数据的时候,我们必须给实体类某个字段注解Id 作为主键,因为它内部存储是靠它来作为主键,并且是递增的。而且在更新的时候它内部可是靠这个Id来进行的。所
4000
以在更新某一条记录的时候不要直接用new出的实体类去直接调用update方法,应该是先通过findFirst方法获取实体类对象,设置属性值后再去update,否则,它会新插入一条记录而不是去更新。

dbUtils的update方法好像是只能更新相应字段的值,但是并不支持修改表结构。所以在修改表结构的时候需要我们自子去写sql语句。

下面我们赶紧步入正题了,如何在升级应用的时候修改表结构呢? 上面我们在创建数据库的时候也提过,它还有一个构造函数可以传一个更新监听,如下:

DbUtils dbUtils=DbUtils.create(this,"dbname",2, new DbUtils.DbUpgradeListener() {
@Override
public void onUpgrade(DbUtils dbUtils, int oldVersion, int newVersion) {
if(newVersion!=oldVersion){
//按需求进行更新
}
}
});

下面是我写的一个方法,用于更新表结构的数据,保存原来的数据
public static void updateTable(DbUtils dbUtils, Class<?> tClass) {
try {
if (dbUtils.tableIsExist(tClass)) {
String tableName = tClass.getName();
tableName = tableName.replace(".", "_");
String sql = "select * from " + tableName;
//声名一个map用来保存原有表中的字段
 Map<String, String> filedMap = new HashMap<>();
//执行自定义的sql语句
           Cursor cursor = dbUtils.execQuery(sql);
int count = cursor.getColumnCount();
for (int i = 0; i < count; i++) {
filedMap.put(cursor.getColumnName(i), cursor.getColumnName(i));
}
//cursor在用完之后一定要close
 cursor.close();
//下面用到了一些反射知识,下面是获取实体类的所有私有属性(即我们更改表结构后的所有字段名)
 Field[] fields = UserInfo.class.getDeclaredFields();

for (int i = 0; i < fields.length; i++) {
if (filedMap.containsKey(fields[i].getName())) {
//假如字段名已存在就进行下次循环
 continue;
} else {
//不存在,就放到map中,并且给表添加字段
 filedMap.put(fields[i].getName(), fields[i].getName());
//根据属性的类型给表增加字段
if (fields[i].getType().toString().equals("class java.lang.String")) {

dbUtils.execNonQuery("alter table " + tableName + " add " + fields[i].getName() + " TEXT ");
} else if (fields[i].getType().equals("int") || fields[i].getType().equals("long") || fields[i].getType().equals("boolean")) {
dbUtils.execNonQuery("alter table " + tableName + " add " + fields[i].getName() + " INTEGER ");
}
}
}

}
} catch (DbException e) {
e.printStackTrace();
}

}

方法中暂时没有删除字段,假如有实际需求大家可以根据这个思路去实现。拜拜~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: