探索安卓内容提供者:构建、访问和管理数据【复习】

文章目录

  • 一 ContentProvider
    • 1.1 数据模型- **ContentProvider 使用基于数据库模型的简单表格来提供需要共享的数据**,在该表格中,每一表示一条记录,而每一列代表特定类型和含义的数据,并且其中每一条数据记录都包含一个名为“_ID”的字段类标识每条数据。
    • 1.2 Uri(统一资源标识符)
    • 1.3 创建内容提供者
    • 1.4 清单文件
    • 1.5 访问其他程序的数据
      • 1.5.1 访问提供者【了解】
      • 1.5.2 通过ContentProvider查询其他程序数据
      • 1.5.3 query方法
      • 1.5.4 多学一招:UriMatcher类【了解】
  • 二 ContentObserver
    • 2.1 创建ContentObserver
    • 2.2 补充:注册ContetnObserver的时机
  • 三 题目总结

一 ContentProvider

  • 内容提供者(ContentProvider)是Android系统四大组件之一,它是不同应用程序之间进行数据共享的标准API,通过ContentResolver类可以访问ContentProvider中共享的数据。
  • ContentProvider的工作原理如下:
    在这里插入图片描述
    • A程序使用ContetntProvider暴露数据,才能被其他程序操作。B程序通过ContetnResolver操作A程序暴露出来的数据,A程序将操作的结果返回给ContentResoler,然后ContetnResolver再将操作的结果返回给B程序。

1.1 数据模型- ContentProvider 使用基于数据库模型的简单表格来提供需要共享的数据,在该表格中,每一表示一条记录,而每一列代表特定类型和含义的数据,并且其中每一条数据记录都包含一个名为“_ID”的字段类标识每条数据。

在这里插入图片描述

1.2 Uri(统一资源标识符)

  • 统一资源标识符(Uniform Resource Identifier,或URI)是一个用于标识某一资源名称的字符串。 该标识允许用户对任何(包括本地和互联网)的资源通过特定的协议进行交互操作。
  • ContentResolver提供一系列增删改查的方法对数据进行操作,并且这些方法以Uri的形式对外提供数据。
  • Uri为内容提供者中的数据建立了唯一标识符。它主要由三部分组成,scheme、authorities和path
    在这里插入图片描述

1.3 创建内容提供者

内容提供者创建步骤:

  1. 在程序包名处右击选择【New】->【Other】->【Content Provider】选项
  2. 输入内容提供者的Class Name(类名称)和URI Authorities(唯一标识,通常使用包名)
  3. 点击【Finish】按钮创建完成
private class MyObserver extends ContentObserver{
        public MyObserver(Handler handler) {
            super(handler);
        }
        public void onChange(boolean selfChange) {
            super.onChange(selfChange);
          }
        //还需要重写增删改查的方法
        //...
    }

1.4 清单文件

  • 内容提供者创建完成后,Android Studio会自动在AndroidManifest.xml中对内容提供者进行注册。
    <application ......>
        <provider
            android:name=".MyContentProvider"
            android:authorities="cn.itcast.mycontentprovider"
            android:enabled="true"
            android:exported="true" >
       </provider>
    </application>
  • provider中的android:name代表是继承于ContentProvider类的的全路径名称。
  • android:authorities:标识MyContentProvider提供的数据,该值可以是一个或者多个URI authority,authorities之间用分号隔开。
  • android:enabled:标识MyContentProvider提供的数据能否被系统实例化
  • android:exported:用于指示该服务是否能被其他程序应用组件调用或跟他交互; 取值为(true | false),如果设置成true,则能够被调用或交互,否则不能;设置为false时,只有同一个应用程序的组件或带有相同用户ID的应用程序才能启动或绑定该服务。

1.5 访问其他程序的数据

  • 在不同的应用程序之间交换数据时,应用程序会通过ContentProvider暴露自身数据,便通过ContentResolver对程序暴露的数据进行操作,因此 CntentProvider充当一个中介的角色。由于在使用ContentProvider暴露数据时,提供了相应的 Uri,因此在访问现有的CntentProvider时,要指定相应的 Uri,然后再通过ContentResolver对象来实现对数据的操作。

