【Jetpack】Room 中的销毁重建策略 ( 创建临时数据库表 | 拷贝数据库表数据 | 删除旧表 | 临时数据库表重命名 )

news2024/10/7 5:18:55

文章目录

  • 一、销毁 和 重建策略
  • 二、销毁 和 重建策略 核心要点
    • 1、创建 Migration 迁移类 - 重点
    • 2、配置 Migration 迁移类
    • 3、修改数据库版本号
    • 4、修改实体类数据类型
  • 三、完整代码示例
    • 1、数据库版本 3 代码示例
      • RoomDatabase 数据库类完整代码
      • Student 实体类完整代码
      • 执行结果
    • 2、数据库版本 4 代码示例
      • RoomDatabase 数据库类完整代码
      • Student 实体类代码示例
      • 执行结果





一、销毁 和 重建策略



在 Android 中使用 Room 操作 SQLite 数据库 , 如果 SQLite 数据库表 修改比较繁琐 ,

如 : 涉及到 修改 数据库表字段的数据类型 , 需要逐个修改数据库值 ;

该环境下 使用 销毁 和 重建策略 是 最佳的方案 ;


销毁 和 重建策略 执行步骤 : 以 Table 表为例 , 要对 Table 表中的数据进行繁琐的操作 ;

  • 首先 , 创建一张 符合 新数据库表结构 的 临时数据库表 Temp_Table 表 ;
  • 然后 , 将 旧数据库表 Table 表中的数据 拷贝到 临时数据库表 Temp_Table 表中 , 如果需要修改 , 也在该步骤中进行修改 ;
  • 再后 , 删除旧的数据库表 Table 表 ;
  • 最后 , 将 临时数据库表 Temp_Table 表 重命名为 Table 表 ;




二、销毁 和 重建策略 核心要点




1、创建 Migration 迁移类 - 重点


在本篇博客中 , 在之前的博客

  • 【Jetpack】Room + ViewModel + LiveData 综合使用 ( 核心要点说明 | 组合方式 | 代码示例 )
  • 【Jetpack】使用 Room 中的 Migration 升级数据库 ( 修改 Entity 实体类 - 更改数据模型 | 创建 Migration 迁移类 | 修改数据库版本 | 代码示例 )

基础上 , 升级数据库版本 4 ;

数据库 版本 2 和 3 分别在 数据库 版本 1 的基础上新增了一个字段 ;

这里要升级的数据库版本 4 , 要 在 数据库版本 3 的基础上 , 将 integer 类型的字段 sex 的 数据类型 修改为 text 类型 ,

这就需要将 整个数据库表中的数据的 指定字段 需要重新赋值 ;

这就需要 使用 销毁重建 策略 ;


销毁 和 重建策略 执行步骤 :

  • 首先 , 创建一张 符合 新数据库表结构 的 临时数据库表;
                // 创新临时数据库
                database.execSQL(
                    "CREATE TABLE temp_student (" +
                            "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," +
                            "name TEXT," +
                            "age INTEGER NOT NULL," +
                            "sex TEXT DEFAULT 'M'," +
                            "degree INTEGER NOT NULL DEFAULT 1)"
                )
  • 然后 , 将 旧数据库表 中的数据 拷贝到 临时数据库表 中 , 如果需要修改 , 也在该步骤中进行修改 ;
                // 拷贝数据
                database.execSQL(
                    "INSERT INTO temp_student (name,age,degree)" +
                            "SELECT name,age,degree FROM student"
                )
  • 再后 , 删除旧的数据库表 ;
                // 删除原始表
                database.execSQL("DROP TABLE student")
  • 最后 , 将 临时数据库表 重命名为 原来的表名 ;
                // 将临时表命令为原表表明
                database.execSQL("ALTER TABLE temp_student RENAME TO student")

上述的 四个步骤 , 都在 Migration 的 public void migrate(@NonNull SupportSQLiteDatabase database) 函数中完成 , 每个步骤分别对应一个 SQL 语句 ;

