UI自动刷新大法:DataBinding数据绑定

news2025/1/19 14:20:57

之前我们讲了DataBinding在Activity、Fragment、RecyclerView中的基础使用,而那些常规使用方法里,每当绑定的变量发生数据变化时,都需要ViewDataBinding重新设值才会刷新对应UI。而DataBinding通过内部实现的观察者模式来进行自动刷新UI,这块内容是DataBinding的重要部分。在观察者模式的角度下,DataBinding库,允许我们使用对象、字段,或者集合来进行观察,当其中的一个可观察者数据对象绑定到了视图当中,并且数据对象的属性发生更改变化的时候,视图将会自动更新。而根据绑定的方式不同,又可分为 单向绑定双向绑定

单向绑定,实现数据变化自动驱动UI刷新,方式有三种:BaseObservable,ObservableField、ObservableCollection。在此之前,先让我们来了解下事件绑定。

前言 事件绑定

为了更好的了解单向绑定和后续的双向绑定,我们先来看下DataBinding中事件绑定的方式。严格来说,事件绑定也是一种变量绑定,只不过设置的绑定不再是单纯的变量,还是回调接口,事件绑定可设置的回调事件有以下:

android:onClick
android:onLongClick
android:onTextChanged
android:afterTextChanged
...

对应使用步骤也较为简单:

第一步 声明内部类

在要使用的activity类里新建一个内部类来声明对应的回调方法,这里我们接着用上篇文章中的工程来继续修改。我们在MainActivity中新建一个内部类,里面声明onClick()和afterTextChanged()事件:

public class MainActivity extends AppCompatActivity {
    UserInfo userInfo;
    DemoBinding viewDataBinding;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        userInfo = new UserInfo("亚历山大", 66);
        viewDataBinding.setUserInfoExample(userInfo);
        viewDataBinding.setUserEventListener(new EventListener());
    }
    public class EventListener{
        public void changedUserName(){
            userInfo.setName("鸭梨山大二世");
            viewDataBinding.setUserInfoExample(userInfo);
        }
        public void changedUserInfo(){
            userInfo.setName("鸭力山大三世");
            userInfo.setAge(81);
            viewDataBinding.setUserInfoExample(userInfo);
        }
    }
}

第二步 修改布局标签内容

同时还要在相应布局文件中的< data>标签里声明此内部类路径,在对应设置此点击事件回调的控件里通过内嵌表达式 @{} 来设置引用。

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <import type="com.example.dbjavatest.MainActivity.EventListener"/>
        <import type="com.example.dbjavatest.bean.UserInfo"/>

        <variable
            name="UserInfoExample"
            type="UserInfo" />

        <variable
            name="UserEventListener"
            type="EventListener" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:id="@+id/tv_user_first"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="@{()->UserEventListener.changedUserName()}"
            android:text="@{UserInfoExample.name,default=defaultValue}"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"/>

        <TextView
            android:id="@+id/tv_user_second"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(UserInfoExample.age),default=defaultValue}"
            app:layout_constraintTop_toBottomOf="@+id/tv_user_first"
            app:layout_constraintStart_toStartOf="parent"/>

        <Button
            android:id="@+id/btn_change"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_constraintTop_toBottomOf="@+id/tv_user_second"
            app:layout_constraintStart_toStartOf="parent"
            android:text="改变属性"
            android:onClick="@{()->UserEventListener.changedUserInfo()}"/>

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

在这布局文件中,android:onClick="@{()->UserEventListener.changedUserName()}"属性含义即为点击事件响应方法为指定的UserEventListener中的changedUserName(),运行后,可查看效果如下:

DataBinding点击事件.gif

单向数据绑定之Base Observable

众所周知,一个单纯的ViewModel类被更新后,并不会让UI自动更新。Observable存在的目的就是为了数据变更后UI会自动刷新。

在此方面,Observable提供了两个方法:

· notifyChange()
· notifyPropertyChanged()

方法一notifyChange()会刷新所有的UI。

方法二notifyPropertyChanged()只会刷新属于它的UI,需要绑定属性(通过注解 @Bindable来绑定)。

使用方式也较为简单:

第一步 修改实体bean类

使实体bean类继承自BaseObservable:

public class UserInfo extends BaseObservable {
    public UserInfo(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        notifyPropertyChanged(BR.name);
    }

    public void setNameAndAge(String name,int age){
        this.name = name;
        this.age = age;
        notifyChange();
    }

    @Bindable
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Bindable
    public String name; //public属性成员可直接在成员变量上方加上@Bindable

    private int age; //private属性成员需要在其get方法上添加@Bindable
}

第二步、修改对应Activity

为了凸显出区别,我们继续沿用上面点击事件中例子的布局,不做修改,但是Activity中代码要修改:

public class MainActivity extends AppCompatActivity {
    UserInfo userInfo;
    ActivityMainBinding viewDataBinding;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        userInfo = new UserInfo("亚历山大", 66);
        viewDataBinding.setUserInfoExample(userInfo);
        viewDataBinding.setUserEventListener(new EventListener());
    }
    public class EventListener{
        public void changedUserName(){
            userInfo.setName("鸭梨山大二世");
            userInfo.setAge(999);//无效
        }
        public void changedUserInfo(){
            userInfo.setNameAndAge("鸭力山大X世",new Random().nextInt(100));
        }
    }
}

可以看到,相比于普通的点击事件代码中明显少了viewDataBinding.setUserInfoExample…等操作,可能一两个点击事件看不出明显差别,但事件一多,你会发现Activity的代码会省略很多,非常利于代码解耦和整洁性。这也不影响相应效果,运行效果如下:

DataBinding中的Observable点击事件.gif

可见,在点击用户名时,userInfo.setAge(999)执行无效的,因为在原实体bean类中,只设置了改变name属性(notifyPropertyChanged(BR.name)):

image.gif
所以在点击name属性的时候,只有名字在变化,而点击事件里setNameAndAge()中因为声明了notifyChange();改变所有元素,因此可看到点击按钮时,全局属性跟着改变了(name属性一致固定写死,所以你可能觉得名字没变化)。

二、单项数据绑定之ObservableField

有的时候相应工程里,实体Bean类需要继承其他类,这样就无法使用Observable了。这时有另外一个方案,即ObservableField。PS:ObservableField不需要进行notify操作。

在ObservableField中,官方提供了对基本数据类型的封装,如ObservableInt、ObservableLong、ObservableFloat、ObservableDouble ObservableShort、ObservableBoolean、ObservableByte、ObservableChar以及 ObservableParcelable 。当然也可通过泛型来申明其他类型,可以说这是官方对Observable中字段的注解和刷新等操作等封装。

其使用方式与Observable还是有点区别的:

第一步 修改实体bean类

public class UserInfo{

    public final ObservableField<String> name;

    public final ObservableField<Integer> age;

    public ObservableField<String> getName() {
        return name;
    }

    public ObservableField<Integer> getAge() {
        return age;
    }

    public UserInfo(String name,
                    Integer age){
        this.name=new ObservableField<>(name);
        this.age= new ObservableField<Integer>(age);
    }
}

可见Bean文件在这里取消了继承,对变量进行了public final修饰,重写对应的get()(final修饰的变量无法写set())。其set()属性的方式则有些许不一样。

第二步 修改对应逻辑

在对应需要进行set逻辑的地方,可以通过ObservableField提供的get、set方法,去拿到值和设置值来达到更新UI效果。如下:

public class MainActivity extends AppCompatActivity {
    UserInfo userInfo;
    ActivityMainBinding viewDataBinding;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        userInfo = new UserInfo("亚历山大", 66);
        viewDataBinding.setUserInfoExample(userInfo);
        viewDataBinding.setUserEventListener(new EventListener());
    }
    public class EventListener{
        public void changedUserName(){
            userInfo.getName().set("鸭梨山大二世");
        }
        public void changedUserInfo(){
            userInfo.getName().set("鸭梨山大一世");
            userInfo.getAge().set(new Random().nextInt(101));
        }
    }
}

对应的效果为:

DataBinding-Field点击事件.gif

三、单项数据绑定之ObservableCollection

