当前位置: 首页 > news >正文

【MyBatis】操作数据库——入门

在这里插入图片描述

文章目录

  • 为什么要学习MyBatis
  • 什么是MyBatis
  • MyBatis 入门
    • 创建带有MyBatis框架的SpringBoot项目
    • 数据准备
    • 在配置文件中配置数据库相关信息
    • 实现持久层代码
    • 单元测试

为什么要学习MyBatis

前面我们肯定多多少少学过 sql 语言,sql 语言是一种操作数据库的一类语言,数据库是保证数据能够持久化存储的一种集合。在众多 sql 语言中,MySQL就是其中一种,并且是人们使用较多的一种 sql 语言,而就是因为 MySQL 使用较简单,使用的人较多,所以就出现了 JDBC 编程,也就是 Java 的一个 API,可以让我们通过 Java 代码来操作我们的数据库,但是呢?JDBC 编程的操作太复杂了,为什么会说 JDBC 操作复杂呢?看下面这段代码。

package com.example.mybatis20231226.Dao;import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;public class UserDao {DataSource dataSource = null;public UserDao(DataSource dataSource) {this.dataSource = dataSource;}public void addUser() throws SQLException {Connection connection = null;PreparedStatement statement = null;try {connection = dataSource.getConnection();String sql = "insert into user values (?,?,?);";statement = connection.prepareStatement(sql);statement.setString(2, "小明");statement.setInt(3, 0);statement.execute();} catch (SQLException e) {throw new RuntimeException(e);} finally {if (statement != null) {statement.close();}if (connection != null) {connection.close();}}}
}

使用 JDBC 操作,需要创建出 DataSource 数据源对象、Connection 对象、PrepareStatement 对象,甚至是 ResultSet 对象,并且在使用完这些资源之后还不能忘记释放掉这些资源,这些 JDBC 很多的操作都是重复的,所以就出现了能够简化 JDBC 操作的框架——MyBatis。

什么是MyBatis

MyBatis的发展历程可以追溯到2001年,当时Clinton Begin发起了一个名为iBATIS的开源项目。iBATIS最初是一个专注于密码软件开发的开源项目,但后来逐渐发展成为一个基于Java的持久层框架。

在2004年,Clinton将iBATIS的名字和源码捐赠给了Apache软件基金会,接下来的6年中,开源软件世界发生了巨大的变化,一切开发实践、基础设施、许可,甚至数据库技术都彻底改变了。

2010年,核心开发团队决定离开Apache软件基金会,并且将iBATIS改名为MyBatis。之后,MyBatis迁移到了Google Code,并在2013年11月再次迁移到了GitHub。