最终定义的 Migration 为 :

        /**
         * 数据库版本 3 升级到 版本 4 的迁移类实例对象
         * 销毁重建策略
         */
        val MIGRATION_3_4: Migration = object : Migration(3, 4) {
            override fun migrate(database: SupportSQLiteDatabase) {
                // 创新临时数据库
                database.execSQL(
                    "CREATE TABLE temp_student (" +
                            "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," +
                            "name TEXT," +
                            "age INTEGER NOT NULL," +
                            "sex TEXT DEFAULT 'M'," +
                            "degree INTEGER NOT NULL DEFAULT 1)"
                )

                // 拷贝数据
                database.execSQL(
                    "INSERT INTO temp_student (name,age,degree)" +
                            "SELECT name,age,degree FROM student"
                )

                // 删除原始表
                database.execSQL("DROP TABLE student")

                // 将临时表命令为原表表明
                database.execSQL("ALTER TABLE temp_student RENAME TO student")
            }
        }

2、配置 Migration 迁移类


创建 RoomDatabase.Builder 时 , 调用 RoomDatabase.Builder#addMigrations , 设置上述创建的 销毁重建策略的 Migration 迁移类 ;

        fun inst(context: Context): StudentDatabase {
            if (!::instance.isInitialized) {
                synchronized(StudentDatabase::class) {
                    // 创建数据库
                    instance = Room.databaseBuilder(
                        context.applicationContext,
                        StudentDatabase::class.java,
                        "student_database.db")
                        .addMigrations(MIGRATION_1_2)
                        .addMigrations(MIGRATION_2_3)
                        .addMigrations(MIGRATION_3_4)
                        .fallbackToDestructiveMigration()
                        .allowMainThreadQueries() // Room 原则上不允许在主线程操作数据库
                                                  // 如果要在主线程操作数据库需要调用该函数
                        .build()
                }
            }
            return instance;
        }

3、修改数据库版本号


在 RoomDatabase 类的 @Database 注解上的 version 数据库版本号参数设置为 4 ;

@Database(entities = [Student::class], version = 4, exportSchema = true)
abstract class StudentDatabase: RoomDatabase() {

4、修改实体类数据类型


将 Entity 实体类 Student 类中的 sex 字段 由

    /**
     * 性别字段
     * 数据库表中的列名为 sex
     * 数据库表中的类型为 INTEGER 文本类型
     */
    @ColumnInfo(name = "sex", typeAffinity = ColumnInfo.INTEGER)
    var sex: Int = 0

修改为 :

    /**
     * 性别字段
     * 数据库表中的列名为 sex
     * 数据库表中的类型为 TEXT 文本类型
     */
    @ColumnInfo(name = "sex", typeAffinity = ColumnInfo.TEXT)
    var sex: String = "M"




三、完整代码示例



代码地址 : https://github.com/han1202012/Room_ViewModel_LiveData


1、数据库版本 3 代码示例


RoomDatabase 数据库类完整代码

package kim.hsl.rvl

import android.content.Context
import android.util.Log
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase

@Database(entities = [Student::class], version = 3, exportSchema = true)
abstract class StudentDatabase: RoomDatabase() {
    /**
     * 获取 数据库访问 对象
     * 这是必须要实现的函数
     */
    abstract fun studentDao(): StudentDao

    companion object {
        lateinit var instance: StudentDatabase

        /**
         * 数据库版本 1 升级到 版本 2 的迁移类实例对象
         */
        val MIGRATION_1_2: Migration = object : Migration(1, 2) {
            override fun migrate(database: SupportSQLiteDatabase) {
                Log.i("Room_StudentDatabase", "数据库版本 1 升级到 版本 2")
                database.execSQL("alter table student add column sex integer not null default 1")
            }
        }

        /**
         * 数据库版本 2 升级到 版本 3 的迁移类实例对象
         */
        val MIGRATION_2_3: Migration = object : Migration(2, 3) {
            override fun migrate(database: SupportSQLiteDatabase) {
                Log.i("Room_StudentDatabase", "数据库版本 2 升级到 版本 3")
                database.execSQL("alter table student add column degree integer not null default 1")
            }
        }

        fun inst(context: Context): StudentDatabase {
            if (!::instance.isInitialized) {
                synchronized(StudentDatabase::class) {
                    // 创建数据库
                    instance = Room.databaseBuilder(
                        context.applicationContext,
                        StudentDatabase::class.java,
                        "student_database.db")
                        .addMigrations(MIGRATION_1_2)
                        .addMigrations(MIGRATION_2_3)
                        .fallbackToDestructiveMigration()
                        .allowMainThreadQueries() // Room 原则上不允许在主线程操作数据库
                                                  // 如果要在主线程操作数据库需要调用该函数
                        .build()
                }
            }
            return instance;
        }
    }
}

Student 实体类完整代码

package kim.hsl.rvl

import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Ignore
import androidx.room.PrimaryKey

/**
 * 定义数据库表 Entity 实体 / 同时定义数据库表 和 对鹰的实体类
 * 设置该数据类对应数据库中的一张数据表, 表名为 student
 * 该数据库表中的数据对应一个 Student 类实例对象
 */
@Entity(tableName = "student")
class Student {
    /**
     * @PrimaryKey 设置主键 autoGenerate 为自增
     * @ColumnInfo name 设置列名称 / typeAffinity 设置列类型
     */
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "id", typeAffinity = ColumnInfo.INTEGER)
    var id: Int = 0