ObservableCollection中最常用的是ObservableList 和 ObservableMap,即dataBinding 提供的包装类用于替代原生的 List 和 Map。其使用方式与前两者差别也不大。

第一步 修改Collection布局

这里我们不再使用实体bean类,而是dataBinding 包装的ObservableMap和ObservableList元素,因此需要修改< data>标签。如下:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <import type="androidx.databinding.ObservableMap"/>
        <import type="androidx.databinding.ObservableList"/>
        <!--注意这里,只能用 "&lt;"和 "&gt;"-->
        <variable
            name="list"
            type="ObservableList&lt;String&gt;"/>
        <variable
            name="map"
            type="ObservableMap&lt;String,Integer&gt;"/>
        <variable
            name="sing"
            type="String"/>
        <variable
            name="num"
            type="int"/>
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:id="@+id/tv_user_first"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{list[num],default=syt}"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"/>

        <TextView
            android:id="@+id/tv_user_second"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(map[sing]),default=sys}"
            app:layout_constraintTop_toBottomOf="@+id/tv_user_first"
            app:layout_constraintStart_toStartOf="parent"/>

        <Button
            android:id="@+id/btn_change"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_constraintTop_toBottomOf="@+id/tv_user_second"
            app:layout_constraintStart_toStartOf="parent"
            android:text="改变属性"
            android:onClick="onButtonClick"/>

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

这里的ObservableMap和ObservableList归属的databinding在androidX包里,如果你的工程还没有适配安卓X,最好请尽快适配。最后一个Button里的android:onClick="onButtonClick"可能会让你感到疑惑,但其实这也是dataBinding里的控件的点击事件写法之一。

第二步 修改Activity中对应逻辑

其Activity中代码就如下:

public class MainActivity extends AppCompatActivity{
    ActivityMainBinding viewDataBinding;
    private ObservableMap<String, Integer> map;
    ObservableArrayList<String> obList;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        map = new ObservableArrayMap<>();
        map.put("test_num",1 );
        map.put("test_biger_num", 100);
        viewDataBinding.setMap(map);
        obList = new ObservableArrayList<>();
        obList.add("ObservableArrayList");
        obList.add("observablelist");
        obList.add("observablelist more");
        viewDataBinding.setList(obList);
        viewDataBinding.setNum(0);
        viewDataBinding.setSing("test_biger_num");
    }

    public void onButtonClick(View v) {
        map.put("test_biger_num",new Random().nextInt(99));
    }

}

对应效果如下:

DataBinding_ObservableCollection点击事件.gif

当然,设置点击事件还有一种方法引用,直接用 :: 即可,
如: android:onClick=“@{listener::onClick}” 就是方法引用绑定!

四、双向数据绑定

双向绑定含义就是 在数据更新时使得View也能更新,而View更新的时候也同时更改数据

此法不适合所有的应用场景,但也有相应的应用场景,比如用户注册登录场景,在输入账号和密码同时,UI刷新同时数据也更新,这里就适合双向绑定。可以说,双向绑定时安卓MVVM架构的基础。
这次简单实例我们用ObservableField方式,先写一个bean实体类:

public class DataBean {
    public final ObservableField<String> dataInfo;

    public DataBean(ObservableField<String> dataInfo) {
        this.dataInfo = dataInfo;
    }

    public ObservableField<String> getDataInfo() {
        return dataInfo;
    }
}

对应也要修改布局文件和引入,如下:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <import type="com.example.dbjavatest.bean.DataBean"/>
        <variable
            name="dataInfoBean"
            type="DataBean" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:id="@+id/tv_data"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="26sp"
            android:textColor="@color/purple_200"
            android:text="@{dataInfoBean.dataInfo}"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:layout_marginLeft="50dp"/>

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="请输入数据"
            android:text="@={dataInfoBean.dataInfo}"
            app:layout_constraintTop_toBottomOf="@+id/tv_data"
            android:textSize="25sp"
            android:layout_marginTop="30dp"
            android:paddingLeft="20dp"/>

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

这里要注意,在EditText中更新数据时会同步到上面的TextView,绑定方式跟单向绑定方式相比,要在内嵌表达式中多用一个“=”,即android:text=“@={dataInfoBean.dataInfo}”。