在功能上,MyBatis是一款优秀的支持自定义SQL查询、存储过程和高级映射的持久层框架。它消除了几乎所有的JDBC代码和参数的手动设置以及结果集的检索。MyBatis可以使用简单的XML或注解进行配置和原始映射,将接口和Java的POJOs(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。使得数据持久层的设计更为灵活和高效。

这里是 MyBatis 的中文官方网站https://mybatis.net.cn/

在这里插入图片描述
在 Spring 中,三层架构分别是Controller(控制层)、Service(业务逻辑层)和Dao(数据访问层),我们的 MyBatis 就处于三层架构的 Dao 层。

在这里插入图片描述
简单来说,MyBatis 就是更简单完成程序和数据库交互的框架,也就是更简单的操作和读取数据库的工具。

MyBatis 入门

首先我们先通过一个使用了 MyBatis 框架的程序来看看 MyBatis 有多么的方便。

创建带有MyBatis框架的SpringBoot项目

在创建项目的时候勾选上 MyBatis FrameworkMySQL Driver

在这里插入图片描述
MyBatis 不是只能用于 Java 的 Spring 框架,它可以独立存在,只是因为 MyBatis 的实用性的方便,所以 Idea 才将 MyBatis 给集成进来了。那么既然选择了 MyBatis,为什么还要选择 MySQL Driver 呢?前面我们说了,MyBatis 是一种框架,他操作的是数据库,只是简化了 JDBC 的操作,所以底层还是 JDBC。

当勾选了 MyBatis 框架了之后,在 SpringBoot 项目的 pom.xml 文件中可以发现已经自动导入了 MyBatis 和 MySQL 的依赖。

<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter-test</artifactId><version>3.0.3</version><scope>test</scope>
</dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope>
</dependency>

如果我们已经创建完成了SpringBoot项目了之后,想要在当前项目添加进去 MyBatis 依赖的话,可以使用前面的 Edit Starters 插件来继续添加进去 MyBatis 依赖。

在这里插入图片描述
当然我们也可以去 maven 中央仓库通过添加 MyBatis 依赖的坐标到 pom.xml 文件中来加入依赖,其实上一个在创建 SpringBoot 项目的时候勾选 MyBatis 选项也是将 MyBatis 的坐标添加进去 pom.xml 文件中,只不过这个是 Idea 帮我们自动完成了。

注意:手动添加 Mybatis 依赖的时候,需要注意 Spring 版本和 MyBatis 版本的对应关系。

数据准备

我们先在本地数据库中存储一些数据,作为后面 MyBatis 操作的数据。

-- 创建数据库
DROP DATABASE IF EXISTS mybatis_test;
CREATE DATABASE mybatis_test DEFAULT CHARACTER SET utf8mb4;
-- 使⽤数据数据
USE mybatis_test;
-- 创建表[⽤⼾表]
DROP TABLE IF EXISTS userinfo;
CREATE TABLE `userinfo` (`id` INT ( 11 ) NOT NULL AUTO_INCREMENT,`username` VARCHAR ( 127 ) NOT NULL,`password` VARCHAR ( 127 ) NOT NULL,`age` TINYINT ( 4 ) NOT NULL,`gender` TINYINT ( 4 ) DEFAULT '0' COMMENT '1-男 2-⼥ 0-默认',`phone` VARCHAR ( 15 ) DEFAULT NULL,`delete_flag` TINYINT ( 4 ) DEFAULT 0 COMMENT '0-正常, 1-删除',`create_time` DATETIME DEFAULT now(),`update_time` DATETIME DEFAULT now(),PRIMARY KEY ( `id` )
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4;-- 添加⽤⼾信息
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'admin', 'admin', 18, 1, '18612340001' );
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'zhangsan', 'zhangsan', 18, 1, '18612340002' );
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'lisi', 'lisi', 18, 1, '18612340003' );
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'wangwu', 'wangwu', 18, 1, '18612340004' );

在这里插入图片描述
在 Java 中创建出 UserInfo 类与数据库中一行的数据对应。这里为什么要与数据库中的列对应以及可不可以不对应,我们后面再说。

package com.example.mybatis20231226.Model;import lombok.Data;import java.util.Date;@Data
public class UserInfo {private int id;private String username;private String password;private int age;private int gender;private String phone;private int deleteFlag;private Date createTime;private Date updateTime;
}

在配置文件中配置数据库相关信息

我这里选择的是 YAML 配置文件配置,properties 也类似。

spring:datasource:url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=falseusername: rootpassword: xxxxxxdriver-class-name: com.mysql.cj.jdbc.Driver

如果MySQL使用的是5.x之前版本的话,driver-class-name选项的值要使用 com.mysql.jdbc.Driver ,大于5.x版本就使用 com.mysql.jdbc.cj.Driver

实现持久层代码

MyBatis 持久层接口规范一般都叫XxxMapper。

package com.example.mybatis20231226.Mapper;import com.example.mybatis20231226.Model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;import java.util.List;@Mapper
public interface UserInfoMapper {@Select("select * from userinfo")public List<UserInfo> selectAll();
}

注意这里的 @Mapper 注解要选择 org.apache.ibatis.annotations 包下的。
在这里插入图片描述
在MyBatis中,@Mapper注解主要用于标识接口,它表示该接口是一个MyBatis的映射器接口。这个注解可以帮助简化代码和提高代码的可读性。

当你使用@Mapper注解标记一个接口时,MyBatis会自动为该接口生成实现类,该实现类包含了该接口中所有方法对应的SQL语句和执行逻辑。而在Spring中使用@Mapper注解,Spring会扫描到这个接口,并将其实例化为一个Bean,自动注入到MyBatis的SqlSession中。这样,你就可以通过直接调用接口方法的方式来执行相应的SQL语句,而不需要手动编写实现代码。

@Select("select * from userinfo")
public List<UserInfo> selectAll();

public List<UserInfo> selectAll() 是方法的声明,而这个 @Select("select * from userinfo") 则是这个方法的实现。Select 说明这个方法是一个查询方法。