    /**
     * 姓名字段
     * 数据库表中的列名为 name
     * 数据库表中的类型为 TEXT 文本类型
     */
    @ColumnInfo(name = "name", typeAffinity = ColumnInfo.TEXT)
    lateinit var name: String

    /**
     * 年龄字段
     * 数据库表中的列名为 age
     * 数据库表中的类型为 INTEGER 文本类型
     */
    @ColumnInfo(name = "age", typeAffinity = ColumnInfo.INTEGER)
    var age: Int = 0

    /**
     * 性别字段
     * 数据库表中的列名为 sex
     * 数据库表中的类型为 INTEGER 文本类型
     */
    @ColumnInfo(name = "sex", typeAffinity = ColumnInfo.INTEGER)
    var sex: Int = 0

    /**
     * degree字段
     * 数据库表中的列名为 sex
     * 数据库表中的类型为 INTEGER 文本类型
     */
    @ColumnInfo(name = "degree", typeAffinity = ColumnInfo.INTEGER)
    var degree: Int = 0

    /**
     * 有些属性用于做业务逻辑
     * 不需要插入到数据库中
     * 使用 @Ignore 注解修饰该属性字段
     */
    @Ignore
    lateinit var studentInfo: String

    /**
     * 默认的构造方法给 Room 框架使用
     */
    constructor(id: Int, name: String, age: Int) {
        this.id = id
        this.name = name
        this.age = age
    }

    /**
     * 使用 @Ignore 标签标注后
     * Room 就不会使用该构造方法了
     * 这个构造方法是给开发者使用的
     */
    @Ignore
    constructor(name: String, age: Int) {
        this.name = name
        this.age = age
    }

    /**
     * 使用 @Ignore 标签标注后
     * Room 就不会使用该构造方法了
     * 这个构造方法是给开发者使用的
     */
    @Ignore
    constructor(id: Int) {
        this.id = id
    }

    override fun toString(): String {
        return "Student(id=$id, name='$name', age=$age)"
    }
}

执行结果

先执行数据库版本为 3 的应用 , 输出结果如下 :

2023-06-05 19:17:12.251 I/Room_MainActivity: Observer#onChanged 回调, List<Student>: []
2023-06-05 19:17:12.532 I/Room_MainActivity: 插入数据 S1 : Student(id=0, name='Tom', age=18)
2023-06-05 19:17:12.536 I/Room_MainActivity: Observer#onChanged 回调, List<Student>: [Student(id=1, name='Tom', age=18)]
2023-06-05 19:17:13.036 I/Room_MainActivity: 插入数据 S2 : Student(id=0, name='Jerry', age=16)
2023-06-05 19:17:13.038 I/Room_MainActivity: Observer#onChanged 回调, List<Student>: [Student(id=1, name='Tom', age=18), Student(id=2, name='Jerry', age=16)]
2023-06-05 19:17:13.538 I/Room_MainActivity: 更新数据 S2 : Student(id=2, name='Jack', age=60)
2023-06-05 19:17:13.540 I/Room_MainActivity: Observer#onChanged 回调, List<Student>: [Student(id=1, name='Tom', age=18), Student(id=2, name='Jack', age=60)]
2023-06-05 19:17:14.051 I/Room_MainActivity: 删除数据 id = 1
2023-06-05 19:17:14.060 I/Room_MainActivity: Observer#onChanged 回调, List<Student>: [Student(id=2, name='Jack', age=60)]
2023-06-05 19:17:14.553 I/Room_MainActivity: 主动查询 : LiveData : androidx.room.RoomTrackingLiveData@8726677 , 实际数据 : null
2023-06-05 19:17:14.554 I/Room_MainActivity: 主动查询2 : [Student(id=2, name='Jack', age=60)]

