移动架构-数据库分库和全版本升级

在项目中,往往涉及到数据库的版本升级,通常会有两种升级方式,一种是纯代码实现,一种是脚本实现,这里使用脚本升级,这样的升级方式更便于维护

思路

全版本升级,重点在于数据的迁移,这里使用备份原数据库,新建数据库,增删字段,复制数据库的升级思路,其版本控制在脚本中声明,代码在写好之后基本是不会变动的,更利于维护

SQLite修改表语句

  • 创建表 CREATE TABLE 表名 (列名 数据类型 限定符...)
CREATE TABLE Table (ID INTEGER,NAME TEXT);
  • 修改表 ALTER TABLE ...
    命令允许用户重命名或添加新的字段在已有表中,不能从表中删除字段。并且只能在表的末尾添加字段
ALTER TABLE tTable RENAME TO MyTable;
  • 添加一列 ALTER TABLE 表名 ADD COLUMN 列名 数据类型 限定符
ALTER TABLE MyTable ADD COLUMN AGE INTEGER;
  • 删除表 DROP TABLE 表名
DROP TABLE MyTable;

更改表结构的方法:

  1. 当表中没有任何数据时
    删除表
DROP TABLE MyTable;

创建表

CREATE TABLE MyTable ...
  1. 当表中有数据时
    将表名改为临时表
ALTER TABLE MyTable RENAME TO _temp_MyTable;

创建新表

CREATE TABLE MyTable (....);

导入数据

INSERT INTO MyTable SELECT .., .. ,"用空来补充原来不存在的数据" FROM _temp_MyTable;

删除临时表

DROP TABLE _temp_MyTable;

实现

这里沿用设计的数据库,数据库分库已经在项目中包含了
修改BaseDaoFactory,使其支持数据库分库

public class BaseDaoFactory {
    private static final String TAG = "BaseDaoFactory";
    private String sqliteDatabasePath;
    private SQLiteDatabase sqLiteDatabase;
    private SQLiteDatabase userDatabase;
    private Map<String, BaseDao> map = Collections.synchronizedMap(new HashMap<String, BaseDao>());
    private static BaseDaoFactory instance = new BaseDaoFactory();

    public static BaseDaoFactory getInstance() {
        return instance;
    }

    private BaseDaoFactory() {
        File file = new File(Environment.getExternalStorageDirectory(), "update");
        if (!file.exists()) {
            file.mkdirs();
        }
        sqliteDatabasePath = file.getAbsolutePath() + "/user.db";
        openDatabase();
    }

