制作一个Android Sqlite远程运维小工具

学更好的别人,

做更好的自己。

——《微卡智享》

2cebc13acd0e2ffe98565aab0782e35e.png

本文长度为3280,预计阅读7分钟

前言

前面的文章中《实现Android本地Sqlite数据库网络传输到PC端》中制作的将本地Sqlite数据库通过网络通讯传到PC端后进行数据的查看,为便运维时使用的,但是如果发现问题后需要对数据库的数据进行修改时,只能通过改了本地数据库再覆盖Android的数据库,这样操作起来非常麻烦,所以本章就是在当时的程序基础上实现了一个针对Android Sqlite数据库进行Sql操作的运维小工具。

db68f9a5895fe06330a1b6b25c3f86f5.png

实现效果

d9bd88617f4a7b8cb70ac2077b2c12b3.png

Android本地的数据库操作我们还是用的Room框架,只不过网上大部分Room的教程都是类的查询,做运维时是需要自己写Sql的,所以是用了Sqlite里面对应的query和execsql这两个方法(查询和执行脚本用到)

#思路
1区分查询还是执行,通过脚本开头是不是select来判断
2select开头的脚本返回Cursor后动态生成字符串后通讯到PC端
3不是select开头的使用execsql直接执行脚本
4通讯方式还是用前篇一样的NanoMsg

核心函数

使用Room返回的对象下面,有一个openHelper.writableDatabase,在这下面就可以找到query和execsql两个方法,用于执行脚本

88d1fafe73605cac767397b1f1211013.png

260ebae1f0053d8856f2178e2ee4237b.png

其实execSQL执行脚本这个比较简单,通讯过来的脚本是什么样,直接执行就完成了。关键是用query查询的怎么样展示出来。

Query的数据呈现

a5e1c7a2423e7877f9bb5af5dff00ab9.png

微卡智享

Query返回Cursor

点击Query的方法后可以看到方法中直接就是返回的Cursor、

1b7d1c55c12007544a4368c1bd2fd29d.png

因为手动写的Sql,并不能知道要返回的对应类,所以在返回数据的时候需要对Cursor进行动态数据的处理。

Cursor中有columncount和columnNames,通过这两个可以得到当前的游标返回的列数和列名。

val sb = StringBuilder()
              //生成对应列名
              val columnqty = it.columnCount
              for (i in 0 until columnqty) {
                  sb.append("[${it.columnNames[i]}]").append(",")
              }


              sb.deleteCharAt(sb.lastIndexOf(","))
              sb.append("\r\n")

而Cursor中获取数据时,都是用的getString、getInt、getFloat等方式,所以在获取数据前,首先需要判断当前列是什么数据类型,然后根据对应的数据类型使用相应的函数获取到数据。Cursor中有个getType的函数,通过这个方法可以获取到对应的数据类型,核心代码如下:

//生成对应数据
    it.moveToFirst()
    do {
        for (i in 0 until columnqty) {
            when (it.getType(i)) {
                Cursor.FIELD_TYPE_STRING -> {
                    sb.append(it.getString(i))
                }
                Cursor.FIELD_TYPE_INTEGER -> {
                    sb.append(it.getInt(i))
                }
                Cursor.FIELD_TYPE_FLOAT -> {
                    sb.append(it.getFloat(i))
                }
                Cursor.FIELD_TYPE_BLOB -> {
                    sb.append(it.getBlob(i))
                }
                else -> {
                    sb.append(it.getString(i))
                }
            }
            sb.append(",")
        }
        sb.deleteCharAt(sb.lastIndexOf(","))
        sb.append("\r\n")
    } while (it.moveToNext())

上面代码中使用了do while,主要是一开始用的while发现第一条数据会忽略掉了,所以用Do while实现后问题解决。

封装好的ExecSql方法

private fun ExecSql(sql: String) {
        val exectype = if (sql.trimStart().startsWith("select")) {
            1
        } else {
            2
        }
        //加载AppDataBase
        val db = DbUtil().getDatabase(this);
        val execsqlScope = CoroutineScope(Job())
        execsqlScope.launch(Dispatchers.IO) {
            try {
                when (exectype) {
                    1 -> {
                        val cursor = db.openHelper.writableDatabase.query(sql)
                        cursor?.let {
                            val sb = StringBuilder()
                            //生成对应列名
                            val columnqty = it.columnCount
                            for (i in 0 until columnqty) {
                                sb.append("[${it.columnNames[i]}]").append(",")
                            }


                            sb.deleteCharAt(sb.lastIndexOf(","))
                            sb.append("\r\n")


                            //生成对应数据
                            it.moveToFirst()
                            do {
                                for (i in 0 until columnqty) {
                                    when (it.getType(i)) {
                                        Cursor.FIELD_TYPE_STRING -> {
                                            sb.append(it.getString(i))
                                        }
                                        Cursor.FIELD_TYPE_INTEGER -> {
                                            sb.append(it.getInt(i))
                                        }
                                        Cursor.FIELD_TYPE_FLOAT -> {
                                            sb.append(it.getFloat(i))
                                        }
                                        Cursor.FIELD_TYPE_BLOB -> {
                                            sb.append(it.getBlob(i))
                                        }
                                        else -> {
                                            sb.append(it.getString(i))
                                        }
                                    }
                                    sb.append(",")
                                }
                                sb.deleteCharAt(sb.lastIndexOf(","))
                                sb.append("\r\n")
                            } while (it.moveToNext())


                            //传输数据
                            VNanoNNPairUtils.getInstance().Send(sb.toString().toByteArray())
                            withContext(Dispatchers.Main) {
                                tvshow.append("查询数据完成发送\r\n")
                            }
                        }
                    }
                    else -> {
                        db.runInTransaction {
                            db.openHelper.writableDatabase.execSQL(sql)
                        }
                        //传输数据
                        VNanoNNPairUtils.getInstance().Send("更新完成".toByteArray())
                    }
                }
            } catch (e: Exception) {
                withContext(Dispatchers.Main) {
                    tvshow.append(e.message + "\r\n")
                }
            }
        }
    }