那么有人会问了,这里类为什么会选择使用 interface 接口,而不是 class 呢?如果你是 class 的话,那么方法的具体实现就是需要我们写出来的,而上面说了这个方法的实现是通过 @Select("select * from userinfo") 注解实现的,如果我们再在这个方法中写上实现的话,就会导致冲突出现问题,而 interface 接口中的所有方法都是抽象方法,是不需要写出方法的实现的,正好对应 MyBatis 注解来实现,所以 interface 接口是最好的选择。

单元测试

当我们写完上面的代码之后,是否需要再创建一个测试类来测试这个方法呢?可以这样,但是这样比较麻烦,我们可以通过单元测试的方法快速的测试我们的代码功能。

单元测试是一种对软件中的最小可测试单元进行检查和验证的测试活动。在软件开发过程中,单元测试是在最低级别进行的测试活动,通常针对软件的独立单元进行,这些单元可能是函数、类、模块或组件。单元测试的目标是确保每个单元都能按照预期的方式工作,并且能够与其他单元协调工作。
对于单元测试中单元的含义,要根据实际情况去判定其具体含义。例如,在C语言中,单元通常指的是一个函数;在Java中,单元通常指的是一个类;在图形化的软件中,单元可能指的是一个窗口或一个菜单等。总的来说,单元就是人为规定的最小的被测功能模块。

我们在需要单元测试的类中右键选择generate。

在这里插入图片描述

选择 Test。

在这里插入图片描述
在这里插入图片描述
当点击ok之后,就会生成一个单元测试代码:

package com.example.mybatis20231226.Mapper;import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;import static org.junit.jupiter.api.Assertions.*;@Slf4j
class UserInfoMapperTest {@BeforeEachvoid setUp() {}@AfterEachvoid tearDown() {}@Testvoid selectAll() {}
}

然后我们只需要完成单元测试中函数的实现的可以了。

package com.example.mybatis20231226.Mapper;import com.example.mybatis20231226.Model.UserInfo;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;import java.util.List;import static org.junit.jupiter.api.Assertions.*;@Slf4j
class UserInfoMapperTest {//通过@Autowired注解拿到Bean@Autowiredprivate UserInfoMapper userInfoMapper;@BeforeEachvoid setUp() {log.info("selectAll 执行之前");}@AfterEachvoid tearDown() {log.info("selectAll 执行之后");}@Testvoid selectAll() {List<UserInfo> list = userInfoMapper.selectAll();log.info(list.toString());}
}

当我们运行会发现,运行出现了问题:

在这里插入图片描述

为什么会出现这种错误呢?出现这种错误就是因为 Spring 环境没有正确启动。所以我们需要在类上加上类注解 @SpringBootTest 来为这个类加上 Spring 上下文管理。

@SpringBootTest
@Slf4j
class UserInfoMapperTest {
}
package com.example.mybatis20231226.Mapper;import com.example.mybatis20231226.Model.UserInfo;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.util.List;import static org.junit.jupiter.api.Assertions.*;@SpringBootTest
@Slf4j
class UserInfoMapperTest {@Autowiredprivate UserInfoMapper userInfoMapper;@BeforeEachvoid setUp() {log.info("selectAll 执行之前");}@AfterEachvoid tearDown() {log.info("selectAll 执行之后");}@Testvoid selectAll() {List<UserInfo> list = userInfoMapper.selectAll();log.info(list.toString());}
}

在这里插入图片描述

在这里插入图片描述
通过这种单元测试就达到了测试代码功能的作用,那么 MyBatis 的详细基础操作我就放在下一篇文章了。

相关文章:

【MyBatis】操作数据库——入门

文章目录 为什么要学习MyBatis什么是MyBatisMyBatis 入门创建带有MyBatis框架的SpringBoot项目数据准备在配置文件中配置数据库相关信息实现持久层代码单元测试 为什么要学习MyBatis 前面我们肯定多多少少学过 sql 语言&#xff0c;sql 语言是一种操作数据库的一类语言&#x…...

免费分享一套SpringBoot+Vue药店(药房)管理系统,帅呆了~~

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的SpringBootVue药店(药房)管理系统 &#xff0c;分享下哈。 项目视频演示 【免费】SpringBootVue药店(药房)管理系统 Java毕业设计_哔哩哔哩_bilibili【免费】SpringBootVue药店(药房)管理系统 Java毕业设计…...

视频怎么加水印?分享两个简单的加水印的方法

