Android|Android 架构之数据库框架升级

目录

  • 1、备份原数据库File文件
  • 2、数据库升级XML编写 updateXml.xml
  • 3、创建XML解析器
    • 3.1 对应工具类 DomUtils.class
    • 3.2 对应XML的实体类
  • 4、万事俱备只欠东风: UpdateManager.class
    前言:
    上一篇讲解了Android 架构之数据框架搭建 ,里面含有数据库最基础的增删改查功能,不过只考虑了单数据库,开发者可以举一反三按照对应思路设计多数据库架构。 在本篇里,将会讲解令开发者比较头疼的数据库升级。
    话不多说,先来看代码效果,看看是否是想要的
    Android|Android 架构之数据库框架升级
    文章图片

    如上图所示:
    • 当前APP版本号为V007;
    • V001、V002升级到V007有对应的处理逻辑;
    • V003、V004、V005、V006升级到V007也有对应的处理逻辑;
    • 同理可实现任意版本可阔多个版本升级到最新数据库;
    开始之前我们先理一下数据库升级的逻辑
    1. 任何数据库在操作之前,我们最好有一个数据库备份,所以这里得要备份对应的数据库File文件;
    2. 任何数据表在操作之前,也要有一个数据表备份,所以这里会在原表名加前后缀操作;
    3. 在数据表升级的时候,有些时候可能会对表名、表列做任意增删改的操作,所以这里每次都要创建一个全新的表;
    4. 全新表创建好了,但是一张空表,这里就需要查询对应加了前后缀的原表数据,将对应数据添加至新表里;
    5. 数据全部拷贝完成时,为了让用户有良好的体验,我们需要删除对应加了前后缀的原表;
    6. 对应原表删除完毕时,我们需要删除对应备份数据库的File文件。
    总结:
    • 操作【1】和【6】 这俩操作 属于 java代码执行
    • 其他【2】、【3】、【4】、【5】 这些操作,都属于SQL操作
    • 但SQL操作,通过效果图发现,是写在XML文件里面的,所以需要写一个XML解析器
    现在我们就按照对应步骤一一讲解

    1、备份原数据库File文件
    /*** 复制单个文件(可更名复制)** @param oldPathFile 准备复制的文件源* @param newPathFile 拷贝到新绝对路径带文件名(注:目录路径需带文件名)* @return*/public static void CopySingleFile(String oldPathFile, String newPathFile) {try {//int bytesum = 0; int byteread = 0; File oldfile = new File(oldPathFile); File newFile = new File(newPathFile); File parentFile = newFile.getParentFile(); if (!parentFile.exists()) {parentFile.mkdirs(); }if (oldfile.exists()) { //文件存在时InputStream inStream = new FileInputStream(oldPathFile); //读入原文件FileOutputStream fs = new FileOutputStream(newPathFile); byte[] buffer = new byte[1024]; while ((byteread = inStream.read(buffer)) != -1) {//bytesum += byteread; //字节数 文件大小fs.write(buffer, 0, byteread); }inStream.close(); }} catch (Exception e) {e.printStackTrace(); }}

    总结:这也没啥可说的,就一个很简单的文件复制。

    2、数据库升级XML编写 updateXml.xml
    create table if not exists tb_photo ( id Long,tb_time TEXT ,tb_path TEXT,tb_name TEXT); alter table tb_photo rename to bak_tb_photo; insert into tb_photo(tb_time,id, tb_path) select tb_time,tb_id,tb_path from bak_tb_photo; drop table if exists bak_tb_photo; alter table tb_photo rename to bak_tb_photo; insert into tb_photo(tb_time,id, tb_path) select tb_time,tb_id,tb_path frombak_tb_photo; drop table if exists bak_tb_photo;

    总结:
    • createVersion 标签 ,表示 当前 最新APP版本需要操作的内容
    • createDb 标签,表示当前最新对应的数据库要操作的内容,可多组标签,实现多个数据库升级
    • sql_createTable 标签,表示当前最新对应的数据表要操作的内容,可多组标签,实现多表升级
    • updateStep 标签,表示不同版本要升级的对象,可多组标签,达到不同版本数据库升级到最新数据库的效果
    • updateDb 标签,表示旧版本要修改的对应数据库
    • sql_before 标签,表示数据库升级时优先级最高的SQL,(在新表创建前执行)
    • sql_after 标签,表示数据库升级时优先级最低并按顺序执行的SQL(在新表创建后执行)

    3、创建XML解析器

    3.1 对应工具类 DomUtils.class

    public class DomUtils {/*** 读取升级xml** @param context* @return*/public static UpdateDbXml readDbXml(Context context) {InputStream is = null; Document document = null; try {is = context.getAssets().open("updateXml.xml"); DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); document = builder.parse(is); } catch (Exception e) {e.printStackTrace(); } finally {if (is != null) {try {is.close(); } catch (IOException e) {e.printStackTrace(); }}}if (document == null) {return null; }UpdateDbXml xml = new UpdateDbXml(document); return xml; }/*** 新表插入数据** @param xml* @param lastVersion 上个版本* @param thisVersion 当前版本* @return*/public static UpdateStep findStepByVersion(UpdateDbXml xml, String lastVersion, String thisVersion) {if (lastVersion == null || thisVersion == null) {return null; }// 更新脚本UpdateStep thisStep = null; if (xml == null) {return null; }List steps = xml.getUpdateSteps(); if (steps == null || steps.size() == 0) {return null; }for (UpdateStep step : steps) {if (step.getVersionFrom() == null || step.getVersionTo() == null) {} else {// 升级来源以逗号分隔String[] lastVersionArray = step.getVersionFrom().split(","); if (lastVersionArray != null && lastVersionArray.length > 0) {for (int i = 0; i < lastVersionArray.length; i++) {// 有一个配到update节点即升级数据if (lastVersion.equalsIgnoreCase(lastVersionArray[i]) && step.getVersionTo().equalsIgnoreCase(thisVersion)) {thisStep = step; break; }}}}}return thisStep; }/*** 解析出对应版本的建表脚本** @return*/public static CreateVersion findCreateByVersion(UpdateDbXml xml, String version) {CreateVersion cv = null; if (xml == null || version == null) {return cv; }List createVersions = xml.getCreateVersions(); if (createVersions != null) {for (CreateVersion item : createVersions) {Log.i("david", "item=" + item.toString()); // 如果表相同则要支持xml中逗号分隔String[] createVersion = item.getVersion().trim().split(","); for (int i = 0; i < createVersion.length; i++) {if (createVersion[i].trim().equalsIgnoreCase(version)) {cv = item; break; }}}}return cv; }}


    3.2 对应XML的实体类

    UpdateDbXml
    /** * @ClassName: UpdateDbXml * @Description: 升级更新数据库 * */public class UpdateDbXml {/*** 升级脚本列表*/private List updateSteps; /*** 升级版本*/private List createVersions; public UpdateDbXml(Document document) {{// 获取升级脚本NodeList updateSteps = document.getElementsByTagName("updateStep"); this.updateSteps = new ArrayList(); for (int i = 0; i < updateSteps.getLength(); i++) {Element ele = (Element) (updateSteps.item(i)); Log.i("jett","updateSteps 各个升级的版本:"+ele.toString()); UpdateStep step = new UpdateStep(ele); this.updateSteps.add(step); }}{/*** 获取各升级版本*/NodeList createVersions = document.getElementsByTagName("createVersion"); this.createVersions = new ArrayList(); for (int i = 0; i < createVersions.getLength(); i++) {Element ele = (Element) (createVersions.item(i)); Log.i("jett","各个升级的版本:"+ele.toString()); CreateVersion cv = new CreateVersion(ele); this.createVersions.add(cv); }}}public List getUpdateSteps() {return updateSteps; }public void setUpdateSteps(List updateSteps) {this.updateSteps = updateSteps; }public List getCreateVersions() {return createVersions; }public void setCreateVersions(List createVersions) {this.createVersions = createVersions; }}

    UpdateStep.class

    /** * @ClassName: UpdateStep * @Description: 数据库升级脚本信息 */public class UpdateStep{ /*** 旧版本*/ private String versionFrom; /*** 新版本*/ private String versionTo; /*** 更新数据库脚本*/ private List updateDbs; // ================================================== public UpdateStep(Element ele) {versionFrom = ele.getAttribute("versionFrom"); versionTo = ele.getAttribute("versionTo"); updateDbs = new ArrayList(); NodeList dbs = ele.getElementsByTagName("updateDb"); for (int i = 0; i < dbs.getLength(); i++){Element db = (Element) (dbs.item(i)); UpdateDb updateDb = new UpdateDb(db); this.updateDbs.add(updateDb); } } public List getUpdateDbs() {return updateDbs; } public void setUpdateDbs(List updateDbs) {this.updateDbs = updateDbs; } public String getVersionFrom() {return versionFrom; } public void setVersionFrom(String versionFrom) {this.versionFrom = versionFrom; } public String getVersionTo() {return versionTo; } public void setVersionTo(String versionTo) {this.versionTo = versionTo; }}

    UpdateDb.class

    ** * @ClassName: UpdateDb * @Description: 更新数据库脚本 * */public class UpdateDb{ /*** 数据库名称*/ private String dbName; /*** */ private List sqlBefores; /*** */ private List sqlAfters; public UpdateDb(Element ele) {dbName = ele.getAttribute("name"); sqlBefores = new ArrayList(); sqlAfters = new ArrayList(); {NodeList sqls = ele.getElementsByTagName("sql_before"); for (int i = 0; i < sqls.getLength(); i++){String sql_before = sqls.item(i).getTextContent(); this.sqlBefores.add(sql_before); }}{NodeList sqls = ele.getElementsByTagName("sql_after"); for (int i = 0; i < sqls.getLength(); i++){String sql_after = sqls.item(i).getTextContent(); this.sqlAfters.add(sql_after); }} } public String getName() {return dbName; } public void setDbName(String dbName) {this.dbName = dbName; } public List getSqlBefores() {return sqlBefores; } public void setSqlBefores(List sqlBefores) {this.sqlBefores = sqlBefores; } public List getSqlAfters() {return sqlAfters; } public void setSqlAfters(List sqlAfters) {this.sqlAfters = sqlAfters; }}

    【Android|Android 架构之数据库框架升级】CreateVersion.class

    public class CreateVersion{ /*** 版本信息*/ private String version; /*** 创建数据库表脚本*/ private List createDbs; public CreateVersion(Element ele) {version = ele.getAttribute("version"); Log.i("jett","CreateVersion="+version); {createDbs = new ArrayList(); NodeList cs = ele.getElementsByTagName("createDb"); for (int i = 0; i < cs.getLength(); i++){Element ci = (Element) (cs.item(i)); CreateDb cd = new CreateDb(ci); this.createDbs.add(cd); }} } public String getVersion() {return version; } public void setVersion(String version) {this.version = version; } public List getCreateDbs() {return createDbs; } public void setCreateDbs(List createDbs) {this.createDbs = createDbs; }}

    CreateDb.class
    /** * @ClassName: CreateDb * @Description: 创建数据库脚本 * */public class CreateDb{ /*** 数据库表名*/ private String name; /*** 创建表的sql语句集合*/ private List sqlCreates; public CreateDb(Element ele) {name = ele.getAttribute("name"); {sqlCreates = new ArrayList(); NodeList sqls = ele.getElementsByTagName("sql_createTable"); for (int i = 0; i < sqls.getLength(); i++){String sqlCreate = sqls.item(i).getTextContent(); this.sqlCreates.add(sqlCreate); }} } public String getName() {return name; } public void setName(String name) {this.name = name; } public List getSqlCreates() {return sqlCreates; } public void setSqlCreates(List sqlCreates) {this.sqlCreates = sqlCreates; }}


    4、万事俱备只欠东风: UpdateManager.class
    public class UpdateManager {private File parentFile = ContUtils.parentFile; private File bakFile = ContUtils.bakFile; private List userList; public void startUpdateDb(Context context) {//读取XML文件,将XML内容转化为对应对象UpdateDbXml updateDbxml = DomUtils.readDbXml(context); //下载 上一个版本--》下一个版本【注:在下载时,需要将旧版本、新版本以逗号的形式写入文件缓存】String[] versions = FileUtil.getLocalVersionInfo(new File(parentFile,"update.txt")); String lastVersion = versions[0]; //拿到上一个版本String thisVersion = versions[1]; //拿到当前版本//数据库File原地址String userFile = ContUtils.sqliteDatabasePath; //数据库File备份地址String user_bak = ContUtils.copySqliteDatabasePath; //升级前,数据库File备份FileUtil.CopySingleFile(userFile, user_bak); //根据对应新旧版本号查询XML转化对象里面的脚本,得到对应升级脚本UpdateStep updateStep = DomUtils.findStepByVersion(updateDbxml, lastVersion, thisVersion); if (updateStep == null) {return; }//拿到对应升级脚本List updateDbs = updateStep.getUpdateDbs(); try {//将原始数据库中所有的表名 更改成 bak_表名(数据还在)executeBeforesSql(updateDbs); //检查新表,创建新表CreateVersion createVersion = DomUtils.findCreateByVersion(updateDbxml, thisVersion); executeCreateVersion(createVersion); //将原来bak_表名的数据迁移到 新表中executeAftersSql(updateDbs); } catch (Exception e) {e.printStackTrace(); }}private void executeAftersSql(List updateDbs) throws Exception {for (UpdateDb db : updateDbs) {if (db == null || db.getName() == null) {throw new Exception("db or dbName is null; "); }List sqls = db.getSqlAfters(); SQLiteDatabase sqlitedb = getDb(); //执行数据库语句executeSql(sqlitedb, sqls); sqlitedb.close(); }}private void executeCreateVersion(CreateVersion createVersion) throws Exception {if (createVersion == null || createVersion.getCreateDbs() == null) {throw new Exception("createVersion or createDbs is null; "); }for (CreateDb cd : createVersion.getCreateDbs()) {if (cd == null || cd.getName() == null) {throw new Exception("db or dbName is null when createVersion; "); }// 创建数据库表sqlList sqls = cd.getSqlCreates(); SQLiteDatabase sqlitedb = getDb(); executeSql(sqlitedb, sqls); sqlitedb.close(); }}//所有的表名 更改成 bak_表名(数据还在)private void executeBeforesSql(List updateDbs) throws Exception {for (UpdateDb db : updateDbs) {if (db == null || db.getName() == null) {throw new Exception("db or dbName is null; "); }List sqls = db.getSqlBefores(); SQLiteDatabase sqlitedb = getDb(); //执行数据库语句executeSql(sqlitedb, sqls); sqlitedb.close(); }}private SQLiteDatabase getDb() {String dbfilepath = null; SQLiteDatabase sqlitedb = null; dbfilepath = ContUtils.sqliteDatabasePath; // logic对应的数据库路径if (dbfilepath != null) {File f = new File(dbfilepath); f.mkdirs(); if (f.isDirectory()) {f.delete(); }sqlitedb = SQLiteDatabase.openOrCreateDatabase(dbfilepath, null); }return sqlitedb; }private void executeSql(SQLiteDatabase sqlitedb, List sqls) {// 检查参数if (sqls == null || sqls.size() == 0) {return; }sqlitedb.beginTransaction(); for (String sql : sqls) {sql = sql.replaceAll("\r\n", " "); sql = sql.replaceAll("\n", " "); if (!"".equals(sql.trim())) {try {// Logger.i(TAG, "执行sql:" + sql, false); sqlitedb.execSQL(sql); } catch (SQLException e) {}}}sqlitedb.setTransactionSuccessful(); sqlitedb.endTransaction(); }}

    到此这篇关于Android 架构之数据库框架升级的文章就介绍到这了,更多相关Android 架构之数据库框架内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

      推荐阅读