在这里插入图片描述


2、数据库版本 4 代码示例


将数据库版本修改为 4 , 然后执行上述 销毁重建策略 修改 ;

主要是创建了 数据库版本 3 升级到 版本 4 的迁移类实例对象 , 该 Migration 类

RoomDatabase 数据库类完整代码

package kim.hsl.rvl

import android.content.Context
import android.util.Log
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase

@Database(entities = [Student::class], version = 4, exportSchema = true)
abstract class StudentDatabase: RoomDatabase() {
    /**
     * 获取 数据库访问 对象
     * 这是必须要实现的函数
     */
    abstract fun studentDao(): StudentDao

    companion object {
        lateinit var instance: StudentDatabase

        /**
         * 数据库版本 1 升级到 版本 2 的迁移类实例对象
         */
        val MIGRATION_1_2: Migration = object : Migration(1, 2) {
            override fun migrate(database: SupportSQLiteDatabase) {
                Log.i("Room_StudentDatabase", "数据库版本 1 升级到 版本 2")
                database.execSQL("alter table student add column sex integer not null default 1")
            }
        }

        /**
         * 数据库版本 2 升级到 版本 3 的迁移类实例对象
         */
        val MIGRATION_2_3: Migration = object : Migration(2, 3) {
            override fun migrate(database: SupportSQLiteDatabase) {
                Log.i("Room_StudentDatabase", "数据库版本 2 升级到 版本 3")
                database.execSQL("alter table student add column degree integer not null default 1")
            }
        }

        /**
         * 数据库版本 3 升级到 版本 4 的迁移类实例对象
         * 销毁重建策略
         */
        val MIGRATION_3_4: Migration = object : Migration(3, 4) {
            override fun migrate(database: SupportSQLiteDatabase) {
                Log.i("Room_StudentDatabase", "数据库版本 3 升级到 版本 4")
                // 创新临时数据库
                database.execSQL(
                    "CREATE TABLE temp_student (" +
                            "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," +
                            "name TEXT," +
                            "age INTEGER NOT NULL," +
                            "sex TEXT NOT NULL DEFAULT 'M'," +
                            "degree INTEGER NOT NULL DEFAULT 1)"
                )

                // 拷贝数据
                database.execSQL(
                    "INSERT INTO temp_student (name, age, degree)" +
                            "SELECT name, age, degree FROM student"
                )

                // 删除原始表
                database.execSQL("DROP TABLE student")

                // 将临时表命令为原表表明
                database.execSQL("ALTER TABLE temp_student RENAME TO student")
            }
        }

        fun inst(context: Context): StudentDatabase {
            if (!::instance.isInitialized) {
                synchronized(StudentDatabase::class) {
                    // 创建数据库
                    instance = Room.databaseBuilder(
                        context.applicationContext,
                        StudentDatabase::class.java,
                        "student_database.db")
                        .addMigrations(MIGRATION_1_2)
                        .addMigrations(MIGRATION_2_3)
                        .addMigrations(MIGRATION_3_4)
                        .fallbackToDestructiveMigration()
                        .allowMainThreadQueries() // Room 原则上不允许在主线程操作数据库
                                                  // 如果要在主线程操作数据库需要调用该函数
                        .build()
                }
            }
            return instance;
        }
    }
}

Student 实体类代码示例

package kim.hsl.rvl

import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Ignore
import androidx.room.PrimaryKey

/**
 * 定义数据库表 Entity 实体 / 同时定义数据库表 和 对鹰的实体类
 * 设置该数据类对应数据库中的一张数据表, 表名为 student
 * 该数据库表中的数据对应一个 Student 类实例对象
 */