1.5.1 访问提供者【了解】

  • 从Uri访问 ContentProvider 的常用模式是使用 CursorLoader 在后台运行异步查询。UI中的 Activity 或 Fragment 会调用查询的 CursorLoader,其转而使用 ContentResolver 获取 ContentProvider。如此一来,用户便可在查询运行时继续使用UI。
  • ContentResolver对象在客户 app的进程中,ContentProvider对象在app中,它们之间自动处理IPC。ContentProvider也是数据存储同数据的外在表现的一个抽象层。
    在这里插入图片描述
  • 注意:为了存取provider,app通常在它的manifest文件中请求特定的权限。
  • 例如,为了从User Dictionary Provider中得到一个单词表,你需要调用ContentResolver.query()。query()方法实际调用User Dictionary Provider中的ContentProvider.query(),如下:
// Queries the user dictionary and returns results
mCursor = getContentResolver().query(
    UserDictionary.Words.CONTENT_URI,   // The content URI of the words table
    mProjection,                        // The columns to return for each row
    mSelectionClause                    // Selection criteria
    mSelectionArgs,                     // Selection criteria
    mSortOrder);                        // The sort order for the returned rows
  • 下表显示了query的参数同SQL SELECT语句的对应关系:
    在这里插入图片描述

1.5.2 通过ContentProvider查询其他程序数据

  • 步骤:
    1. 通过parse()方法解析Uri
    2. 通过query()方法查询数据
    3. 通过while()遍历查询到的数据
	//获取相应操作的Uri,Uri.parse()方法是将字符串转化成Uri对象。
    Uri uri = Uri.parse("content://cn.itcast.mycontentprovider/person"); 
    //获取ContentResolver对象
    ContentResolver resolver = context.getContentResolver();
    //通过ContentResolver对象查询数据
    Cursor cursor = resolver.query(Uri uri, String[] projection, String selection,
                                     String[] selectionArgs, String sortOrder);
    //通过while()循环将Cursor对象中的数据遍历出来
    while (cursor.moveToNext()) {
        String address = cursor.getString(0); 
        long date = cursor.getLong(1);
        int type = cursor.getInt(2);
   }
    cursor.close();

1.5.3 query方法

ContentResolver的query方法的函数接口如下:

public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder, CancellationSignal cancellationSignal)

参数说明:

  • uri:要查询的数据的地址。
  • projection:要查询的列,即需要返回的数据的字段。
  • selection:查询条件,即需要满足的约束条件。
  • selectionArgs:查询条件的参数,用于替换selection中的占位符。
  • sortOrder:查询结果的排序方式。
  • cancellationSignal:用于取消查询的信号。

返回值:

  • Cursor:查询结果的游标对象。

注意事项:

  • 如果查询不需要使用selection和selectionArgs,可以将它们设置为null。
  • 如果不需要排序,可以将sortOrder设置为null。
  • 如果不需要取消查询,可以将cancellationSignal设置为null。

示例代码:

Uri uri = Uri.parse("content://com.example.provider/user");
String[] projection = {"name", "age"};
String selection = "age > ?";
String[] selectionArgs = {"18"};
String sortOrder = "name ASC";
CancellationSignal cancellationSignal = null;
Cursor cursor = getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder, cancellationSignal);

1.5.4 多学一招:UriMatcher类【了解】

  1. 初始化UriMatcher
    UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
    
  2. 将Uri注册到UriMatcher中
    matcher.addURI("cn.itcast.contentprovider", "people", PEOPLE);  
    matcher.addURI("cn.itcast.contentprovider", "person/#", PEOPLE_ID);
    
  3. 与已经注册的Uri进行匹配
    Uri uri = Uri.parse("content://" + "cn.itcast.contentprovider" + "/people");
    int match = matcher.match(uri);
    switch (match){
          case PEOPLE:
           //匹配成功后做的相关操作
           case PEOPLE_ID:
           //匹配成功后做的相关操作
    default:
        return null;
   }   

二 ContentObserver

  1. 内容观察者(ContentObserver)用于观察指定Uri所代表的数据的变化,当ContentObserver观察到指定Uri代表的数据发生变化时,就会触发onChange()方法,此时在onChange()方法中使用ContentResovler可以查询到变化的数据。
  2. 要使用ContentObserver观察数据变化,就必须在ContentProvider中调用ContentResolver的notifyChange()方法。
  • ContentObserver的工作原理如下:
    在这里插入图片描述
    • 使用contentObserver观察 A程序的数据时,首先要在 A程序的ContentProvider中调用ContentResolver的notifyChange()方法,调用此方法后,当 B操作程序作 A程序中的数据时, A程序会向消息中心发送数据变化的消息。此时C程序会观察到消息中心的数据有变化,会触发 ContentObserver的onChange()方法。
      创建ContentObserver的具体步骤如下:

2.1 创建ContentObserver

  1. 创建一个类继承自ContentObserver,并重写onChange方法。
    public class MyContentObserver extends ContentObserver {
    	//Handler对象是主线程中的Handler对象,也可以是其他线程中的Handler对象
        public MyContentObserver(Handler handler) {
            super(handler);
        }
    	//当MyContentObserver观察到Uri代表的数据发生变化时,程序回调用onChange()方法,并在该方法中处理相关的逻辑
        @Override
        public void onChange(boolean selfChange, Uri uri) {
            super.onChange(selfChange, uri);
            // 处理数据变化的逻辑
        }
    }
    
  2. 注册内容观察者
    ContentResolver resolver = getContentResolver();
    Uri uri = Uri.parse("content://aaa.bbb.ccc");
    resolver.registerContentObserver(uri, true, new MyContentObserver(new Handler());
    

参数说明:

  • uri:要监听的数据的地址。
  • notifyForDescendants:是否监听uri的所有子路径。
  1. 取消注册内容观察者
    getContentResolver().unregisterContentObserver(contentObserver);
    

通过以上步骤,就可以创建并使用ContentObserver来监听数据的变化。

注意事项:

  • ContentObserver只能监听ContentProvider中数据的变化,而不能监听其他的数据源。
  • ContentObserver的onChange方法在主线程中执行,如果需要执行耗时操作,建议在onChange中开启新的线程来处理。
  • ContentObserver的注册和取消注册应该在合适的时机进行,避免不必要的资源消耗。

  • 下面是一个完整的示例代码,演示如何创建和使用ContentObserver来监听数据的变化:

    public class MainActivity extends AppCompatActivity {
    
        private MyContentObserver contentObserver;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            // 创建ContentObserver对象
            contentObserver = new MyContentObserver(new Handler());
            
            // 注册ContentObserver监听数据变化
            Uri uri = Uri.parse("content://com.example.provider/user");
            getContentResolver().registerContentObserver(uri, true, contentObserver);
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            // 取消注册ContentObserver
            getContentResolver().unregisterContentObserver(contentObserver);
        }
    
        private class MyContentObserver extends ContentObserver {
            public MyContentObserver(Handler handler) {
                super(handler);
            }
    
            @Override
            public void onChange(boolean selfChange, Uri uri) {
                super.onChange(selfChange, uri);
                // 处理数据变化的逻辑
                Log.d("ContentObserver", "Data changed: " + uri.toString());
                // 可以在这里更新UI或执行其他操作
            }
        }
    }
    
    • 在上述示例中,在MainActivity的onCreate方法中创建了一个ContentObserver对象,并在onDestroy方法中取消注册。在MyContentObserver的onChange方法中,我们可以处理数据变化的逻辑,例如打印日志或更新UI。

2.2 补充:注册ContetnObserver的时机

  • 通常是在Activity、Fragment或Service等组件中的某个方法中注册ContentObserver来监听数据的变化。具体来说,可以在以下方法中注册ContentObserver:
    • 在Activity中,可以在onCreate方法中注册,然后在onDestroy方法中取消注册。
    • 在Fragment中,可以在onCreateView方法中注册,然后在onDestroyView方法中取消注册。
    • 在Service中,可以在onCreate方法中注册,然后在onDestroy方法中取消注册。
  • 具体选择,取决于业务需求和组件的生命周期。
  • 示例代码:
public class MainActivity extends AppCompatActivity {

    private MyContentObserver contentObserver;

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

        // 创建ContentObserver对象
        contentObserver = new MyContentObserver(new Handler());

        // 注册ContentObserver监听数据变化
        Uri uri = Uri.parse("content://com.example.provider/user");
        getContentResolver().registerContentObserver(uri, true, contentObserver);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        // 取消注册ContentObserver
        getContentResolver().unregisterContentObserver(contentObserver);
    }

    private class MyContentObserver extends ContentObserver {

        public MyContentObserver(Handler handler) {
            super(handler);
        }

        @Override
        public void onChange(boolean selfChange, Uri uri) {
            super.onChange(selfChange, uri);
            // 处理数据变化的逻辑
            Log.d("ContentObserver", "Data changed: " + uri.toString());
            // 可以在这里更新UI或执行其他操作
        }
    }
}