TIPS

1f53083bc95ee38ffa189d7411938965.png

如上图,我这里返回的显示格式是第一行为列名,然后每个是对应的数据,其实掌握了动态生成的方法后,完全也可以自己拼装成Json的方法实现,我这主要自己通讯,用Json的方式每一条数据都要加一个列表,通讯的数据流太大,为了节省点资源还是改为了上面的方式。

cb3e0fb5917663b3e1af0d5e996506ef.png

顺便说一下,我又重新下了VS2022,C#这块直接用的VS2022编译的,新的编译器中智能提示实现在比原来强大太多了,看上图红框中就知道了。

后来找了个OpenCV的Demo直接在VS2022下打开升级编译后,也是一切正常,暂时看不出什么问题,并且鼠标指针悬停时的提示参数显示也比VS2019详细了好多,里面还有热重载的功能,等有时间也测试下,感觉项目整体升级到VS2022的日期越来越近了。

关于数据库的通讯,及通讯的方式,可以看《实现Android本地Sqlite数据库网络传输到PC端》这篇文中,最后这个Demo的源码地址如下,GitHub上不去的可以点击文末的原文链接,上面是码云的源码地址。

源码地址:

https://github.com/Vaccae/TransAndroidSqliteDBDemo.git

164f39c6a74364f3a81fd6e45b7b1bff.png

扫描二维码

获取更多精彩

微卡智享

fc3ab055ed3d65b2628a6bec2b90325c.png

「 往期文章 」

VS2022 MAUI Hello World——Windows平台及Android平台效果

Android BaseQuickAdapter3.0.4版本二级列表的使用及遇到的问题

Android Room数据库版本迁移的实战

 

非常好用的SQLiteSpy 1.8.16 免费正式版(内附有一做好的DB,大家可以马上看下效果)。网上看到的,整理了下,共享给大家! 希望有用! SQLiteSpy是一个快速和紧凑的图形用户界面的SQLite数据库管理软件。它可以读取sqlite3文件并执行SQL。图形用户界面使得它很容易分析和操纵sqlite3的数据库。 注意:SQLiteSpy是免费供个人和教育用途,SQLiteSpy主要特点: 1、数据库一览:树状显示所有的架构,包括表,列,索引和触发器在数据库中包含的项目。按F5更新架构树,双击一个表或视图来显示它的数据,使用常用的命令的上下文菜单。 2、网格单元格编辑:表格单元格中编辑,显示一个表通过树状架构,选择一个单元格,然后按F2键调用编辑器。然后修改并确认您的更改写回到表里。 3、数据类型显示:本机的SQL数据类型显示不同的背景颜色来帮助检测类型错误。类型错误可能会导致性能下降或错误的SELECT结果集,防止NULL值与空字符串混淆。 4、完全的Unicode: SQLiteSpy具有完全支持SQLite的Unicode的能力。数据显示和输入是完全实现为Unicode,包括SQL命令。 5、多个SQL编辑:现代标签是用来编辑和显示的查询语句和结果比较容易多个SQL查询。 SQL查询执行输入或加载到SQL他们编辑。然后按F9键运行该查询,或Ctrl + F9来运行当前行或选择只。 6、时间测量: SQL执行的时间会自动测量和显示,以帮助优化查询。 7、正则表达式:在SQL关键字regexp是支持,并增加了完整的Perl的正则表达式语法5.10 SQLiteSpy。的实施,实现了利用DIRegEx库。 8、数学SQL函数:下面的SQL函数可用数学除了SQLite的默认:ACOS(), ASIN(), ATAN(), ATAN(), ATAN2(), CEIL(), CEILING(), COS(), COT(), DEGREES(), EXP(), FLOOR(), LN(), LOG(), LOG(), LOG2(), LOG10(), MOD(), PI(), POW(), RADIANS(), SIGN(), SIN(), SQRT(), TAN(), TRUNCATE(). 9、数据压缩:压缩的SQL函数()适用的zlib的紧缩到任何文本或BLOB值。 10、紧凑型结果储存:使用内部数据存储机制,以达到最佳的兼容SQLite的原生数据类型。因此,SQLiteSpy使用远低于其它的SQLite管理内存和更有效地处理大量的表。 11、内建的SQLite引擎: SQLiteSpy已建成一个单一的应用程序文件与SQLite数据库引擎可执行文件。不需要部署任何DLL文件,这使得SQLiteSpy更易于部署。 12、加密支持: SQLiteSpy可以阅读和修改加密的数据库文件由DISQLite3产生。 DISQLite3实现了自己的母语AES加密。这为不符合商业SQLite的加密扩展(SSE)的或任何其他第三方的实施提供兼容。 13、易安装和卸载:要运行SQLiteSpy,只需解压SQLiteSpy.exe文件到任何目录和执行文件。不需要安装。刚开始时,该程序创建一个文件SQLiteSpy.db3(1 sqlite3的数据库)来存储的和设置。它不写任何其他文件或注册表。卸载一样只是简单的删除两个文件:应用程序的可执行文件和数据库文件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Vaccae

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值