@Entity(tableName = "student")
class Student {
    /**
     * @PrimaryKey 设置主键 autoGenerate 为自增
     * @ColumnInfo name 设置列名称 / typeAffinity 设置列类型
     */
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "id", typeAffinity = ColumnInfo.INTEGER)
    var id: Int = 0

    /**
     * 姓名字段
     * 数据库表中的列名为 name
     * 数据库表中的类型为 TEXT 文本类型
     */
    @ColumnInfo(name = "name", typeAffinity = ColumnInfo.TEXT)
    lateinit var name: String

    /**
     * 年龄字段
     * 数据库表中的列名为 age
     * 数据库表中的类型为 INTEGER 文本类型
     */
    @ColumnInfo(name = "age", typeAffinity = ColumnInfo.INTEGER)
    var age: Int = 0

    /**
     * 性别字段
     * 数据库表中的列名为 sex
     * 数据库表中的类型为 TEXT 文本类型
     */
    @ColumnInfo(name = "sex", typeAffinity = ColumnInfo.TEXT)
    var sex: String = "M"

    /**
     * 性别字段
     * 数据库表中的列名为 sex
     * 数据库表中的类型为 INTEGER 文本类型
     */
    /*@ColumnInfo(name = "sex", typeAffinity = ColumnInfo.INTEGER)
    var sex: Int = 0*/

    /**
     * degree字段
     * 数据库表中的列名为 sex
     * 数据库表中的类型为 INTEGER 文本类型
     */
    @ColumnInfo(name = "degree", typeAffinity = ColumnInfo.INTEGER)
    var degree: Int = 0

    /**
     * 有些属性用于做业务逻辑
     * 不需要插入到数据库中
     * 使用 @Ignore 注解修饰该属性字段
     */
    @Ignore
    lateinit var studentInfo: String

    /**
     * 默认的构造方法给 Room 框架使用
     */
    constructor(id: Int, name: String, age: Int) {
        this.id = id
        this.name = name
        this.age = age
    }

    /**
     * 使用 @Ignore 标签标注后
     * Room 就不会使用该构造方法了
     * 这个构造方法是给开发者使用的
     */
    @Ignore
    constructor(name: String, age: Int) {
        this.name = name
        this.age = age
    }

    /**
     * 使用 @Ignore 标签标注后
     * Room 就不会使用该构造方法了
     * 这个构造方法是给开发者使用的
     */
    @Ignore
    constructor(id: Int) {
        this.id = id
    }

    override fun toString(): String {
        return "Student(id=$id, name='$name', age=$age)"
    }
}

执行结果

执行结果如下 :

2023-06-05 19:18:58.864 I/Room_StudentDatabase: 数据库版本 3 升级到 版本 4
2023-06-05 19:18:58.909 I/Room_MainActivity: Observer#onChanged 回调, List<Student>: [Student(id=1, name='Jack', age=60)]
2023-06-05 19:18:59.346 I/Room_MainActivity: 插入数据 S1 : Student(id=0, name='Tom', age=18)
2023-06-05 19:18:59.351 I/Room_MainActivity: Observer#onChanged 回调, List<Student>: [Student(id=1, name='Jack', age=60), Student(id=2, name='Tom', age=18)]
2023-06-05 19:18:59.853 I/Room_MainActivity: 插入数据 S2 : Student(id=0, name='Jerry', age=16)
2023-06-05 19:18:59.855 I/Room_MainActivity: Observer#onChanged 回调, List<Student>: [Student(id=1, name='Jack', age=60), Student(id=2, name='Tom', age=18), Student(id=3, name='Jerry', age=16)]
2023-06-05 19:19:00.362 I/Room_MainActivity: 更新数据 S2 : Student(id=2, name='Jack', age=60)
2023-06-05 19:19:00.371 I/Room_MainActivity: Observer#onChanged 回调, List<Student>: [Student(id=1, name='Jack', age=60), Student(id=2, name='Jack', age=60), Student(id=3, name='Jerry', age=16)]
2023-06-05 19:19:00.875 I/Room_MainActivity: 删除数据 id = 1
2023-06-05 19:19:00.877 I/Room_MainActivity: Observer#onChanged 回调, List<Student>: [Student(id=2, name='Jack', age=60), Student(id=3, name='Jerry', age=16)]
2023-06-05 19:19:01.377 I/Room_MainActivity: 主动查询 : LiveData : androidx.room.RoomTrackingLiveData@b957950 , 实际数据 : null
2023-06-05 19:19:01.378 I/Room_MainActivity: 主动查询2 : [Student(id=2, name='Jack', age=60), Student(id=3, name='Jerry', age=16)]

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/632824.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