三 题目总结

  1. 简述内容提供者的工作原理
    • 假设B程序需要操作A程序数据库中的数据,一般需要A程序使用ContentProvider
      暴露数据,才能被其他程序操作。B程序通过ContentResolver操作A程序暴露出来的数据,而A程序会将操作结果返回给ContentResolver,然后ContentResolver再将操作结果返回给B程序。
  2. 简述内容观察者的工作原理
    • 使用ContentObserver观察A程序的数据时,首先要在A程序的ContentProvider中调用ContentResolver的notifyChange()方法。调用此方法后,当B程序操作A程序中的数据时,A程序会向“消息中心”发送数据变化的消息,此时C程序会观察到“消息中心”的数据有变化,会触发ContentObserver的onChange()方法。
  3. 在ContentProvider中ContentUris的作用是提供增删改查的方法

  • 在ContentProvider中,ContentUris类提供了一些方法,用于处理操作数据库中的数据的URI。这些方法可以帮助开发者在增删改查数据时,对URI进行解析和操作。
    具体来说,ContentUris的作用如下:
  1. 解析URI:ContentUris类的parseId()方法可以从URI中解析出对应的记录的ID。这个方法通常在查询或删除单个记录时使用。例如,可以使用ContentUris.parseId(uri)方法从URI中解析出记录的ID。
  2. 构建URI:ContentUris类的withAppendedId()方法可以将ID添加到URI中,构建出一个新的URI。这个方法通常在插入或更新记录时使用。例如,可以使用ContentUris.withAppendedId(baseUri, id)方法将ID添加到baseUri中,构建出新的URI。
  3. 获取记录的URI:ContentUris类的withAppendedId()方法也可以用于获取指定记录的URI。这个方法通常在查询或删除单个记录时使用。例如,可以使用ContentUris.withAppendedId(baseUri, id)方法获取指定记录的URI。
    通过使用ContentUris类的方法,开发者可以方便地解析和操作URI,从而实现对数据库中的数据进行增删改查的操作。

  1. 若要实现对系统联系人的增删改查,需要使用的系统ContentProvider的Uri为Contacts.Phones.CONTENT_URI
  2. 联系人信息内容提供者的主机名是com.android.contacts
    • 联系人信息的内容提供者的主机名是com.android.contacts,它是Android系统中默认的联系人信息提供者。通过该内容提供者,应用程序可以访问和操作设备上的联系人信息。
  3. 下面哪些功能需要用ContentProvider来实现()。
    A、读取系统中的短信内容
    B、建立一个数据库
    C、开机后自动启动一个程序
    D、播放一段音乐
  • 解析:

    • A、读取系统中的短信内容:需要使用ContentProvider来实现。Android系统中的短信内容存储在短信提供者中,开发者需要通过ContentResolver来查询短信提供者,从而读取系统中的短信内容。

    • B、建立一个数据库:不需要使用ContentProvider来实现。建立数据库可以直接使用SQLiteOpenHelper或Room等数据库框架来创建和管理数据库。

    • C、开机后自动启动一个程序:不需要使用ContentProvider来实现。开机后自动启动一个程序可以通过BroadcastReceiver和BOOT_COMPLETED广播来实现。

    • D、播放一段音乐:不需要使用ContentProvider来实现。播放音乐可以使用MediaPlayer或其他音频播放框架来实现,不涉及ContentProvider的使用。

    • 因此,只有读取系统中的短信内容需要使用ContentProvider来实现。其他功能不需要使用ContentProvider。

  1. 短信的内容提供者是()
    A、ContactProvider
    B、MessageProvider
    C、SmsProvider
    D、TelephonyProvider
  2. 在下列选项中,联系人信息内容提供者的主机名是()
    A、contact
    B、com.android.contacts
    C、com.android.provider.contact
    D、com.android.provider.contacts
  3. 内容提供者主要功能是实现跨程序共享数据的功能
  4. provider中的android:name代表是继承于ContentProvider类的的全路径名称。
  5. 为了解析Uri对象,Android系统提供了一个辅助工具类UriMatcher用于匹配Uri。
  6. Android中通过ContentResover.query()查询短信数据库的时候,第一个Uri参数如何写 contentprovider
  7. 内容观察者是通过观察消息中心来观察数据库的变化
  8. 消息中心是用来观察指定Uri所代表的数据
  9. 利用内容解析者读取短信数据库内容时,短信数据库SmsInfo表主要用来存储短信信息
  10. resolver.registerContentObserver()方法用于注册内容观察者
  11. 创建UriMatcher对象时调用UriMatcher(int code),参数通常使用UriMatcher.NO_MATCH,表示路径不满足条件返回_-1
  12. 当ContentObserver观察到指定Uri代表的数据发生变化时,就会触发ContentObserver的**onChange()**方法。
  13. 内容提供者把私有的数据给暴露出来,我们通过ContentResolver来进行查询数据
  14. 在Android中,是通过ContentResolver读取联系人信息的。
  15. 注册provider时需要指定两个属性android.name和android:authorities
  16. 短信数据是存放在sms表中的
  17. Android中通过内容提供者来读取联系人信息,data表用来保存联系人信息的.
    • Android中读取联系人信息 有三张关键的表1 data表用来存储联系人信息的表,2 raw_contacts 表用来存储一共有多少个联系人. 3 mimetype表用来区分联系人信息的表
  18. 在短信接收器案例中,注册短信内容观察者时,使用的到Uri是Content://sms/

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数字图像处理 基于matlab、opencv计算图像的梯度方向和梯度幅值

