Android手把手编写儿童手机远程监控App之SQLite详解2

概述

上节完成嘟宝SQLite数据库功能。SQLite 是一个嵌入式关系型数据库管理系统,与传统数据库(如 MySQL、PostgreSQL)不同,它不是一个独立的进程,而是一个可以直接嵌入到应用程序文件性数据库。是全球部署最广泛的数据库引擎,因为它在简单性、可靠性和功能性之间取得了很好的平衡。如果你需要一个轻量级、零配置、可靠的数据存储解决方案,SQLite 是非常好的选择。

SQLite数据类型不多,简单够用。

  • INTEGER数字类型
  • REAL浮点型
  • TEXT文本型
  • BLOB二进制文件类型 SQLiteOpenHelper类是Android 用于管理SQLite数据库。包括数据库的创建、数据的增删改查、事物等等。在 Android 中使用原始 SQL 语句操作 SQLite 数据库,相比使用 ORM 框架(如 Room)或 Android 封装的 API,有以下显著好处:
  • 完全的控制权
  • 执行复杂查询更高效
  • 性能优势明显
  • 迁移和维护简单
  • 调试和排查问题方便
  • 避免 ORM 的陷阱

基于原始SQL增删改查

表结构: id 主键、自增、不为空 dumaName 嘟妈名称 dumaId嘟妈身份识别码 bindDateTime嘟妈绑定时间 核心函数

  • rawQuery 用于原始SQL查询功能
  • execSQL用于原始SQL增删改、表格创建等
clike 复制代码
Cursor rawQuery(String sql, String[] selectionArgs)
Cursor cursor = db.rawQuery("SELECT * FROM users WHERE age > ? AND name LIKE ?", new Object[]{"18", "%张%"});

rawQuery只要不抛出SQLException 异常,代表执行成功,他的返回查询结果是Cursor 。selectionArgs是占位符,它将Object内的结构分配给SQL语句中的问号。实际生成的SQL语句

clike 复制代码
SELECT * FROM users WHERE age > 18 AND name LIKE "18"
clike 复制代码
void execSQL(String sql, Object[] bindArgs)
db.execSQL("INSERT INTO users (name, age) VALUES (?, ?)", 
           new Object[]{"张三", 25});

execSQL不返回值,只要不抛出SQLException 异常,代表执行成功。bindArgs是占位符,它将Object内的结构分配给SQL语句中的问号,实际生成的语句

clike 复制代码
INSERT INTO users (name, age) VALUES ("张三", 25)

我们可以使用字符串拼接的方式,取消占位符的使用,将其设置NULL即可或者不传递。

事例

MyDB类

clike 复制代码
package com.zilong.dubao;

import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.widget.Toast;

public class MyDB extends SQLiteOpenHelper {
    public MyDB( String name, SQLiteDatabase.CursorFactory factory,
                int version){
        super(app.getContext(), name, factory, version);


    }
    @Override
    public void onCreate(SQLiteDatabase db) {
        Toast.makeText(app.getContext(),"数据库与表创建成功",Toast.LENGTH_SHORT).show();
        String dumaTabel="CREATE TABLE duma (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, dumaName text,dumaId text,bindDateTime INTEGER)";
        db.execSQL(dumaTabel);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}

MainActivity类源码

clike 复制代码
package com.zilong.dubao;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    private MyDB myDB=new MyDB("dubao.db",null,12);
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initBtn();
//        startService();
        ImageView qrCodeImageView = findViewById(R.id.qrCode);
        uuid u=new uuid();
        String dubaoId=u.getuuid();
        Log.d("uuid",dubaoId);
        Bitmap logoBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.logo);
        int foreground = Color.parseColor("#2196F3"); // 前景蓝
        int background = Color.WHITE; // 背景白
        Bitmap qrBitmap = QRCodeUtil.ShowQRCode(
                dubaoId, logoBitmap, 0.2f, foreground, background);
        qrCodeImageView.setImageBitmap(qrBitmap);
    }
    private void initBtn(){
        Button createDBBtn=findViewById(R.id.createDB);
        createDBBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                myDB.getWritableDatabase();

            }
        });
        Button insertBtn=findViewById(R.id.insertDB);
        insertBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SQLiteDatabase db =myDB.getWritableDatabase();
                String sql="";
                sql=String.format("INSERT INTO duma( \"dumaName\", \"dumaId\", \"bindDateTime\") VALUES ( '%s', '%s', '%d');","嘟妈","f1122aeb-f2b0-400d-9919-eddd2eaebaa2" ,System.currentTimeMillis());
                Log.d("mqtt",sql);
                db.execSQL(sql);

            }
        });
        Button updateBtn=findViewById(R.id.updateDB);
        updateBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SQLiteDatabase db =myDB.getWritableDatabase();
                String sql="";
                sql=String.format("UPDATE duma set dumaName=\"%s\" WHERE dumaId=\"%s\"","嘟妈2","f1122aeb-f2b0-400d-9919-eddd2eaebaa2" );
                Log.d("mqtt",sql);
                db.execSQL(sql);

            }
        });

        Button queryBtn=findViewById(R.id.queryDB);
        queryBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SQLiteDatabase db =myDB.getWritableDatabase();
                Cursor cursor = db.rawQuery("SELECT * FROM duma", null);
                if (cursor.moveToFirst()){
                    do{
                        @SuppressLint("Range") String dumaName=cursor.getString(cursor.getColumnIndex("dumaName"));
                        @SuppressLint("Range") String dumaId=cursor.getString(cursor.getColumnIndex("dumaId"));
                        @SuppressLint("Range") int bindDateTime=cursor.getInt(cursor.getColumnIndex("bindDateTime"));
                        Toast.makeText(MainActivity.this,dumaName,Toast.LENGTH_SHORT).show();

                    }while (cursor.moveToNext());
                }
                cursor.close();



            }

        });
        Button delBtn=findViewById(R.id.delDB);
        delBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SQLiteDatabase db =myDB.getWritableDatabase();
                String sql="";
                sql=String.format("DELETE FROM duma WHERE dumaId=\"%s\"","f1122aeb-f2b0-400d-9919-eddd2eaebaa2");
                Log.d("mqtt",sql);
                db.execSQL(sql);

            }
        });


    }

    private void startService(){
        Intent i = new Intent(this, MyService.class);
        startForegroundService(i);
    }


}