    public synchronized <T extends BaseDao<M>, M> T getDataHelper(Class<T> clazz, Class<M> entityClass) {
        BaseDao baseDao = null;
        if (map.get(clazz.getSimpleName()) != null) {
            return (T) map.get(clazz.getSimpleName());
        }
        try {
            baseDao = clazz.newInstance();
            baseDao.init(entityClass, sqLiteDatabase);
            map.put(clazz.getSimpleName(), baseDao);
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        return (T) baseDao;
    }

    public synchronized <T extends BaseDao<M>, M> T getUserHelper(Class<T> clazz, Class<M> entityClass) {
        openUserDatabase(getPath());
        BaseDao baseDao = null;
        //反射得到对象类型
        try {
            baseDao = clazz.newInstance();
            baseDao.init(entityClass, userDatabase);
            map.put(clazz.getSimpleName(), baseDao);
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return (T) baseDao;
    }

    private void openDatabase() {
        //打开数据库,如果不存在则创建
        sqLiteDatabase = SQLiteDatabase.openOrCreateDatabase(sqliteDatabasePath, null);
    }

    public String getPath() {
        UserDao userDao = BaseDaoFactory.getInstance().getDataHelper(UserDao.class, User.class);
        if (userDao == null) {
            return null;
        }
        User currentUser = userDao.getCurrentUser();
        if (currentUser == null) {
            return null;
        }
        File file = new File(Environment.getExternalStorageDirectory(), "update");
        if (!file.exists()) {
            file.mkdirs();
        }
        File childFile = new File(file.getAbsolutePath(), currentUser.getUser_id());
        if(!childFile.exists()){
            childFile.mkdirs();
        }
        return file.getAbsolutePath() + "/" + currentUser.getUser_id() + "/logic.db";
}

    private void openUserDatabase(String userDBPath) {
        //打开数据库,如果不存在则创建
        userDatabase = SQLiteDatabase.openOrCreateDatabase(userDBPath, null);
    }
}

创建数据库脚本

public class CreateDb {

    //数据库表名
    private String name;

    //创建表的sql语句集合
    private List<String> sqlCreates;

    public CreateDb(Element ele) {
        name = ele.getAttribute("name");
        sqlCreates = new ArrayList<String>();
        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<String> getSqlCreates() {
        return sqlCreates;
    }

    public void setSqlCreates(List<String> sqlCreates) {
        this.sqlCreates = sqlCreates;
    }
}

数据库升级创建表脚本

public class CreateVersion {
    //版本信息
    private String version;

    //创建数据库表脚本
    private List<CreateDb> createDbs;

    public CreateVersion(Element ele) {
        version = ele.getAttribute("version");
        createDbs = new ArrayList<CreateDb>();
        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<CreateDb> getCreateDbs() {
        return createDbs;
    }

    public void setCreateDbs(List<CreateDb> createDbs) {
        this.createDbs = createDbs;
    }
}

复制单个文件(可更名复制)

public class FileUtil {
    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();
        }
    }
}

更新数据库脚本

public class UpdateDb {
    //数据库名称
    private String dbName;
    private List<String> sqlBefores;
    private List<String> sqlAfters;

    public UpdateDb(Element ele) {
        dbName = ele.getAttribute("name");
        sqlBefores = new ArrayList<String>();
        sqlAfters = new ArrayList<String>();
        NodeList sqlsBefore = ele.getElementsByTagName("sql_before");
        for (int i = 0; i < sqlsBefore.getLength(); i++) {
            String sql_before = sqlsBefore.item(i).getTextContent();
            this.sqlBefores.add(sql_before);
        }
        NodeList sqlsAfter = ele.getElementsByTagName("sql_after");
        for (int i = 0; i < sqlsAfter.getLength(); i++) {
            String sql_after = sqlsAfter.item(i).getTextContent();
            this.sqlAfters.add(sql_after);
        }
    }

    public String getDbName() {
        return dbName;
    }

    public void setDbName(String dbName) {
        this.dbName = dbName;
    }

    public List<String> getSqlBefores() {
        return sqlBefores;
    }

    public void setSqlBefores(List<String> sqlBefores) {
        this.sqlBefores = sqlBefores;
    }

    public List<String> getSqlAfters() {
        return sqlAfters;
    }

    public void setSqlAfters(List<String> sqlAfters) {
        this.sqlAfters = sqlAfters;
    }
}

升级更新数据库

public class UpdateDbXml {
    //升级脚本列表
    private List<UpdateStep> updateSteps;

    //升级版本
    private List<CreateVersion> createVersions;

    public UpdateDbXml(Document document) {
        // 获取升级脚本
        NodeList updateSteps = document.getElementsByTagName("updateStep");
        this.updateSteps = new ArrayList<UpdateStep>();
        for (int i = 0; i < updateSteps.getLength(); i++) {
            Element ele = (Element) (updateSteps.item(i));
            UpdateStep step = new UpdateStep(ele);
            this.updateSteps.add(step);
        }
        //获取各升级版本
        NodeList createVersions = document.getElementsByTagName("createVersion");
        this.createVersions = new ArrayList<CreateVersion>();
        for (int i = 0; i < createVersions.getLength(); i++) {
            Element ele = (Element) (createVersions.item(i));
            CreateVersion cv = new CreateVersion(ele);
            this.createVersions.add(cv);
        }
    }

    public List<UpdateStep> getUpdateSteps() {
        return updateSteps;
    }

    public void setUpdateSteps(List<UpdateStep> updateSteps) {
        this.updateSteps = updateSteps;
    }

    public List<CreateVersion> getCreateVersions() {
        return createVersions;
    }

    public void setCreateVersions(List<CreateVersion> createVersions) {
        this.createVersions = createVersions;
    }
}

数据库升级脚本信息

public class UpdateStep {
    //旧版本
    private String versionFrom;

    //新版本
    private String versionTo;

    //更新数据库脚本
    private List<UpdateDb> updateDbs;

    public UpdateStep(Element ele) {
        versionFrom = ele.getAttribute("versionFrom");
        versionTo = ele.getAttribute("versionTo");
        updateDbs = new ArrayList<UpdateDb>();
        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<UpdateDb> getUpdateDbs() {
        return updateDbs;
    }

    public void setUpdateDbs(List<UpdateDb> 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;
    }
}

数据库脚本管理

public class UpdateManager {
    private static final String TAG = "UpdateManager";
    private static final String INFO_FILE_DIV = "/";
    private List<User> userList;
    private File parentFile = new File(Environment.getExternalStorageDirectory(), "update");
    private File bakFile = new File(parentFile, "backDb");

    public UpdateManager() {
        if (!parentFile.exists()) {
            parentFile.mkdirs();
        }
        if (!bakFile.exists()) {
            bakFile.mkdirs();
        }

    }

    public void checkThisVersionTable(Context context) {
        UserDao userDao = BaseDaoFactory.getInstance().getDataHelper(UserDao.class, User.class);
        userList = userDao.query(new User());
        UpdateDbXml xml = readDbXml(context);
        String thisVersion = getVersionName(context);
        CreateVersion thisCreateVersion = analyseCreateVersion(xml, thisVersion);
        try {
            executeCreateVersion(thisCreateVersion, true);
        } catch (Exception e) {
        }

    }

    //开始升级
    public void startUpdateDb(Context context) {
        UpdateDbXml updateDbxml = readDbXml(context);
        if (getLocalVersionInfo()) {
            //拿到当前版本
            String thisVersion = getVersionName(context);
            //拿到上一个版本
            String lastVersion = lastBackupVersion;
            UpdateStep updateStep = analyseUpdateStep(updateDbxml, lastVersion, thisVersion);
            if (updateStep == null) {
                return;
            }
            List<UpdateDb> updateDbs = updateStep.getUpdateDbs();
            CreateVersion createVersion = analyseCreateVersion(updateDbxml, thisVersion);
            try {
                //更新每个用户的数据库
                for (User user : userList) {
                    String logicDbDir = parentFile.getAbsolutePath() + "/update" + "/" + user.getUser_id() + "/logic.db";

                    String logicCopy = bakFile.getAbsolutePath() + "/" + user.getUser_id() + "/logic.db";
                    FileUtil.CopySingleFile(logicDbDir, logicCopy);
                }
                //备份总数据库
                String user = parentFile.getAbsolutePath() + "/user.db";
                String user_bak = bakFile.getAbsolutePath() + "/user.db";
                FileUtil.CopySingleFile(user, user_bak);
                // 第二步:执行sql_before语句,删除以及备份相关旧表
                executeDb(updateDbs, -1);
                // 第三步:检查新表,创建新表
                executeCreateVersion(createVersion, false);
                Log.d(TAG, "第三步检查新表完成!");
                // 第四步:从备份表中恢复数据,恢复后删除备份表
                executeDb(updateDbs, 1);
            } catch (Exception e) {
                e.printStackTrace();
            }
            // 第五步:升级成功,删除备份数据库
            if (userList != null && !userList.isEmpty()) {
                for (User user : userList) {
                    String logicDbDir = parentFile.getAbsolutePath() + "/update" + "/" + user.getUser_id() + ".db";
                    File file = new File(logicDbDir);
                    if (file.exists()) {
                        file.delete();
                    }
                }
            }
            File userFileBak = new File(bakFile.getAbsolutePath() + "user_bak.db");
            if (userFileBak.exists()) {
                userFileBak.delete();
            }
            Log.d(TAG, "升级成功");
        }
    }

    //根据建表脚本,核实一遍应该存在的表
    private void executeCreateVersion(CreateVersion createVersion, boolean isLogic) 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;");
            }
            if (!"logic".equals(cd.getName())) {
                continue;
            }
            // 创建数据库表sql
            List<String> sqls = cd.getSqlCreates();
            SQLiteDatabase sqlitedb = null;
            try {
                // 逻辑层数据库要做多用户升级
                if (userList != null && !userList.isEmpty()) {
                    // 多用户建新表
                    for (int i = 0; i < userList.size(); i++) {
                        // 获取db
                        sqlitedb = getDb(cd, userList.get(i).getUser_id());
                        executeSql(sqlitedb, sqls);
                        sqlitedb.close();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                // 关闭数据库
                if (sqlitedb != null) {
                    sqlitedb.close();
                }
            }
        }
    }


    //执行针对db升级的sql集合 type:小于0为建表前,大于0为建表后
    private void executeDb(List<UpdateDb> updateDbs, int type) throws Exception {
        if (updateDbs == null) {
            throw new Exception("updateDbs is null;");
        }
        for (UpdateDb db : updateDbs) {
            if (db == null || db.getDbName() == null) {
                throw new Exception("db or dbName is null;");
            }
            List<String> sqls = null;
            //更改表
            if (type < 0) {
                sqls = db.getSqlBefores();
            } else if (type > 0) {
                sqls = db.getSqlAfters();
            }
            SQLiteDatabase sqlitedb = null;
            try {
                // 逻辑层数据库要做多用户升级
                if (userList != null && !userList.isEmpty()) {
                    // 多用户表升级
                    for (int i = 0; i < userList.size(); i++) {
                        sqlitedb = getDb(db, userList.get(i).getUser_id());
                        executeSql(sqlitedb, sqls);
                        sqlitedb.close();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (null != sqlitedb) {
                    sqlitedb.close();
                }
            }
        }
    }

    //执行sql语句
    private void executeSql(SQLiteDatabase sqlitedb, List<String> sqls) throws Exception {
        // 检查参数
        if (sqls == null || sqls.size() == 0) {
            return;
        }
        // 事务
        sqlitedb.beginTransaction();
        for (String sql : sqls) {
            sql = sql.replaceAll("
", " ");
            sql = sql.replaceAll("
", " ");
            if (!"".equals(sql.trim())) {
                try {
                    // Logger.i(TAG, "执行sql:" + sql, false);
                    sqlitedb.execSQL(sql);
                } catch (SQLException e) {
                }
            }
        }
        sqlitedb.setTransactionSuccessful();
        sqlitedb.endTransaction();
    }


    //新表插入数据
    private UpdateStep analyseUpdateStep(UpdateDbXml xml, String lastVersion, String thisVersion) {
        if (lastVersion == null || thisVersion == null) {
            return null;
        }
        // 更新脚本
        UpdateStep thisStep = null;
        if (xml == null) {
            return null;
        }
        List<UpdateStep> 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;
    }

    //根据xml对象获取对应要修改的db文件
    private SQLiteDatabase getDb(UpdateDb db, String userId) {
        return getDb(db.getDbName(), userId);
    }

    private SQLiteDatabase getDb(CreateDb db, String userId) {
        return getDb(db.getName(), userId);
    }

    //创建数据库,获取数据库对应的SQLiteDatabase
    private SQLiteDatabase getDb(String dbname, String userId) {
        String dbfilepath = null;
        SQLiteDatabase sqlitedb = null;
        File file = new File(parentFile, userId);
        if (!file.exists()) {
            file.mkdirs();
        }
        if (dbname.equalsIgnoreCase("logic")) {
            dbfilepath = file.getAbsolutePath() + "/logic.db";// logic对应的数据库路径
        } else if (dbname.equalsIgnoreCase("user")) {
            dbfilepath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/user.db";// service对应的数据库
        }
        if (dbfilepath != null) {
            File f = new File(dbfilepath);
            f.mkdirs();
            if (f.isDirectory()) {
                f.delete();
            }
            sqlitedb = SQLiteDatabase.openOrCreateDatabase(dbfilepath, null);
        }
        return sqlitedb;
    }


    //解析出对应版本的建表脚本
    private CreateVersion analyseCreateVersion(UpdateDbXml xml, String version) {
        CreateVersion cv = null;
        if (xml == null || version == null) {
            return cv;
        }
        List<CreateVersion> createVersions = xml.getCreateVersions();
        if (createVersions != null) {
            for (CreateVersion item : createVersions) {
                // 如果表相同则要支持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;
    }

    //读取升级xml
    private 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;
    }

    //获取APK版本号
    public String getVersionName(Context context) {
        String versionName = null;
        try {
            PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
            versionName = info.versionName;
        } catch (PackageManager.NameNotFoundException e) {
        }
        return versionName;
    }

    //保存下载APK版本信息
    public boolean saveVersionInfo(Context context, String newVersion) {
        boolean ret = false;
        FileWriter writer = null;
        try {
            writer = new FileWriter(new File(parentFile, "update.txt"), false);
            writer.write("V003" + INFO_FILE_DIV + "V002");
            writer.flush();
            ret = true;
        } catch (IOException e) {
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return ret;
    }

    //获取本地版本相关信息
    private String existVersion;
    private String lastBackupVersion;

    private boolean getLocalVersionInfo() {
        boolean ret = false;
        File file = new File(parentFile, "update.txt");
        if (file.exists()) {
            int byteread = 0;
            byte[] tempbytes = new byte[100];
            StringBuilder stringBuilder = new StringBuilder();
            InputStream in = null;
            try {
                in = new FileInputStream(file);
                while ((byteread = in.read(tempbytes)) != -1) {
                    stringBuilder.append(new String(tempbytes, 0, byteread));
                }
                String[] infos = stringBuilder.toString().split(INFO_FILE_DIV);
                if (infos.length == 2) {
                    existVersion = infos[0];
                    lastBackupVersion = infos[1];
                    ret = true;
                }
            } catch (Exception e) {

            } finally {
                if (null != in) {
                    try {
                        in.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    in = null;
                }
            }
        }
        return ret;
    }
}

模拟用户登录

@DbTable("tb_user")
public class User {

    public String name;

    public String password;

    public String user_id;
    public Integer status;

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public String getUser_id() {
        return user_id;
    }

    public void setUser_id(String user_id) {
        this.user_id = user_id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}
public class UserDao extends BaseDao<User> {
    private static final String TAG = "UserDao";
    @Override
    public String createTable() {
        return "create table if not exists tb_user( name TEXT, password TEXT, user_id Text,status Integer);";
    }

    @Override
    public long insert(User entity) {
        List<User> list = query(new User());
        User where = null;
        for (User user : list) {
            where = new User();
            where.setUser_id(user.getUser_id());
            user.setStatus(0);
            update(user, where);
        }
        Log.d(TAG, "用户" + entity.getName() + "登录");
        entity.setStatus(1);
        return super.insert(entity);
    }

    //得到当前登录的User
    public User getCurrentUser() {
        User user = new User();
        user.setStatus(1);
        List<User> list = query(user);
        if (list.size() > 0) {
            return list.get(0);
        }
        return null;
    }
}

模拟用户下载数据

@DbTable("tb_photo")
public class Photo {
    public String time;

    public String path;

    public String getTime() {
        return time;
    }

    public void setTime(String time) {
        this.time = time;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }
}
public class PhotoDao extends BaseDao<Photo> {

    @Override
    public String createTable() {
        return "create table if not exists tb_photo(
" +
                "                time TEXT,
" +
                "                path TEXT,
" +
                "                to_user TEXT
" +
                "                )";
    }
}

测试

public class MainActivity extends AppCompatActivity {

    UpdateManager updateManager;
    UserDao baseDao;
    int i = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        updateManager = new UpdateManager();
        baseDao = BaseDaoFactory.getInstance().getDataHelper(UserDao.class, User.class);
    }

    public void login(View view) {

        User user = new User();
        user.setName("V00" + (i++));
        user.setPassword("123456");
        user.setName("jack" + i);
        user.setUser_id("N000" + i);
        baseDao.insert(user);
        updateManager.checkThisVersionTable(this);
    }

    public void insert(View view) {
        Photo photo = new Photo();
        photo.setPath("data/data/my.jpg");
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
        photo.setTime(dateFormat.format(new Date()));
        PhotoDao photoDao = BaseDaoFactory.getInstance().getUserHelper(PhotoDao.class, Photo.class);
        photoDao.insert(photo);
    }

    public void write(View view) {
        //写入版本
        updateManager.saveVersionInfo(this, "V002");
    }

    public void update(View view) {
        updateManager.checkThisVersionTable(this);
        updateManager.startUpdateDb(this);
    }
}

在Assets文件夹加入升级脚本

<!-- 请保证该文档一定是 UTF-8编码 -->
<updateXml>
    <createVersion version="V003">
        <createDb name="user">
            <!-- 设备与软件关联信息 -->
            <sql_createTable>
                create table if not exists tb_user(
                name TEXT,
                password TEXT,
                loginName TEXT,
                lastLoginTime,
                user_id Integer primary key
                );
            </sql_createTable>
        </createDb>
        <createDb name="logic">
            <!-- 设备与软件关联信息 -->
            <sql_createTable>
                create table if not exists tb_photo(
                time TEXT,
                path TEXT,
                to_user TEXT,
                sendTime TEXT
                );
            </sql_createTable>
        </createDb>
    </createVersion>
    <updateStep
        versionFrom="V002"
        versionTo="V003">
        <updateDb name="logic">
            <sql_before>alter table tb_photo rename to bak_tb_photo;</sql_before>
            <sql_after>
                insert into tb_photo(time,
                path)
                select time,path
                from bak_tb_photo;
            </sql_after>
            <sql_after>
                drop table if exists bak_tb_photo;
            </sql_after>
        </updateDb>
        <updateDb name="user">
            <sql_before>alter table tb_user rename to bak_t_user;</sql_before>
            <sql_after>
                insert into tb_user(name,
                password)
                select name,password
                from bak_tb_user;
            </sql_after>
            <sql_after>
                drop table if exists bak_t_user;
            </sql_after>
        </updateDb>
    </updateStep>
</updateXml>

注意当前版本与升级脚本的一致

原文地址:https://www.cnblogs.com/cj5785/p/10664611.html