chatgpt赋能python:Python编程爱好者必备:如何参加线上比赛

Python编程爱好者必备&#xff1a;如何参加线上比赛 作为一名拥有10年Python编程经验的工程师&#xff0c;我非常喜欢参加线上编程比赛。在这些比赛中&#xff0c;我可以与全球的编程爱好者一起竞技&#xff0c;展现自己编程的优势和挑战自己的能力。在这篇SEO文章中&#xff…

数论与组合数学 期末总结(完结)

数论与组合数学 自然数的基本性质整除最大公约数&#xff08;GCD&#xff09;辗转相除法欧几里得算法 互质 Coprime素数算数基本定理 同余欧拉定理欧拉函数费马小定理威尔逊定理 逆元求逆&#xff1a;欧几里得扩展算法 线性同余方程组 ( a x b m o d m ) (axb\ mod\ m) (axb m…

2023数维杯A题水体污染对流弥散吸附完整论文及所有数值计算模拟代码

大家好呀&#xff0c;从昨天发布赛题一直到现在&#xff0c;总算完成了数维杯A题完整的成品论文。 A题论文37页&#xff0c;一些修改说明提醒7页&#xff0c;正文22页&#xff0c;附录8页 本论文可以保证原创&#xff0c;保证高质量。绝不是随便引用一大堆模型和代码复制粘贴…

chatgpt赋能python:Python如何快速取出所有元素?

Python如何快速取出所有元素&#xff1f; 随着Python编程的流行&#xff0c;我们常常需要处理列表、元组和字典等数据结构。在这些数据结构中&#xff0c;最常见的操作是获取所有元素。本文将介绍如何使用Python来快速取出所有元素。 获取列表中所有元素 在Python中&#xf…

简易操作系统:使用Python 做的图形界面 C 做的内核

目录 实验要求 一、文件管理和用户接口 ⑴文件的逻辑结构 ⑵磁盘模拟 ⑶目录结构 ⑷磁盘分配 ⑸磁盘空闲存储空间管理 ⑹用户接口 ⑺屏幕显示 代码部分 python调用c的方法&#xff1a; ​编辑 c语言部分&#xff0c;文件名 Operating_System_C.c python语言部分 运…

2023认证杯数学建模第二阶段C题完整原创论文讲解

大家好呀&#xff0c;从昨天发布赛题一直到现在&#xff0c;总算完成了认证杯二阶段C题完整的成品论文。 本论文可以保证原创&#xff0c;保证高质量。绝不是随便引用一大堆模型和代码复制粘贴进来完全没有应用糊弄人的垃圾半成品论文。 C第二阶段完整论文共64页&#xff0c;一…

越跌越买!192亿大举抄底

虽然本周主流大盘指数表现乏力&#xff0c;但股票ETF市场再现资金逢低“扫货”。 截至6月9日收盘&#xff0c;全市场736只股票ETF&#xff08;统计股票ETF和跨境ETF&#xff09;总份额增长196亿份&#xff0c;净流入资金约192亿元&#xff0c;再现“越跌越买”的趋势。 其中&…

理解原子操作与CAS锁

理解原子操作与CAS锁实现 线程间内存访问同步的问题理解cpu的存储体系结构cpu存储架构cache line了解一下写回策略 write-back多线程运行在cpu的多核之中&#xff0c;数据怎么共享&#xff0c;怎么同步&#xff1f;通过事件串行化通过MESI 原子操作CAS锁 线程间内存访问同步的问…

chatgpt赋能python:如何去除Python列表中的中括号

如何去除Python列表中的中括号 在Python中&#xff0c;列表是一个非常重要的数据类型。它可以存储多个不同类型的元素&#xff0c;并且可以动态地增加或删除元素。但是&#xff0c;有时候我们需要将列表中的元素取出来&#xff0c;而不想要中括号。本文将介绍两种不同的方法来…

.net framework 命令行项目使用 sqlite,DbContext

文章目录 背景描述实际操作环境安装Nuget包安装三者之间的关系ORM解释 项目从零开始创建过程新建项目安装nugetDB first和Code first新建文件注意&#xff0c;DbContext命名运行测试基础增删改查和原生sql操作查增&#xff0c;删&#xff0c;改增改删 sql语句执行sql查询sql执行…