在数字媒体时代&#xff0c;视频已经成为信息传播的重要方式。许多人在创作视频是会加上自己独特的水印&#xff0c;防止视频被盗用。水印作为数字版权保护技术的一种&#xff0c;可以有效地防止视频被非法复制、传播或篡改&#xff0c;从而保护创作者的权益和利益。下面我分享…...

Apache Commons Collection3.2.1反序列化分析(CC1)

Commons Collections简介 Commons Collections是Apache软件基金会的一个开源项目&#xff0c;它提供了一组可复用的数据结构和算法的实现&#xff0c;旨在扩展和增强Java集合框架&#xff0c;以便更好地满足不同类型应用的需求。该项目包含了多种不同类型的集合类、迭代器、队…...

MySQL入门篇(10)-聚合函数的应用

MySQL数据库聚合函数的应用 在MySQL数据库中&#xff0c;聚合函数用于计算一组数据的统计值并返回结果。这些函数可以应用于查询语句中&#xff0c;对数据进行汇总、计数、平均值计算等操作。本文将介绍一些常用的MySQL聚合函数及其应用。 1. COUNT函数 COUNT函数用于计算指…...

Vue3基本概念

script部分 export default对象的属性&#xff1a; name&#xff1a;组件的名称 components&#xff1a;存储中用到的所有组件 props&#xff1a;存储父组件传递给子组件的数据 watch()&#xff1a;当某个数据发生变化时触发 computed&#xff1a;动态计算某个数据 setup(pro…...

每日OJ题_算法_模拟①_力扣1576. 替换所有的问号

目录 模拟算法原理 力扣1576. 替换所有的问号 解析代码 模拟算法原理 模拟算法是一种常用的计算机算法&#xff0c;它模拟了实际问题的运行过程&#xff0c;并通过数学模型来预测结果。模拟算法可以应用于各个领域&#xff0c;例如物理、化学、生物、计算机网络等等。 模拟算…...

杂题——试题 算法训练 区间最大和

分析&#xff1a; 如果使用两个for循环遍历所有情况&#xff0c;运行会超时解决运行超时的关键点在于&#xff1a;及时停止累加&#xff0c;丢弃当前的子序列 比如【1&#xff0c;-2&#xff0c;3&#xff0c;10】从第一个数字开始的子序列的和小于从第三个数字开始的子序列的和…...

(安卓)跳转应用市场APP详情页的方式

前言 最近在做一个需求&#xff0c;需要从自己APP进入到系统的应用市场 方便用户在应用市场给自己的APP打分 于是查阅了一些资料&#xff0c;下面说一下实现方法 实现方案 一般来说&#xff0c;最简单的方案就是这样&#xff1a; val uri Uri.parse("market://details…...

亚信安全助力宁夏首个人工智能数据中心建成 铺设绿色算力安全底座

近日&#xff0c;由宁夏西云算力科技有限公司倾力打造&#xff0c;亚信安全科技股份有限公司&#xff08;股票代码&#xff1a;688225&#xff09;全力支撑&#xff0c;总投资达数十亿元人民币的宁夏智算中心项目&#xff0c;其一期工程——宁夏首个采用全自然风冷技术的30KW机…...

ASP.NET Core WebAPI_解决跨域问题(前端后端)

说明 我的前端框架为Vue&#xff13; 前后端跨域选其一即可 前端跨域 在项目的根目录找到vite.config.js文件&#xff0c;添加代码&#xff1a; server: {proxy: {/api: {target: https://localhost:xxxx,changeOrigin: true,secure: false},},} axios代码片段&#xff1a; …...

保姆级的指针详解(超详细)

目录 一.内存和地址  1.初识指针 2.如何理解编址 二. 指针变量 三.指针的解引用操作符 1.指针变量的大小 四.指针变量类型的意义 五.指针的运算 1.指针加减整数 2.指针减指针 3.野指针 3.1指针未初始化 3.2指针越界访问 3.3指针指向的空间被提前释放 3.4如何规…...

R-YOLO

Abstract 提出了一个框架&#xff0c;名为R-YOLO&#xff0c;不需要在恶劣天气下进行注释。考虑到正常天气图像和不利天气图像之间的分布差距&#xff0c;我们的框架由图像翻译网络&#xff08;QTNet&#xff09;和特征校准网络&#xff08;FCNet&#xff09;组成&#xff0c;…...

Qt无边框窗口拖拽和阴影