一、图像的梯度 1、简述 图像可以被视为标量场(即二维函数)。 通过微分将标量场转换为矢量场。 梯度是一个向量,描述了在x或y方向上移动时,图像变化的速度。我们使用导数来回答这样的问题,图像梯度的大小告诉图像变化的速度,而梯度的方向告诉图像变化最…

【C++学习】C++入门 | 引用 | 引用的底层原理 | auto关键字 | 范围for(语法糖)

写在前面&#xff1a; 上一篇文章我介绍了缺省参数和函数重载&#xff0c; 探究了C为什么能够支持函数重载而C语言不能&#xff0c; 这里是传送门&#xff0c;有兴趣可以去看看&#xff1a;http://t.csdn.cn/29ycJ 这篇我们继续来学习C的基础知识。 目录 写在前面&#x…

图像金字塔

​ 图像金字塔是由一幅图像的多个不同分辨率的子图构成的图像集合。是通过一个图像不断的降低采样率产生的&#xff0c;最小的图像可能仅仅有一个像素点。下图是一个图像金子塔的示例。从图中可以看到&#xff0c;图像金字塔是一系列以金字塔形状排列的、自底向上分辨率逐渐降低…

【数字图像处理】3.对比度增强

目录 3.1 灰度直方图 3.2 线性变换 3.3 直方图正规化 3.4 伽马变换 3.5 全局直方图均衡化 3.6 CLAHE 对比度增强是图像增强的一种&#xff0c;它主要解决的是图像的灰度级范围较小造成的对比度较低的问题&#xff0c;目的是将图像的灰度级增强到指定范围&#xff0c;使得…

实战:用docker-compose容器化springboot项目

文章目录 前言技术积累docker-compose定义docker-compose文件参数docker-compose命令 实战演示1、创建挂载路径2、编写docker-compose.yml3、启动并管理容器 写在最后 前言 前面我们学习和实战了用dockerfile构建镜像&#xff0c;通过镜像可以任意在docker环境容器化部署项目。…

Opencv-C++笔记 (7) : opencv-文件操作XML和YMAL文件

文章目录 一、概述二、文件操作三、打开文件四、写入五、读写个人源码 一、概述 除了图像数据之外&#xff0c;有时程序中的尺寸较小的Mat类矩阵、字符串、数组等 数据也需要进行保存&#xff0c;这些数据通常保存成XML文件或者YAML文件。本小节中将介绍如何利用OpenCV 4中的函…

神经网络:卷积操作

当谈到计算机视觉中的网络模型结构时&#xff0c;卷积操作是其中一个关键的组成部分。卷积操作是一种基于局部区域的操作&#xff0c;它在计算机视觉中用于图像处理和特征提取。 卷积操作的原理如下&#xff1a; 给定一个输入图像和一个称为卷积核&#xff08;或滤波器&#x…