运行实例查看结果 点击创建数据库两次,但实际onCreate只调用一次创建。 分别操作

  • 插入数据-查询数据
  • 更新数据-查询数据
  • 删除数据-查询数据

SQLite 事务

在 Android SQLite 中,事务是一组数据库操作的逻辑单元,要么全部执行成功,要么全部失败回滚,确保数据的一致性和完整性。 事务的基本特性(ACID)

  • 原子性:事务中的所有操作要么全部成功,要么全部失败
  • 一致性:事务执行前后数据库保持完整状态
  • 隔离性:并发事务之间互不干扰
  • 持久性:事务提交后数据永久保存
clike 复制代码
package com.zilong.dubao;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    private MyDB myDB=new MyDB("dubao.db",null,12);
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initBtn();
    }
    private void initBtn(){
        Button rollupBtn=findViewById(R.id.rollupDB);
        rollupBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SQLiteDatabase db = myDB.getWritableDatabase();
                db.beginTransaction();
                try {
                    // 执行多个数据库操作
                    for (int i = 0; i < 3; i++) {
                        String sql="";
                        sql=String.format("INSERT INTO duma( \"dumaName\", \"dumaId\", \"bindDateTime\") VALUES ( '%s', '%s', '%d');","嘟妈"+i,"f1122aeb-f2b0-400d-9919-eddd2eaebaa2" ,System.currentTimeMillis());
                        db.execSQL(sql);
                        if (i==1){
                            throw  new Exception("失败");
                        }
                    }
                    db.setTransactionSuccessful();
                    db.close();


                } catch (Exception e) {
                    // 发生异常,自动回滚
                    e.printStackTrace();
                    db.endTransaction();
                    db.close();
                    Toast.makeText(MainActivity.this,"发生异常,自动回滚",Toast.LENGTH_SHORT).show();
                }

            }
        }); 
    }  
}

运行效果查看

相关推荐
martindelophy2 小时前
用自然语言剪视频:我们在 Timeline Studio 中实现了 ChatCut 对话剪辑
android·音视频
ao-weilai3 小时前
MySQL数据库:复合查询
android·数据库·mysql
三少爷的鞋16 小时前
AI 时代,我们都将成为通才型开发者:只懂 Android,已经不够了
android
Dovis(誓平步青云)20 小时前
家里设备越来越多,如何用一张空间地图控制灯光和温度![
android·java·前端·javascript·人工智能·电脑
晚风叙码21 小时前
MySQL 数据类型详解:从数值到字符串,一篇讲透
android·mysql·adb
传奇开心果编程1 天前
【Compose Multiplatform 跨端开发学与练】第3课 布局与组件
android·windows·学习·ui·ios·kotlin·composer
传奇开心果编程1 天前
【Compose Multiplatform 跨端开发学与练】第8课 资源管理与主题
android·windows·学习·ios·kotlin·web·composer
传奇开心果编程1 天前
【Compose Multiplatform 跨端开发学与练】第9课 测试与调试
android·学习·macos·ios·kotlin·web·composer
传奇开心果编程1 天前
【Compose Multiplatform 跨端开发学与练】第4课 导航与路由
android·windows·学习·ui·ios·kotlin·composer
传奇开心果编程1 天前
【Compose Multiplatform 跨端开发学与练】第6课 状态管理与架构
android·学习·ui·ios·架构·kotlin·composer