『Android』复杂数据的存储SQLite和Room框架

  • 🍁简介
  • 🌷创建数据库
  • 抽象方法
  • 实例方法
  • 构造方法
  • 🌺操作数据
  • 添加数据
  • 老师&学长博客
  • 🌳Room(官方第三方框架)
  • 简介
  • 使用
  • 创建数据库表实体类
  • Dao数据操作工具接口
  • Database数据库对象抽象类
  • MainActivity连接并调用数据库
  • 灵魂发问


注意:不是教程只是笔记,如有错误欢迎批评指正

🍁简介

常用的数据库 sqlserver oracle mysql

Android嵌入式数据库SQLite

SQLite数据库支持SQL语法和ACID事务,适用于存储大量的关系型数据

eg:qq的聊天列表

学习强国的新闻

Android 数据库 Realm Android 数据库存储框架_Android 数据库 Realm

🌷创建数据库

创建数据库需要使用到一个抽象类SQLiteOpenHelper

抽象方法

它有两个抽象方法:

onCreate():创建数据库

onUpgrade():升级数据库

Android 数据库 Realm Android 数据库存储框架_数据库_02

实例方法

getReadableDatabases()getWritableDatabases()用于创建或打开一个数据库,返回一个可对数据读写操作的对象,两者的区别是:当数据库不可写入时(如磁盘满了),getReadableDatabases()方法返回的对象将以只读的方式打开数据库,getWritableDatabases()方法则会出现异常

构造方法

有3个构造方法可供重写,其中第一个参数少,用第一个构造方法有4个参数:

参数

解释

参数一

context

参数二

数据库名

参数三

查询数据时返回一个自定义的cursor,一般为null

参数四

当前数据库的版本号,可用于对数据库进行升级操作

Android 数据库 Realm Android 数据库存储框架_Android 数据库 Realm_03

onCreate方法中,通过sqLiteDatabase.execSQL()方法可以执行建表语句,如下我通过sql语句定义了一个user表,id为主键

DBOpenHelper完整代码

public class DBOpenHelper extends SQLiteOpenHelper {
    //构造方法
    public DBOpenHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
    }

    //创建数据库的表
    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        //建表
        sqLiteDatabase.execSQL("create table user(" +
                "id integer " +
                "primary key autoincrement,username " +
                "varchar(20),password varchar(20)," +
                "age integer)");
    }

    //更新数据库的表
    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

    }
}

MainActivity中我们与数据库建立连接并打开数据库

Android 数据库 Realm Android 数据库存储框架_数据库_04

🌺操作数据

添加数据

然后我们在xml文件里添加几个按钮,通过按钮来对数据进行操作,添加数据有两种方式,

`sqLiteDatabase.execSQL("")`方法执行sql语句添加
通过`ContentValues`保存键值对添加
//方法二:
 //类似hashmap,以键值对保存数据  key->数据表列名  value->列的值
 ContentValues contentValues=new ContentValues();
 contentValues.put("username","test1234");
 contentValues.put("password","123456");
 contentValues.put("age",19);
 sqLiteDatabase.insert("user",null,contentValues);

Android 数据库 Realm Android 数据库存储框架_sqlite_05

App Inspection可以查看数据库的表结构

这种查看数据库表结构的方式必须要求虚拟机在API26及以上

Android 数据库 Realm Android 数据库存储框架_Android 数据库 Realm_06

数据库文件存放在/data/data/<package name>/databases/目录下

Android 数据库 Realm Android 数据库存储框架_数据库_07

老师&学长博客

这种传统的操作数据库的方法就记录这么多,老师和学长的博客都写的很详细啦


MainActivity中完整代码

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //创建好数据库,并与数据库之间建立连接
        DBOpenHelper dbOpenHelper=new DBOpenHelper(MainActivity.this,"test",null,1);
        //打开数据库,返回一个可对数据读写操作的对象
        SQLiteDatabase sqLiteDatabase=dbOpenHelper.getWritableDatabase();

        findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //方法一:直接执行数据库执行语句
                //sqLiteDatabase.execSQL("");
                //方法二:
                //类似hashmap,以键值对保存数据  key->数据表列名  value->列的值
                ContentValues contentValues=new ContentValues();
                contentValues.put("username","test1234");
                contentValues.put("password","123456");
                contentValues.put("age",19);
                sqLiteDatabase.insert("user",null,contentValues);
            }
        });
    }
}


🌳Room(官方第三方框架)

简介

使用 Room 将数据保存到本地数据库 | Android 开发者 | Android Developers (google.cn)

对数据库中的查询操作很是繁琐,为了更加专注Android内容的开发,官方对SQLliteOpenHelper再封装,简化了开发者对数据库中数据的操作

  • 针对 SQL 查询的编译时验证。
  • 可最大限度减少重复和容易出错的样板代码的方便注解。
  • 简化了数据库迁移路径。

使用

Room 包含三个主要组件:

  • 数据库表实体,用于表示应用的数据库中的表。
  • 数据访问对象 (DAO),提供您的应用可用于查询、更新、插入和删除数据库中的数据的方法。
  • 数据库类,用于保存数据库并作为应用持久性数据底层连接的主要访问点。