QFIELD在遥感数据处理中的应用

概述 从卫星图像生成的土地覆盖绘图需要地面实况数据&#xff0c;以便“训练”分类算法&#xff0c;并计算最终地图的准确性。地面实况数据由具有准确位置的数据点和来自已知土地覆盖类型的预定义列表的标签组成。本教程将指导用户完成斐济苏瓦训练区的地面实况数据收集。 收…

chatgpt赋能python:Python反向画圆的方法

Python反向画圆的方法 介绍 Python是一种高级编程语言&#xff0c;在数据科学、机器学习、Web开发等领域具有广泛的应用。其中&#xff0c;Python的图形绘制能力也颇为强大&#xff0c;可以利用Python编写出各种图形和动画效果。本文将介绍Python如何反向画圆&#xff0c;通过…

chatgpt赋能python:Python如何去除空行?

Python如何去除空行&#xff1f; 在Python编程中&#xff0c;经常会遇到需要去除文本文件或字符串中的空行的情况。空行通常是在文件或字符串中不希望存在的&#xff0c;因为它们可能会影响代码的可读性和执行效率。但是&#xff0c;如何才能在Python中高效地去除空行呢&#…

CSS布局模式之Flex布局Grid布局

文章目录 1. 简介1.1 什么是CSS布局&#xff1f;1.2 为什么使用CSS布局&#xff1f; 2. Flex布局2.1 什么是Flex布局&#xff1f;2.2 Flex容器和Flex项目2.3 Flex容器的属性2.3.1 flex-direction2.3.2 justify-content2.3.3 align-items2.3.4 align-content 2.4 Flex项目的属性…

计算机视觉-目标检测(一):从 R-CNN 到 Faster R-CNN

文章目录 1. 概要2. 区域卷积卷积神经网络R-CNN2.1 模型结构2.2 Selective Search2.3 warp2.4 R-CNN训练2.5 R-CNN推理2.6 R-CNN性能评价2.7 R-CNN的缺点 3. SPP-Net3.1 SPP-Net对RCNN的改进3.2 SPP-Net网络结构3.3 SPP-Net训练过程3.4 SPP-Net的问题 4. Fast R-CNN4.1 Fast R-…

浅析设计模式 -- 责任链模式

目录 前言 概述 基本概念 ▐ 结构 ▐ 使用 使用示例 ▐ 代码实现​​​​​​​ ▐ 结果输出 ▐ UML图 扩展 源码赏析 优缺点及适用场景 ▐ 优点 ▐ 缺点 ▐ 适用场景 前言 我们在进行软件开发时要想实现可维护、可扩展&#xff0c;就需要尽量复用代码&…

【数据结构与算法】深入浅出:单链表的实现和应用

&#x1f331;博客主页&#xff1a;青竹雾色间. &#x1f618;博客制作不易欢迎各位&#x1f44d;点赞⭐收藏➕关注 ✨人生如寄&#xff0c;多忧何为 ✨ 目录 前言 单链表的基本概念 节点 头节点 尾节点 单链表的基本操作 创建单链表 头插法&#xff1a; 尾插法&#…

Shell脚本学习记录(常见指令)

Shell echo命令 Shell 的 echo 指令与 PHP 的 echo 指令类似&#xff0c;都是用于字符串的输出。命令格式&#xff1a; echo string 1.显示普通字符串: echo "It is a test" //双引号省略效果相同 2.显示转义字符 echo "\"It is a test\"" …

chatgpt赋能python:Python取出字典中键名对应的值

Python取出字典中键名对应的值 作为一个有10年Python编程经验的工程师&#xff0c;我经常遇到需要从字典中取出键名对应的值的情况。在这篇文章中&#xff0c;我将介绍Python中几种不同的方法来执行这个任务&#xff0c;并提供有关每个方法的优缺点的评估。让我们开始吧&#…

chatgpt赋能python:Python怎么取余数?

Python怎么取余数&#xff1f; 在Python中&#xff0c;我们经常需要进行数学运算&#xff0c;而其中计算余数也是经常用到的。虽然计算余数的方法似乎很简单&#xff0c;但是在不同的编程语言中有些微小的差异。本文将介绍在Python中如何高效地计算余数&#xff0c;以及一些相…