对应Activity中代码如下:

public class MainActivity extends AppCompatActivity{
    ActivityMainBinding viewDataBinding;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        DataBean dataBean = new DataBean(new ObservableField<String>(""));
        viewDataBinding.setDataInfoBean(dataBean);
    }
}

效果也能猜到:

DataBinding双向绑定.gif

五、List Set Map等数据结构

除了ObservableCollection,DataBinding也支持原生Java数据结构(数组、List、Set和Map)在布局文件中使用,且在布局文件中都可以通过list[index]的形式来获取元素。

官方为了和< variable>标签元素区分开,在声明具有多个泛型的数据类型时,需要使用"& lt;"和 " >"用以区分。如下:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <import type="java.util.List" />
        <import type="java.util.Set" />
        <import type="java.util.Map" />
        <variable
            name="array"
            type="String[]" />
        <variable
            name="list"
            type="List&lt;String&gt;" />
        <variable
            name="map"
            type="Map&lt;String, String&gt;" />
        <variable
            name="set"
            type="Set&lt;String&gt;" />
        <variable
            name="num"
            type="int" />
        <variable
            name="sing"
            type="String" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">

        <TextView
        ···
        android:text="@{array[1]}" />
        <TextView
        ···
        android:text="@{list[num]}" />
        <TextView
        ···
        android:text="@{map[sing]}" />
        <TextView
        ···
        android:text='@{map["test"]}' />
    </LinearLayout>
</layout>

六、使用相应类方法

在DataBinding中,使用相应类方法,可现在< data>标签中导入该类不需要写<vari…>标签,然后在布局中像对待一般方法来调用就行。

例如,先写个没啥用的静态类:

public class UIUtils {

    public static String showTheDemo(String str) {
        return str.toString();
    }

}

在< data>中引入该类:

<import type="com.example.dbjavatest.UIUtils" />

然后在对应控件里调用:

<TextView
    android:id="@+id/tv_data"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="26sp"
    android:textColor="@color/purple_200"
    android:text="@{UIUtils.showTheDemo(dataInfoBean.dataInfo)}"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    android:layout_marginLeft="50dp"/>

PS : DataBinding中布局里的控件通过嵌入表达式不仅可以引用对应方法,也可以使用三元运算符等运算符。

七、include和viewStub

DataBinding也支持include的布局文件,一样通过dataBinding来进行数据绑定,一样需要使用< layout>标签和声明需要使用的变量,然后在主布局中将对应的变量传递给include布局,使两个布局共享的数据变量相同。

例如:view_insert.xml中

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <import type="com.example.dbjavatest.bean.DataBean"/>
        <variable
            name="dataInfoBean"
            type="DataBean" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="请输入数据"
            android:text="@={dataInfoBean.dataInfo}"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            android:textSize="25sp"
            android:layout_marginTop="30dp"
            android:paddingLeft="20dp"/>
    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

对应主布局则直接include,同时通过bind:变量名来将同一变量传过去。你可能发现这里会报错,在布局头文件声明xmlns:bind=“http://schemas.android.com/apk/res-auto” 即可。对应布局文件为:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:bind="http://schemas.android.com/apk/res-auto">

    <data>
        <import type="com.example.dbjavatest.bean.DataBean"/>
        <variable
            name="dataInfoBean"
            type="DataBean" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:id="@+id/tv_data"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="26sp"
            android:textColor="@color/purple_200"
            android:text="@{dataInfoBean.dataInfo}"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:layout_marginLeft="50dp"/>

        <include
            layout="@layout/view_insert"
            app:layout_constraintTop_toBottomOf="@+id/tv_data"
            bind:dataInfoBean = "@{dataInfoBean}"
            />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

ViewStub绑定变量和将变量传递给ViewStub的方式与此一致。例如:

<ViewStub
    android:id="@+id/view_stub"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout="@layout/view_insert"
    bind:dataInfoBean="@{dataInfoBean}" />

当然,ViewStub 文件一样要使用 layout 等标签进行布局。相应的在Activity中也是通过ViewBinding获取对象实例:

View viewStub = viewDataBinding.viewStub.getViewStub().inflate();

通过此实例,可以控制viewStub的可见性。如果在xml中,没用使用bind:dataInfoBean=“@{dataInfoBean}”,但又想对ViewStub进行数据绑定。则可以在ViewStub 设置 setOnInflateListener回调函数时进行数据绑定,如下:

viewDataBinding.viewStub.setOnInflateListener(new ViewStub.OnInflateListener() {
    @Override
    public void onInflate(ViewStub stub, View inflated) {
        ViewDataBinding viewStubBinding = DataBindingUtil.bind(inflated);
        viewStubBinding.setDataInfoBean(dataBean);
    }
});

对DataBinding的数据绑定就介绍到这里了,如果后续发现有遗漏的要点,会即使补充。另外,如果看这篇文字有点吃力,说明你对DataBinding的基础操作还不熟悉,请翻阅我的上一片文章。

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

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

相关文章

理解JAVA EE设计模式

理解JAVA EE设计模式 在Web应用程序的设计和开发阶段,开发人员在开发类似的项目时可能会遇到相似的问题。每名开发人员可能会遇到的问题找出不同或相似的解决方案。但是,这导致一些时间和精力浪费在为相似的问题寻找解决方案上。因此,要啊节省时间和精力,需要记录常见问题…

基于Spring Boot的足球青训俱乐部管理后台系统,计算机毕业设计(带源码+论文)

源码获取地址&#xff1a; 码呢-一个专注于技术分享的博客平台一个专注于技术分享的博客平台,大家以共同学习,乐于分享,拥抱开源的价值观进行学习交流http://www.xmbiao.cn/resource-details/1757420859554869250

力扣刷题之旅:高阶篇(四)—— 最小生成树算法

力扣&#xff08;LeetCode&#xff09;是一个在线编程平台&#xff0c;主要用于帮助程序员提升算法和数据结构方面的能力。以下是一些力扣上的入门题目&#xff0c;以及它们的解题代码。 --点击进入刷题地址 引言&#xff1a; 在算法领域中&#xff0c;图论是一个重要且有趣…

基于 Python 深度学习的电影评论情感分析系统,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

去空行小工具Html + Javascript

这是一个平常用到的小工具&#xff0c;为了节省屏幕空间把空行去掉&#xff0c;怕要用的时候找不到故记录在此。 效果图 网页版&#xff0c;放在浏览器里就可以用 <!doctype html> <html><head><meta charset"utf-8"><title>去回车…

MySQL数据库⑨_事务(四个属性+回滚提交+隔离级别+MVCC)

目录 1. 事务的概念和四个属性 2. 事务的支持版本 3. 事务的提交方式 4. 事务的相关演示 4.1 常规操作_回滚_提交 4.2 原子性_演示 4.3 持久性_演示 4.4 begin自动更改提交方式 4.5 单条SQL与事务的关系 5. 事务的隔离级别 5.1 四种隔离级别 5.2 查看与设置隔离级别…

Peter算法小课堂—区间模型(2)

上次咋们讲了前两个区间模型&#xff1a;1.最大不重叠区间数 2.不重叠区间最少分组数。今天我们就学习&#xff1a;最小区间覆盖问题、区间重叠最厚层数&#xff01; 最小区间覆盖 先看三道题 那么&#xff0c;第1题&#xff0c;它是浮点数的题&#xff0c;也就要求首尾相同。…

react【五】redux/reduxToolkit/手写connext

文章目录 1、回顾纯函数2、redux2.1 redux的基本使用2.2 通过action修改store的数值2.3 订阅state的变化2.4 目录结构2.5 Redux的使用过程2.6 redux的三大原则2.7 Redux官方图 3、redux在React中的使用4、react-redux使用4.1 react-redux的基本使用4.2 异步请求 redux-thunk4.3…

Pycharm里如何设置多Python文件并行运行

点击上方“Python爬虫与数据挖掘”&#xff0c;进行关注 回复“书籍”即可获赠Python从入门到进阶共10本电子书 今 日 鸡 汤 夕阳何事近黄昏&#xff0c;不道人间犹有未招魂。 大家好&#xff0c;我是皮皮。 一、前言 相信使用Pycharm的粉丝们肯定有和我一样的想法&#xff0c;…