【ARIMA-SSA-LSTM】合差分自回归移动平均方法-麻雀优化-长短期记忆神经网络研究(Python代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

前端Vue自定义数字输入框 带加减按钮的数字输入框组件

前端Vue自定义数字输入框 带加减按钮的数字输入框组件&#xff0c; 下载完整代码请访问uni-app插件市场地址&#xff1a;https://ext.dcloud.net.cn/plugin?id13163 效果图如下&#xff1a; # cc-numbox #### 使用方法 使用方法 <!-- title: 标题 isSetMax: 是否设置最…

synchronized原理

Synchronized能够实现原子性和可见性&#xff1a;在Java内存模型中&#xff0c;synchronized规定&#xff0c;线程在加锁时&#xff0c;先清空工作内存→在主内存中拷贝最新变量的副本到工作内存→执行完代码→将更改后的共享变量的值刷新到主内存中→释放互斥锁。 synchroniz…

Axure教程—折叠面手风琴效果

上文中介绍了用Axure制作折叠面板的基础制作&#xff0c;这次介绍折叠面板手机风琴效果 效果 预览地址&#xff1a;https://e18rf6.axshare.com 功能 点击标题展开内容&#xff0c;点击另一标题&#xff0c;其展开的内容折叠 制作 拖入四个动态面板&#xff0c;分别命名为1、…

【微服务】springboot 通用限流方案设计与实现

目录 一、背景 二、限流概述 2.1 dubbo 服务治理模式 2.1.1 dubbo框架级限流 2.1.2 线程池设置 2.1.3 集成第三方组件 2.2 springcloud 服务治理模式 2.2.1 hystrix 2.2.2 sentinel 2.3 网关层限流 三、常用限流策略 3.1 限流常用的算法 3.1.1 令牌桶算法 3.1.2 …

【深度学习】2-5 神经网络-批处理

批处理&#xff08;Batch Processing&#xff09;是指在深度学习中每次迭代更新模型参数时同时处理多个样本的方式。 批处理时要注意对应维度的元素个数要一致 关于之前手写数字识别的例子&#xff1a; 用图表示&#xff0c;可以发现&#xff0c;多维数组的对应维度的元素个数…

前端Vue自定义导航栏菜单 定制左侧导航菜单按钮 中部logo图标 右侧导航菜单按钮

前端Vue自定义导航栏菜单 定制左侧导航菜单按钮 中部logo图标 右侧导航菜单按钮&#xff0c; 下载完整代码请访问uni-app插件市场地址&#xff1a;https://ext.dcloud.net.cn/plugin?id13152 效果图如下&#xff1a; # cc-navHeader #### 使用方法 使用方法 在page.json设…

一种实现Spring动态数据源切换的方法 | 京东云技术团队

1 目标 不在现有查询代码逻辑上做任何改动&#xff0c;实现dao维度的数据源切换&#xff08;即表维度&#xff09; 2 使用场景 节约bdp的集群资源。接入新的宽表时&#xff0c;通常uat验证后就会停止集群释放资源&#xff0c;在对应的查询服务器uat环境时需要查询的是生产库…

实例讲解,一文弄懂workqueue和waitqueue

本期主题&#xff1a; 讲清workqueue和waitqueu&#xff1a; 从中断讲起waitqueue是什么workqueue总结 往期链接&#xff1a; linux设备驱动中的并发linux设备驱动中的编译乱序和执行乱序linux设备驱动之内核模块linux字符驱动linux字符驱动之ioctl部分linux字符驱动之read、…

分布式存储Ceph的部署及应用(创建MDS、RBD、RGW 接口)

系列文章目录 文章目录 系列文章目录一、1.存储基础2. 单机存储的问题3. 分布式存储&#xff08;软件定义的存储 SDS&#xff09; 二 Ceph1.Ceph 简介2. Ceph 数据的存储过程 总结 一、 1.存储基础 1.1 单机存储设备 ●DAS&#xff08;直接附加存储&#xff0c;是直接接到计算…

SAX解析XML返回对应格式的Map对象

前言 最近有一个解析大型xml的需求&#xff0c;xml大小7M&#xff0c;其中xml结构非常复杂&#xff0c;元素各种嵌套 不乏有元素下对象&#xff0c;元素下集合&#xff0c;集合下对象&#xff0c;集合下集合&#xff0c;兄弟不同元素节点&#xff0c;元素下对象下集合&#xff…

HDFS读写流程

读数据流程 客户端向NameNode请求文件的位置&#xff1a;客户端想要访问一个文件时&#xff0c;会向NameNode发送一个请求&#xff0c;要求获取该文件在HDFS上的位置信息。 NameNode将位置信息返回给客户端&#xff1a;NameNode接收到客户端的请求后&#xff0c;会返回该文件所…

设计模式—访问者模式

需求&#xff1a;店铺采购了一批水果&#xff08;苹果及橘子&#xff09;&#xff0c;现在市场监督局来店里检查过期的水果。 public class Fruit {private String name;private Date pickDate;public Fruit(String name, Date pickDate) {this.name name;this.pickDate pic…