创建数据库表实体类

//使用 @Entity注解定义的类会被映射为数据库中的一张表。
//默认实体类的类名为表名,字段名为表名。当然我们也是可以修改的。
@Entity
public class User1 {
    //@PrimaryKey注解用来标注表的主键,
    //并且使用autoGenerate = true 来指定了主键自增长
    @PrimaryKey(autoGenerate = true)
    public int id;
    public String userName;
    public String passWord;
    int age;
}

Android 数据库 Realm Android 数据库存储框架_sqlite_08

Dao数据操作工具接口

Dao类是一个 interface,其中定义了一系列的操作数据库的方法。Room为我们的提供了相关的注解,有@Insert、@Delete、@Update 和 @Query。

//Dao结尾的类  里面是数据库增删改查的方法
@Dao//
public interface UserDao {
    //只需定义接口,无需实现

    //表示是增加数据
    @Insert
    void insertUser(User1 user1);

    //删除数据
    @Delete
    void deleteUser(User1 user1);

    //查询数据
    @Query("SELECT * FROM User1")
    List<User1> findALLUser();

    //精确匹配
    @Query("SELECT * FROM User1 where id=:userId")
    List<User1> findAllUserById(int userId);

    //模糊匹配
    @Query("SELECT * FROM User1 where userName like '%'||:name|| '%'")
    List<User1> findAllUserById(String name);
}

image-20220429203532613

Database数据库对象抽象类

这是一个抽象类,并不真正的实现对数据库的连接和数据操作,而是定义抽象方法,让MainActivity去实现

//建立数据库连接的抽象类
/*
1.创建
2.改造成抽象类
3.添加注解
4.定义获取数据库工具对象的抽象方法
 */
@Database(entities={User1.class},version=1,exportSchema=false)
public abstract class UserDaoDatabase extends RoomDatabase{
    public abstract UserDao getUserDao();
}
@Database(entities={User1.class},version=1,exportSchema=false)

这其中的前两个参数好理解,一个是映射的数据库实体类,一个是数据库的版本号;Schema是数据库的组织和结构,exportSchema指暴露数据库的组织架构到一个文件夹,这个文件夹通过room.schemaLocation指定。Schema记录了数据库的组织和结构,并带有版本信息,所以不适合在发布的app中的文件夹中,而是最好指定到版本控制系统中,默认为true打开状态。所以最好是false。

Android 数据库 Realm Android 数据库存储框架_Android 数据库 Realm_09

MainActivity连接并调用数据库

public class MainActivity extends AppCompatActivity {

    UserDao userDao;
    UserDaoDatabase userDaoDatabase;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

    //1.和数据库建立连接
    userDaoDatabase= Room.databaseBuilder(this,UserDaoDatabase.class,"Mytest")
            .allowMainThreadQueries()//允许在主线程调用
            .build();

    //2.返回的不是一个接口对象,返回的是一个接口的实现类  是运行期间动态生成的
    userDao=userDaoDatabase.getUserDao();

    //3.操作数据库
        //增加数据
    findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            User1 user1=new User1();
            user1.userName="starry";
            user1.age=20;
            user1.passWord="lx0411";
            userDao.insertUser(user1);//接口的方法是不能够调用?为什么这里可以调用
        }
    });

        //查询数据
    findViewById(R.id.button2).setOnClickListener(
        (view)->{
            List<User1> user1List=userDao.findAllUserById(1);
            for(User1 user1:user1List){
                Log.i("user1", "id: "+user1.id+" name: "+user1.userName);
            }

        }
    );

    	//删除数据
    findViewById(R.id.button3).setOnClickListener(
        (view)->{
            User1 user1=new User1();
            user1.id=2;
            userDao.deleteUser(user1);
        }
    );



    }
}

每点击一次添加数据,表中就会新增一条数据

Android 数据库 Realm Android 数据库存储框架_Android_10

点击删除数据,可以看到id=2的数据已被删除

Android 数据库 Realm Android 数据库存储框架_数据库_11

点击查询数据按钮,在日志打印台通过tag过滤日志可以看到,成功查询到id=1的记录

Android 数据库 Realm Android 数据库存储框架_android_12

灵魂发问

最后有一个疑问为什么insertUser()方法可以直接被调用呢?我们都知道接口本身是不能被实例化的,不能直接调用。那么为什么这一行代码不会报错

userDao.insertUser(user1);//接口的方法是不能够调用?为什么这里可以调用

这是因为这一行代码:返回的不是一个接口对象,返回的是一个接口的实现类 是运行期间动态生成的

//2.返回的不是一个接口对象,返回的是一个接口的实现类  是运行期间动态生成的
    userDao=userDaoDatabase.getUserDao();

如何查看这个动态生成的实现类呢?

Android 数据库 Realm Android 数据库存储框架_数据库_13


可以看到这个动态生成的实现类都实现了接口中的方法

Android 数据库 Realm Android 数据库存储框架_android_14