linux---内存管理

一 虚拟内存 即使是现代操作系统中&#xff0c;内存依然是计算机中很宝贵的资源&#xff0c;看看你电脑几个T固态硬盘&#xff0c;再看看内存大小就知道了。 为了充分利用和管理系统内存资源&#xff0c;Linux采用虚拟内存管理技术&#xff0c;利用虚拟内存技术让每个进程都有…

three.js 细一万倍教程 从入门到精通(三)

目录 五、详解PBR材质纹理 5.1、详解PBR物理渲染 5.2、标准网格材质与光照物理效果 5.3、置换贴图与顶点细分设置 5.4、设置粗糙度与粗糙度贴图 5.5、设置金属度与金属贴图 5.6、法线贴图应用 5.7、如何获取各种类型纹理贴图 5.8、纹理加载进度情况 单张图片加载 多…

C++赛马游戏

题目&#xff1a; 代码&#xff1a; #include<iostream> using namespace std; int a,b,c; int main(){cin>>a>>b>>c;if(a>b&&a>c&&b>c){//a>b>ccout<<c<<" "<<b<<" "&…

docker 3.1 镜像

docker 3.1 镜像命令 拉取镜像 docker pull debian #从 Docker Hub 拉取名为 debian 的镜像docker pull hello-world #从 Docker Hub 拉入名为 hello-world 的镜像‍ 运行镜像/容器 docker run hello-world ‍ 查看本地所有的镜像 docker images​​ 容器生成镜像…

Gitee的使用教程(简单详细)

1.安装git&#xff08;我的电脑自带git&#xff0c;我没弄这步QAQ&#xff09; Git (git-scm.com)https://git-scm.com/ 安装好后在桌面点击鼠标右键会出现git GUI 和 git Bash&#xff08;没有的话点击显示更多选项&#xff09; 2.去gitee上注册一个账号 工作台 - Gitee.co…

LeetCode、208. 实现 Trie (前缀树)【中等,自定义数据结构】

文章目录 前言LeetCode、208. 实现 Trie (前缀树)【中等&#xff0c;自定义数据结构】题目链接与分类思路 资料获取 前言 博主介绍&#xff1a;✌目前全网粉丝2W&#xff0c;csdn博客专家、Java领域优质创作者&#xff0c;博客之星、阿里云平台优质作者、专注于Java后端技术领…

C# WinFrom+AspNetCore WebApi实现大文件下载与上传

客户端UI: 服务端WebApi: 客户端代码&#xff1a; App.config&#xff1a; <?xml version"1.0" encoding"utf-8" ?> <configuration><appSettings><add key"WebApi" value"https://localhost:7285"/><…

Vulnhub靶场 DC-8

目录 一、环境搭建 二、信息收集 1、主机发现 2、指纹识别 三、漏洞复现 1、SQL注入 sqlmap工具 2、dirsearch目录探测 3、反弹shell 4、提权 exim4 5、获取flag 四、总结 一、环境搭建 Vulnhub靶机下载&#xff1a; 官网地址&#xff1a;https://download.vulnhub.com/dc/DC-…

Java基于SpringBoot+vue的租房网站,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

《UE5_C++多人TPS完整教程》学习笔记5 ——《P6 在线子系统(Online Subsystem)》

本文为B站系列教学视频 《UE5_C多人TPS完整教程》 —— 《P6 在线子系统&#xff08;Online Subsystem&#xff09;》 的学习笔记&#xff0c;该系列教学视频为 Udemy 课程 《Unreal Engine 5 C Multiplayer Shooter》 的中文字幕翻译版&#xff0c;UP主&#xff08;也是译者&a…

华为机考入门python3--(12)牛客12-字符串反转

分类&#xff1a;字符串 知识点&#xff1a; 字符串是否为空 if not my_str 字符串逆序 my_str[::-1] 题目来自【牛客】 def reverse_string(s): # 判断字符串是否为空或只包含空格 if not s.strip(): return "" # 使用Python的切片语法反转字符串 re…