Java 、Springboot 连接整合 redis

news/2024/11/23 9:57:13/

1.  连 接  redis 

        默认有三种方式连接redis.

第一种:jedis---传统的项目--ssm

第二种:lettuce:---->刚出现没有多久就被springboot整合进来。

第三种:springboot连接redis

1.1  jedis操作redis服务器

(1)引入jedis依赖

 <dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>3.8.0</version></dependency>

 (2)编写相关的代码

string字符串命令:

 @Test//jedis连接public void test01(){//获取jedis对象Jedis jedis = new Jedis ("192.168.28.222",6379);//获取所有Set<String> keys = jedis.keys ("*");System.out.println (keys);//判断是否存在Boolean k1 = jedis.exists ("是否存在-----" + "k1");System.out.println (k1);//string类 型 测 试//存值String set = jedis.set ("k6", "wjj");System.out.println (set);//取值String k6 = jedis.get ("k6");System.out.println (k6);//删除Long k61 = jedis.del ("k6");System.out.println ("删除-----" + k61);//设置时间jedis.expire ("k2",60);//查看剩余时间Long k51 = jedis.ttl ("k2");System.out.println ("剩余" + k51);//测试是否存在Boolean k2 = jedis.exists ("k2");System.out.println ("是否存在" + k2);//存在不存,不存在直接存入Long k21 = jedis.setnx ("k6", "33");System.out.println ("k21------" + k21);//指定数值增加数值Long k63 = jedis.incrBy ("k6", 5);String k62 = jedis.get ("k6");System.out.println (k62);//指定数值减少Long k64 = jedis.decrBy ("k6", 6);String k55 = jedis.get ("k6");System.out.println (k55);jedis.close ();}

hash字段命令:

@Testpublic void test04(){//获取jedis对象Jedis jedis = new Jedis ("192.168.28.222",6379);//hash类型HashMap<String, String> hashMap = new HashMap<> ();hashMap.put ("name","wjjj");hashMap.put ("age","66");hashMap.put ("add","厕所");//存入数据Long k7 = jedis.hset ("k7----", hashMap);System.out.println (k7);//获取全部字段Map<String, String> k71 = jedis.hgetAll ("k7");System.out.println (k71);//获取所有字段Set<String> k72 = jedis.hkeys ("k7");System.out.println ("字段----" + k72);//获取所有值List<String> k73 = jedis.hvals ("k7");System.out.println ("值-----" + k73);//获取表中字段的数量Long k74 = jedis.hlen ("k7");System.out.println (k74);//获取所有给定字段的值List<String> hmget = jedis.hmget ("k7", "name", "age");System.out.println ("指定字段的值" + hmget);//只有在字段 field 不存在时,设置哈希表字段的值Long hsetnx = jedis.hsetnx ("k7", "sex", "男");System.out.println (hsetnx);//list队列Long lpush = jedis.lpush ("k8", "aa", "bb", "cc", "dd");List<String> k8 = jedis.lrange ("k8", 0, -1);System.out.println (k8);jedis.close ();}

list   列表命令:

@Testpublic void test05(){//获取jedis对象Jedis jedis = new Jedis ("192.168.28.222",6379);//list队列//添加数据Long lpush = jedis.lpush ("k8", "aa", "bb", "cc", "dd");//获取数据List<String> k8 = jedis.lrange ("k8", 0, -1);System.out.println ("元素----" + k8);//获取列表长度Long k81 = jedis.llen ("k8");System.out.println ("长度-----" + k81);//获取最后一个元素并移除String k82 = jedis.rpop ("k8");List<String> k9 = jedis.lrange ("k8", 0, -1);System.out.println ("元素剩余-----" + k9);//通过索引获取列表中的元素String k83 = jedis.lindex ("k8", 4);System.out.println ("第五个数据" + k83);jedis.close ();}

set列表命令:

@Testpublic void test06(){//获取jedis对象Jedis jedis = new Jedis ("192.168.28.222",6379);// set  集合//添加数据Long sadd = jedis.sadd ("k9", "aa", "bb", "cc", "dd", "ee");Long sadd1 = jedis.sadd ("k10", "aa", "bb", "cc", "gg", "ll");System.out.println ("添加数据" + sadd);//取数据Set<String> k9 = jedis.smembers ("k9");System.out.println ("取数据" + k9);//取出交集Set<String> sinter = jedis.sinter ("k9", "k10");System.out.println ("交集" + sinter);//返回给定所有集合的差集Set<String> sdiff = jedis.sdiff ("k9", "k10");System.out.println ("差集" + sdiff);jedis.close ();}

sort  set 有序集合命令:

@Testpublic void test07(){//获取jedis对象Jedis jedis = new Jedis ("192.168.28.222",6379);//  sort  set  集合//添加数据HashMap<String, Double> hashMap = new HashMap<> ();hashMap.put ("yw",99.0);hashMap.put ("sx",88.0);hashMap.put ("yy",65.0);hashMap.put ("ls",69.0);hashMap.put ("hx",85.0);Long k11 = jedis.zadd ("k11", hashMap);System.out.println (k11);//返回区间之内的Set<String> k111 = jedis.zrange ("k11", 0, -1);System.out.println ("返回" + k111);//返回有序集合中指定成员的排名,有序集成员按分数值递减Long zrevrank = jedis.zrevrank ("k11", "ls");System.out.println ("排名" + zrevrank);//获取有序集合的成员数Long k112 = jedis.zcard ("k11");System.out.println ("成员数" + k112);//返回有序集中指定区间内的成员,通过索引,分数从高到底Set<String> k113 = jedis.zrevrange ("k11", 0, -1);System.out.println ("分数" + k113);jedis.close ();}

1.2 .测试jedis使用和不使用连接池的效率

配置连接池

@Testpublic void test02(){//连接池的配置信息JedisPoolConfig jedisPoolConfig = new JedisPoolConfig ();jedisPoolConfig.setMaxTotal (10);//最大连接个数jedisPoolConfig.setMinIdle (2);//最小空闲时间jedisPoolConfig.setMaxIdle (10);//最大空闲时间jedisPoolConfig.setTestOnBorrow (true);//在连接对象时验证是否有联通性JedisPool jedisPool = new JedisPool (jedisPoolConfig,"192.168.28.222",6379);Jedis jedis = jedisPool.getResource ();//清空当前库jedis .flushDB ();String k5 = jedis.set ("k5", "55");String k51 = jedis.get ("k5");System.out.println (k51);jedis.close ();//归还连接池}

(1.)  不使用连接池

(2.)使用连接池

结论:使用连接池 比没用要快很多

2. springboot 整合redis

        springboot在整合redis时提高两个模板类,StringRedisTemplate和RedisTemplate.以后对redis的操作都在该模板类中。StringRedisTemplate是RedisTemplate的子类。

2.1 导入依赖

<!--redis相关依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency>

2.2 修改配置文件

#redis的配置信息
spring.redis.host=192.168.28.222
spring.redis.port=6379#最多获取数
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-wait=-1ms
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0

2.3 添加配置类

RedisTemplate

        它是StringRedisTemplate的父类,它类可以存储任意数据类型,但是任意类型必须序列化,默认采用的是jdk的序列化方式。jdk序列化方式阅读能力差,而且占用空间大. 我们在使用是一般需要人为指定序列化方式。

package com.dxh;import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;/*** @program: redis* @author: ♥丁新华* @create: 2023-04-24 16:17**/
@Configuration
public class RedisConfig {//比如验证码@Bean //该方法的返回对象交于spring容器管理public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template = new RedisTemplate<>();RedisSerializer<String> redisSerializer = new StringRedisSerializer ();Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);ObjectMapper om = new ObjectMapper ();om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(om);template.setConnectionFactory(factory);//key序列化方式template.setKeySerializer(redisSerializer);//value序列化template.setValueSerializer(jackson2JsonRedisSerializer);//key hashmap序列化template.setHashKeySerializer (redisSerializer);//value hashmap序列化template.setHashValueSerializer(jackson2JsonRedisSerializer);return template;}
}

2.4 测  试 

(1 )关于key的方法

@SpringBootTest
class RedisApplicationTests {//因为springboot整合redis时会把StringRedisTemplate创建并交于spring容器管理@Autowiredprivate StringRedisTemplate redisTemplate;@Testvoid contextLoads() {//关于key的方法//获取所有keySet<String> keys = redisTemplate.keys ("*");System.out.println (keys);//判断key是否存在Boolean k1 = redisTemplate.hasKey ("k1");System.out.println (k1);//删除指定keyBoolean k11 = redisTemplate.delete ("k1");System.out.println (k11);//设置过期时间Boolean k12 = redisTemplate.expire ("k1", 60, TimeUnit.MILLISECONDS);//获取还剩多少时间redisTemplate.getExpire ("k1");}}

(2.) 关于字符串的操作

@SpringBootTest
class RedisApplicationTests3 {//因为springboot整合redis时会把StringRedisTemplate创建并交于spring容器管理@Autowiredprivate StringRedisTemplate redisTemplate;@Testvoid contextLoads() {//操作字符串//操作字符串===StringRedisTemplate会把对每一种数据的操作单独封装成一个类ValueOperations<String, String> s1 = redisTemplate.opsForValue ();//添加数据s1.set ("k1","33");s1.set ("k2","44");//获取数据  getString k12 = s1.get ("k1");System.out.println ("k1-----" + k12);//判断是否存入成功  setIfAbsentBoolean aBoolean = s1.setIfAbsent ("k2", "wjj");System.out.println ("是否----" + aBoolean);//增加指定时间  incrementLong k3 = s1.increment ("k3", 20);System.out.println ("k3---" + k3);//减少指定时间  decrementLong k31 = s1.decrement ("k3", 10);System.out.println ("k3----" + k31);ArrayList<String> list = new ArrayList<> ();list.add ("k1");list.add ("k2");list.add ("k3");//获取多个  multiGetList<String> list1 = s1.multiGet (list);System.out.println ("多个----" + list1);//判断是否存在,Boolean k6 = s1.setIfPresent ("k6", "22");System.out.println ("成功是否----" + k6);//获取原值同时设置新值【getset】String andSet = s1.getAndSet ("k2", "ghj");System.out.println ("同步----" + andSet);}}

3.   操作 hash 值

@SpringBootTest
class RedisApplicationTests4 {//因为springboot整合redis时会把StringRedisTemplate创建并交于spring容器管理@Autowiredprivate StringRedisTemplate redisTemplate;@Testvoid contextLoads() {// 操作hash方法HashOperations<String, Object, Object> s2 = redisTemplate.opsForHash ();// HashOperations<String, Object, Object> forHash = redisTemplate.opsForHash();// 向其中添加数据s2.put("k1","name","平家祥");s2.put("k1","age","16");s2.put("k1","sex","男");// 获取值  valuesList<Object> k1 = s2.values ("k1");System.out.println ("值---" + k1);//  获取变量中的键值对 entriesMap<Object, Object> k11 = s2.entries ("k1");System.out.println ("键值对---" + k11);//通过hasKey(H key, Object hashKey)方法判断变量中是否存在map键Boolean k12 = s2.hasKey ("k1", "22");System.out.println ("通过hasKey(H key, Object hashKey)方法判断变量中是否存在map键---" + k12);//keys 获取变量中的键Set<Object> k13 = s2.keys ("k1");System.out.println ("变量中的键----" + k13);//获取长度Long k14 = s2.size ("k1");System.out.println ("长度----" + k14);}}

4. 操作  list  

@SpringBootTest
class RedisApplicationTests5 {//因为springboot整合redis时会把StringRedisTemplate创建并交于spring容器管理@Autowiredprivate StringRedisTemplate redisTemplate;@Testvoid contextLoads() {//操作list集合方法ListOperations<String, String> s3 = redisTemplate.opsForList ();//左侧添加数据Long k1 = s3.leftPush ("k1", "22");System.out.println ("左侧添加---" + k1);//右侧添加数据Long k2 = s3.rightPush ("k2", "33");System.out.println ("左侧添加---" + k2);//获取元素String k11 = s3.index ("k1", 0);System.out.println ("元素----" + k11);//范围查找List<String> k12 = s3.range ("k1", 0, -1);System.out.println ("范围查找" + k12);//列表长度Long k13 = s3.size ("k1");System.out.println ("长度" + k13);}}

5. set 集合

@SpringBootTest
class RedisApplicationTests6 {//因为springboot整合redis时会把StringRedisTemplate创建并交于spring容器管理@Autowiredprivate StringRedisTemplate redisTemplate;@Testvoid contextLoads() {//操作set集合方法SetOperations<String, String> s4 = redisTemplate.opsForSet ();//添加元素Long k1 = s4.add ("k1", "22", "33", "44", "55");Long k66 = s4.add ("k2", "22", "66", "44", "58");//移除Long k11 = s4.remove ("k1", "22");System.out.println ("移除----" + k11);//集合大小Long k12 = s4.size ("k1");System.out.println ("集合大小-----" + k12);//判断是否存在Boolean k13 = s4.isMember ("k1", "33");System.out.println ("是否存在----" + k13);//随机获取一个元素String k14 = s4.randomMember ("k1");System.out.println ("随机元素-----" + k14);//获取两个交集Set<String> intersect = s4.intersect ("k1", "k2");System.out.println ("交集---" + intersect);}}

6. zset 有序集合

@SpringBootTest
class RedisApplicationTests7 {//因为springboot整合redis时会把StringRedisTemplate创建并交于spring容器管理@Autowiredprivate StringRedisTemplate redisTemplate;@Testvoid contextLoads() {//操作zSet有序集合方法ZSetOperations<String, String> s6 = redisTemplate.opsForZSet ();//添加元素s6.add ("k1","english",88.0);s6.add ("k1","math",66.0);s6.add ("k1","history",86.0);//获取元素Set<String> k1 = s6.range ("k1", 0, -1);System.out.println ("元素---" + k1);//获取指定范围Set<String> k11 = s6.range ("k1", 0, -1);System.out.println ("指定范围---" + k11);//指定元素增加指定值Double aDouble = s6.incrementScore ("k1", "math", 22.0);System.out.println ("增加---" + aDouble);//获取对应key和value的scoreDouble score = s6.score ("k1", "english");System.out.println ("获取对应key和value的score" + score);}}

3. springboot连接集群

3.1 配置文件

spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-wait=-1ms
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0# 设置redis重定向的次数---根据主节点的个数
spring.redis.cluster.max-redirects=3spring.redis.cluster.nodes=192.168.28.222:7001,192.168.28.222:7002,192.168.28.222:7003,\192.168.28.222:7004,192.168.28.222:7005,192.168.28.222:7006

3.2 连接多个端口

3.3 添加数据

@SpringBootTest
class RedisApplicationTests8 {//因为springboot整合redis时会把StringRedisTemplate创建并交于spring容器管理@Autowiredprivate RedisTemplate redisTemplate;@Testvoid contextLoads() {ValueOperations vs = redisTemplate.opsForValue ();vs.set ("k2","55");}}

 

3.4 测试

 

4. redis的应用场景

(1.) 缓存原理

 

(2)缓存的作用:

用缓存,主要有两个用途:高性能、高并发。

高性能

假设这么个场景,你有个操作,一个请求过来,吭哧吭哧你各种乱七八糟操作 mysql,半天查出来一个结果,耗时 600ms。但是这个结果可能接下来几个小时都不会变了,或者变了也可以不用立即反馈给用户。那么此时咋办?

缓存啊,折腾 600ms 查出来的结果,扔缓存里,一个 key 对应一个 value,下次再有人查,别走 mysql 折腾 600ms 了,直接从缓存里,通过一个 key 查出来一个 value,2ms 搞定。性能提升 300 倍。

就是说对于一些需要复杂操作耗时查出来的结果,且确定后面不怎么变化,但是有很多读请求,那么直接将查询出来的结果放在缓存中,后面直接读缓存就好。

高并发

mysql 这么重的数据库,压根儿设计不是让你玩儿高并发的,虽然也可以玩儿,但是天然支持不好。mysql 单机支撑到 2000QPS 也开始容易报警了。

所以要是你有个系统,高峰期一秒钟过来的请求有 1万,那一个 mysql 单机绝对会死掉。你这个时候就只能上缓存,把很多数据放缓存,别放 mysql。缓存功能简单,说白了就是 key-value 式操作,单机支撑的并发量轻松一秒几万十几万,支撑高并发 so easy。单机承载并发量是 mysql 单机的几十倍。
 

(3)什么样的数据适合放入缓存

1.数据量不大

2.访问频率高

3.数据更改频率低

(4)如何使用缓存

1. 导入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.12.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.example</groupId><artifactId>redis-springboot01</artifactId><version>0.0.1-SNAPSHOT</version><name>redis-springboot01</name><description>redis-springboot01</description><properties><java.version>8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- mysql --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.3.1</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build></project>

2. 配置文件

server.port=8888spring.datasource.url=jdbc:mysql:///student
spring.datasource.password=root
spring.datasource.username=abc123
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Drivermybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl#redis的配置信息
spring.redis.host=192.168.28.222
spring.redis.port=6379
#最多获取数
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-wait=-1ms
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0

3. 编写mapper层

@Mapper
public interface StudentMapper extends BaseMapper<Student>{}

4. 编写service层

public interface StudentService {/*** 根据ID查询* @param id* @return*/Student findById (Integer id);
}

5. 服务层

@Service
public class StudentServiceimpl implements StudentService {@Resourceprivate StudentMapper studentMapper;@Autowiredprivate RedisTemplate<String,Object> redisTemplate;@Overridepublic Student findById(Integer id) {ValueOperations<String, Object> forValue = redisTemplate.opsForValue();//1.查询缓存Object o = forValue.get("dept::" + id);//判断if(o!=null){ //证明缓存里边有//返回数据return (Student) o;}//调用方法Student student = studentMapper.selectById(id);//查询之后直接放入缓存if(student!=null){forValue.set("student::"+id,student);}return student;}}

6. controller  层

/*** @program: redis-springboot01* @author: ♥丁新华* @create: 2023-04-25 11:20**/
@RestController
public class StudentController {@Resourceprivate StudentService studentService;//restful风格@GetMapping("b/{id}")public Student findById(@PathVariable Integer id){return studentService.findById (id);}}

7. 测  试

 

控制台会查询数据库:

 

因为使用了缓存机制,再次访问的话会走缓存,不会再去访问数据库,可以释放一定的压力,

 


http://www.ppmy.cn/news/557189.html

相关文章

K短路

其实这个才是最短路的一个非常好的应用。那么下面我们就来讲一讲具体如何实现吧。 先确保自己已经熟练掌握了两种最短路的求解方法&#xff01;&#xff01;&#xff01; 这里有传送门&#xff1a; 1、SPFA 2、Dijsktra priority&#xff01; 然后我们先大体讲一讲思路&am…

寒假集训D3.22.12.31

Day3 K.61外边距特性 1.垂直方向上&#xff0c;外边距取最大值 2.水平方向&#xff0c;外边距合并处理 3.父子嵌套边距&#xff08;子元素与上有间距&#xff09; 1&#xff09;margin换padding 2&#xff09;父盒子设置边框 3&#xff09;加浮动…

3.springboot连接redis并完成缓存操作

目录&#xff1a; 1. java连接redis 2. springboot连接redis操作。 3. 完成缓存操作 默认有三种方式连接redis. 第一种:jedis---传统的项目--ssm 第二种:lettuce:---->刚出现没有多久就被springboot整合进来。 第三种:springboot连接redis 1 jedis操作redis服务器 &am…

AutoSAR系列讲解(入门篇)2.2-SWC的类型(APPL)

SWC的类型 一、原子级的SWC&#xff08;Atomic SWC&#xff09; 二、集合级的SWC&#xff08;Composition SWC&#xff09; 三、特殊的SWC 一、原子级的SWC&#xff08;Atomic SWC&#xff09; 原子级的SWC&#xff08;Atomic SWC&#xff09;&#xff1a;故名思意&#xff…

全国大学生网络安全精英赛练习题

1、某公司技术人员利于自己的技术入侵了某电商数据库&#xff0c;将其中的用户数据下载后在暗网中进行售卖&#xff0c;该行为的处置最适用的是以下那部法律?&#xff08;&#xff09; A.刑法 B.网络安全法 C.电子签名法 D.劳动法 正确答案&#xff1a;A 解析&#xff1a;入侵…

SSDB:高性能数据库服务器

SSDB&#xff1a;高性能数据库服务器 - 张善友 SSDB是一个开源的高性能数据库服务器, 使用Google LevelDB作为存储引擎, 支持T级别的数据, 同时支持类似Redis中的zset和hash等数据结构, 在同时需求高性能和大数据的条件下, 作为Redis的替代方案. 因为SSDB的最初目的是替代Redi…

开启你的大神之路-Android优质学习资源、项目和网站大整合(Android学习以来的全面资料整理)...

大神之路-Android优质学习资源和项目大整合 Android非常不错的学习资源、项目和网站其实非常多&#xff0c;但是大部分计较不集中&#xff0c;不利于新手对Android的学习和整体把握。今天刚好有空&#xff0c;把自己学习Android以来熟悉的和平时常访问的网站资料做一下整理&…

大神之路-Android优质资源和项目大整合

&#xfeff;&#xfeff; 大神之路-Android优质资源和项目大整合 分享知识 分享快乐. Android非常不错的学习资源、项目和网站其实非常多&#xff0c;但是大部分计较不集中&#xff0c;不利于新手对Android的学习和整体把握。今天刚好有空&#xff0c;把自己学习Android以来…