先看下效果&#xff1a; 说明 自定义窗口控件的无边框,窗口事件由于没有系统自带边框,无法实现拖拽拉伸等事件的处理,一种方法就是重新重写主窗口的鼠标事件&#xff0c;一种时通过nativeEvent事件处理。重写事件相对繁琐,我们这里推荐nativeEvent处理。注意后续我们在做win平…...

ES6 Proxy详解

文章目录 概述Proxy 实例的方法get(target, propKey, receiver)set(target, propKey, value, receiver)has(target, propKey)deleteProperty(target, propKey)defineProperty(target, propKey, propDesc)getOwnPropertyDescriptor(target, propKey)getPrototypeOf(target)setPr…...

Prompt Learning 的几个重点paper

Prefix Tuning: Prefix-Tuning: Optimizing Continuous Prompts for Generation 在输入token之前构造一段任务相关的virtual tokens作为Prefix&#xff0c;然后训练的时候只更新Prefix部分的参数&#xff0c;PLM中的其他参数固定。针对自回归架构模型&#xff1a;在句子前面添…...

中科大计网学习记录笔记(三):接入网和物理媒体

前言&#xff1a; 学习视频&#xff1a;中科大郑烇、杨坚全套《计算机网络&#xff08;自顶向下方法 第7版&#xff0c;James F.Kurose&#xff0c;Keith W.Ross&#xff09;》课程 该视频是B站非常著名的计网学习视频&#xff0c;但相信很多朋友和我一样在听完前面的部分发现信…...

设计模式:工厂方法模式

工厂模式属于创建型模式&#xff0c;也被称为多态工厂模式&#xff0c;它在创建对象时提供了一种封装机制&#xff0c;将实际创建对象的代码与使用代码分离&#xff0c;有子类决定要实例化的产品是哪一个&#xff0c;把产品的实例化推迟到子类。 使用场景 重复代码 : 创建对象…...

HTML 相关知识点记录

<div> </div> DIV标签详细介绍-CSDN博客 div 是 division 的简写&#xff0c;division 意为分割、区域、分组。比方说&#xff0c;当你将一系列的链接组合在一起&#xff0c;就形成了文档的一个 division。 <p>标签&#xff1a;定义段落...

系统架构设计师考试大纲2023

一、 考试方式&#xff08;机考&#xff09; 考试采取科目连考、 分批次考试的方式&#xff0c; 连考的第一个科目作答结束交卷完成后自动进 入第二个科目&#xff0c; 第一个科目节余的时长可为第二个科目使用。 高级资格&#xff1a; 综合知识科目考试时长 150 分钟&#xff…...

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…...

Spark 之 入门讲解详细版(1)

1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室&#xff08;Algorithms, Machines, and People Lab&#xff09;开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目&#xff0c;8个月后成为Apache顶级项目&#xff0c;速度之快足见过人之处&…...

Debian系统简介

目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版&#xff…...

前端导出带有合并单元格的列表

// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...

spring:实例工厂方法获取bean

spring处理使用静态工厂方法获取bean实例&#xff0c;也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下&#xff1a; 定义实例工厂类&#xff08;Java代码&#xff09;&#xff0c;定义实例工厂&#xff08;xml&#xff09;&#xff0c;定义调用实例工厂&#xff…...

关于 WASM:1. WASM 基础原理

一、WASM 简介 1.1 WebAssembly 是什么&#xff1f; WebAssembly&#xff08;WASM&#xff09; 是一种能在现代浏览器中高效运行的二进制指令格式&#xff0c;它不是传统的编程语言&#xff0c;而是一种 低级字节码格式&#xff0c;可由高级语言&#xff08;如 C、C、Rust&am…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2

每日一言 今天的每一份坚持&#xff0c;都是在为未来积攒底气。 案例&#xff1a;OLED显示一个A 这边观察到一个点&#xff0c;怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 &#xff1a; 如果代码里信号切换太快&#xff08;比如 SDA 刚变&#xff0c;SCL 立刻变&#…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)

在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马&#xff08;服务器方面的&#xff09;的原理&#xff0c;连接&#xff0c;以及各种木马及连接工具的分享 文件木马&#xff1a;https://w…...

站群服务器的应用场景都有哪些?

站群服务器主要是为了多个网站的托管和管理所设计的&#xff0c;可以通过集中管理和高效资源的分配&#xff0c;来支持多个独立的网站同时运行&#xff0c;让每一个网站都可以分配到独立的IP地址&#xff0c;避免出现IP关联的风险&#xff0c;用户还可以通过控制面板进行管理功…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...