一、Redis介绍

Redis 是一个高性能的key-value数据格式的内存缓存,NoSQL数据库。NOSQL:not only sql,泛指非关系型数据库。关系型数据库: (mysql, oracle, sql server, sqlite)

  1. 1. 数据存放在表中,表之间有关系。
  2. 2. 通用的SQL操作语言。
  3. 3. 大部分支持事务。

非关系型数据库[ redis,hadoop,mangoDB]:

  1. 1. 没有数据表的概念,不同的nosql数据库存放数据位置不同。
  2. 2. nosql数据库没有通用的操作语言。
  3. 3. 基本不支持事务。 redis支持简单事务

redis是业界主流的key-value nosql 数据库之一。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。redis是一款基于CS架构的数据库,所以redis有客户端,也有服务端。其中,客户端可以使用python等编程语言,也可以终端命令行工具

Redis优点

  • 异常快速 : Redis是非常快的,每秒可以执行大约110000设置操作,81000个/每秒的读取操作。
  • 支持丰富的数据类型 : Redis支持最大多数开发人员已经知道如列表,集合,可排序集合,哈希等数据类型。
  • 原子 – Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
  • Redis是一个多功能实用工具,可以在很多如,消息传递队列中使用(Redis原生支持发布/订阅)
  • 单线程特性,秒杀系统,基于redis是单线程特征,防止出现数据库“爆破”

redis的典型应用

(一)性能

Redis 中缓存热点数据,能够保护数据库,提高查询效率。如下图所示,我们在碰到需要执行耗时特别久,且结果不频繁变动的SQL,就特别适合将运行结果放入缓存。这样,后面的请求就去缓存中读取,使得请求能够迅速响应。


(二)并发

还是如上图所示,在大并发的情况下,所有的请求直接访问数据库,数据库会出现连接异常。这个时候,就需要使用redis做一个缓冲操作,让请求先访问到redis,而不是直接访问数据库。

安装Redis环境

要在 Ubuntu 上安装 Redis,打开终端,然后输入以下命令:
  1. $sudo apt-get update
  2. $sudo apt-get install redis-server
这将在您的计算机上安装Redis

启动 Redis

  1. $redis-server

查看 redis 是否还在运行

  1. $redis-cli
这将打开一个 Redis 提示符,如下图所示:
  1. redis 127.0.0.1:6379>
在上面的提示信息中:127.0.0.1 是本机的IP地址,6379是 Redis 服务器运行的端口。现在输入 PING 命令,如下图所示:
  1. redis 127.0.0.1:6379> ping
  2. PONG
这说明现在你已经成功地在计算机上安装了 Redis。

二、Python操作Redis

redis-py 的API的使用可以分类为:

  • 连接方式
  • 操作
    1. String 操作
    2. Hash 操作
    3. List 操作
    4. Set 操作
    5. Sort Set 操作
  • 管道
  • 发布订阅

2.1、连接方式

1、操作模式

redis-py提供两个类Redis和StrictRedis用于实现Redis的命令,StrictRedis用于实现大部分官方的命令,并使用官方的语法和命令,Redis是StrictRedis的子类,用于向后兼容旧版本的redis-py。

  1. import redis
  2.  
  3. r = redis.Redis(host='10.211.55.4', port=6379)
  4. r.set('foo', 'Bar')
  5. print r.get('foo')

2、连接池

redis-py使用connection pool来管理对一个redis server的所有连接,避免每次建立、释放连接的开销。默认,每个Redis实例都会维护一个自己的连接池。可以直接建立一个连接池,然后作为参数Redis,这样就可以实现多个Redis实例共享一个连接池。

  1. import redis
  2.  
  3. pool = redis.ConnectionPool(host='10.211.55.4', port=6379)
  4. r = redis.Redis(connection_pool=pool)
  5. r.set('foo', 'Bar')
  6. print r.get('foo')

2.2、操作

  1. 1. string类型:
  2. 字符串类型是 Redis 中最为基础的数据存储类型,它在 Redis 中是二进制安全的,也就是byte类型
  3. 最大容量是512M
  4. 2. hash类型:
  5. hash用于存储对象,对象的结构为属性、值,值的类型为string
  6. key:{
  7. 域:值[这里的值只能是字符串],
  8. 域:值,
  9. 域:值,
  10. 域:值,
  11. ...
  12. }
  13. 3. list类型:
  14. 列表的元素类型为string
  15. key:[ 1,值2,值3..... ]
  16. 4. set类型:
  17. 无序集合,元素为string类型,元素唯一不重复,没有修改操作。
  18. {值1,值4,值3,值5}
  19. 5. zset类型:
  20. 有序集合,元素为string类型,元素唯一不重复,没有修改操作。

2.2.1、String 操作

redis中的String在在内存中按照一个name对应一个value来存储。如图:

set(name, value, ex=None, px=None, nx=False, xx=False)

  1. Redis中设置值,默认,不存在则创建,存在则修改
  2. 参数:
  3. ex,过期时间(秒)
  4. px,过期时间(毫秒)
  5. nx,如果设置为True,则只有name不存在时,当前set操作才执行
  6. xx,如果设置为True,则只有name存在时,岗前set操作才执行

setnx(name, value)

  1. 设置值,只有name不存在时,执行设置操作(添加)

setex(name, value, time)

  1. # 设置值
  2. # 参数:
  3. # time,过期时间(数字秒 或 timedelta对象)

psetex(name, time_ms, value)

  1. # 设置值
  2. # 参数:
  3. # time_ms,过期时间(数字毫秒 或 timedelta对象)

mset(*args, **kwargs)

  1. 批量设置值
  2. 如:
  3. mset(k1='v1', k2='v2')

  4. mget({'k1': 'v1', 'k2': 'v2'})

get(name)

  1. 获取值

mget(keys, *args)

  1. 批量获取
  2. 如:
  3. mget('ylr', 'wupeiqi')

  4. r.mget(['ylr', 'wupeiqi'])

getset(name, value)

  1. 设置新值并获取原来的值

getrange(key, start, end)

  1. # 获取子序列(根据字节获取,非字符)
  2. # 参数:
  3. # name,Redis 的 name
  4. # start,起始位置(字节)
  5. # end,结束位置(字节)

setrange(name, offset, value)

  1. # 修改字符串内容,从指定字符串索引开始向后替换(新值太长时,则向后添加)
  2. # 参数:
  3. # offset,字符串的索引,字节(一个汉字三个字节)
  4. # value,要设置的值

strlen(name)

  1. # 返回name对应值的字节长度(一个汉字3个字节)

incr(self, name, amount=1)

  1. # 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
  2.  
  3. # 参数:
  4. # name,Redis的name
  5. # amount,自增数(必须是整数)
  6.  
  7. # 注:同incrby

incrbyfloat(self, name, amount=1.0)

  1. # 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。
  2.  
  3. # 参数:
  4. # name,Redis的name
  5. # amount,自增数(浮点型)

decr(self, name, amount=1)

  1. # 自减 name对应的值,当name不存在时,则创建name=amount,否则,则自减。
  2.  
  3. # 参数:
  4. # name,Redis的name
  5. # amount,自减数(整数)

append(key, value)

  1. # 在redis name对应的值后面追加内容
  2.  
  3. # 参数:
  4. key, redisname
  5. value, 要追加的字符串

2.2.2、Hash 操作

hash表现形式上有些像pyhton中的dict,可以存储一组关联性较强的数据 , redis中Hash在内存中的存储格式如下图:  

hset(name, key, value)

  1. # name对应的hash中设置一个键值对(不存在,则创建;否则,修改)
  2.  
  3. # 参数:
  4. # name,redis的name
  5. # key,name对应的hash中的key
  6. # value,name对应的hash中的value
  7.  
  8. # 注:
  9. # hsetnx(name, key, value),当name对应的hash中不存在当前key时则创建(相当于添加)

hmset(name, mapping)

  1. # 在name对应的hash中批量设置键值对
  2.  
  3. # 参数:
  4. # name,redis的name
  5. # mapping,字典,如:{'k1':'v1', 'k2': 'v2'}
  6.  
  7. # 如:
  8. # r.hmset('xx', {'k1':'v1', 'k2': 'v2'})

hget(name,key)

  1. # 在name对应的hash中获取根据key获取value

hmget(name, keys, *args)

  1. # 在name对应的hash中获取多个key的值
  2.  
  3. # 参数:
  4. # name,reids对应的name
  5. # keys,要获取key集合,如:['k1', 'k2', 'k3']
  6. # *args,要获取的key,如:k1,k2,k3
  7.  
  8. # 如:
  9. # r.mget('xx', ['k1', 'k2'])
  10. # 或
  11. # print r.hmget('xx', 'k1', 'k2')

hgetall(name)

  1. # 获取name对应hash的所有键值

hlen(name) 

  1. # 获取name对应的hash中键值对的个数

hkeys(name)

  1. # 获取name对应的hash中所有的key的值

hvals(name)

  1. # 获取name对应的hash中所有的value的值

hexists(name, key)

  1. # 检查name对应的hash是否存在当前传入的key

hdel(name,*keys)

  1. # 将name对应的hash中指定key的键值对删除

hincrby(name, key, amount=1)

  1. # 自增name对应的hash中的指定key的值,不存在则创建key=amount
  2. # 参数:
  3. # name,redis中的name
  4. # key, hash对应的key
  5. # amount,自增数(整数)

hincrbyfloat(name, key, amount=1.0)

  1. # 自增name对应的hash中的指定key的值,不存在则创建key=amount
  2.  
  3. # 参数:
  4. # name,redis中的name
  5. # key, hash对应的key
  6. # amount,自增数(浮点数)
  7.  
  8. # 自增name对应的hash中的指定key的值,不存在则创建key=amount

hscan_iter(name, match=None, count=None)

  1. # 利用yield封装hscan创建生成器,实现分批去redis中获取数据
  2.  
  3. # 参数:
  4. # match,匹配指定key,默认None 表示所有的key
  5. # count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数
  6.  
  7. # 如:
  8. # for item in r.hscan_iter('xx'):
  9. # print item

2.2.3、List 操作

List操作,redis中的List在在内存中按照一个name对应一个List来存储。如图:  

lpush(name,values)

  1. # 在name对应的list中添加元素,每个新的元素都添加到列表的最左边
  2.  
  3. # 如:
  4. # r.lpush('oo', 11,22,33)
  5. # 保存顺序为: 33,22,11
  6.  
  7. # 扩展:
  8. # rpush(name, values) 表示从右向左操作

lpushx(name,value)

  1. # 在name对应的list中添加元素,只有name已经存在时,值添加到列表的最左边
  2.  
  3. # 更多:
  4. # rpushx(name, value) 表示从右向左操作

llen(name)

  1. # name对应的list元素的个数

linsert(name, where, refvalue, value))

  1. # 在name对应的列表的某一个值前或后插入一个新值
  2.  
  3. # 参数:
  4. # name,redis的name
  5. # where,BEFORE或AFTER
  6. # refvalue,标杆值,即:在它前后插入数据
  7. # value,要插入的数据

r.lset(name, index, value)

  1. # 对name对应的list中的某一个索引位置重新赋值
  2.  
  3. # 参数:
  4. # name,redis的name
  5. # index,list的索引位置
  6. # value,要设置的值

r.lrem(name, value, num) 

  1. # 在name对应的list中删除指定的值
  2.  
  3. # 参数:
  4. # name,redis的name
  5. # value,要删除的值
  6. # num, num=0,删除列表中所有的指定值;
  7. # num=2,从前到后,删除2个;
  8. # num=-2,从后向前,删除2个

lpop(name)

  1. # 在name对应的列表的左侧获取第一个元素并在列表中移除,返回值则是第一个元素
  2.  
  3. # 更多:
  4. # rpop(name) 表示从右向左操作

lindex(name, index)

  1. # 在name对应的列表中根据索引获取列表元素

lrange(name, start, end)

  1. # 在name对应的列表分片获取数据
  2. # 参数:
  3. # name,redis的name
  4. # start,索引的起始位置
  5. # end,索引结束位置

ltrim(name, start, end)

  1. # 在name对应的列表中移除没有在start-end索引之间的值
  2. # 参数:
  3. # name,redis的name
  4. # start,索引的起始位置
  5. # end,索引结束位置

2.2.4、Set 操作

Set操作,Set集合就是不允许重复的列表

sadd(name,values)

  1. # name对应的集合中添加元素

scard(name)

  1. # 获取name对应的集合中元素个数

sdiff(keys, *args)

  1. # 在第一个name对应的集合中且不在其他name对应的集合的元素集合

sinter(keys, *args)

  1. # 获取多一个name对应集合的交集

sismember(name, value)

  1. # 检查value是否是name对应的集合的成员

smembers(name)

  1. # 获取name对应的集合的所有成员

spop(name)

  1. # 从集合中随机移除一个成员,并将其返回

srandmember(name, numbers)

  1. # 从name对应的集合中随机获取 numbers 个元素

srem(name, values)

  1. # 在name对应的集合中删除某些值

sunion(keys, *args)

  1. # 获取多一个name对应的集合的并集

sscan_iter(name, match=None, count=None)

  1. # 同字符串的操作,用于增量迭代分批获取元素,避免内存消耗太大

2.2.5、Sort Set 操作

有序集合,在集合的基础上,为每元素排序;元素的排序需要根据另外一个值来进行比较,所以,对于有序集合,每一个元素有两个值,即:值和分数,分数专门用来做排序。

zadd(name, *args, **kwargs)

  1. # 在name对应的有序集合中添加元素
  2. # 如:print(r.zadd("zz",{"n1":1,"n2":2,"n3":3,"n4":4}))
  3.  
  4. # 查看:print(r.zscan("zz"))

zcard(name)

  1. # 获取name对应的有序集合元素的数量

zcount(name, min, max)

  1. # 获取name对应的有序集合中分数 在 [min,max] 之间的个数

zincrby(name, value, amount)

  1. # 自增name对应的有序集合的 name 对应的分数

zrange( name, start, end, desc=False, withscores=False, score_cast_func=float)

  1. # 按照索引范围获取name对应的有序集合的元素
  2. aa=r.zrange("zset_name",0,1,desc=False,withscores=True,score_cast_func=int)
  3. print(aa)
  4. '''参数:
  5. name redis的name
  6. start 有序集合索引起始位置
  7. end 有序集合索引结束位置
  8. desc 排序规则,默认按照分数从小到大排序
  9. withscores 是否获取元素的分数,默认只获取元素的值
  10. score_cast_func 对分数进行数据转换的函数'''

zscore(name, value)

  1. #获取name对应有序集合中 value 对应的分数

zrank(name, value)

  1. # 获取某个值在 name对应的有序集合中的排行(从 0 开始)
  2.  
  3. # 更多:
  4. # zrevrank(name, value),从大到小排序

zrem(name, values)

  1. # 删除name对应的有序集合中值是values的成员
  2.  
  3. # 如:zrem('zz', ['s1', 's2'])

zremrangebyrank(name, min, max)

  1. # 根据排行范围删除

zremrangebyscore(name, min, max)

  1. # 根据分数范围删除

zinterstore(dest, keys, aggregate=None)

  1. # 获取两个有序集合的交集,如果遇到相同值不同分数,则按照aggregate进行操作
  2. # aggregate的值为: SUM MIN MAX

zunionstore(dest, keys, aggregate=None)

  1. # 获取两个有序集合的并集,如果遇到相同值不同分数,则按照aggregate进行操作
  2. # aggregate的值为: SUM MIN MAX

2.2.6、其他常用操作

delete(*names)

  1. # 根据删除redis中的任意数据类型

exists(name)

  1. # 检测redis的name是否存在

keys(pattern='*')

  1. # 根据模型获取redis的name
  2.  
  3. # 更多:
  4. # KEYS * 匹配数据库中所有 key 。
  5. # KEYS h?llo 匹配 hello , hallo 和 hxllo 等。
  6. # KEYS h*llo 匹配 hllo 和 heeeeello 等。
  7. # KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo

expire(name ,time)

  1. # 为某个redis的某个name设置超时时间

rename(src, dst)

  1. # 对redis的name重命名为

randomkey()

  1. # 随机获取一个redis的name(不删除)

type(name)

  1. # 获取name对应值的类型

scan_iter(match=None, count=None)

  1. # 同字符串操作,用于增量迭代获取key

2.2.7、使用场景

针对各种数据类型使用场景如下:

(一)String

这个其实没啥好说的,最常规的set/get操作,value可以是String也可以是数字。一般做一些复杂的计数功能的缓存,比如减少库存。

(二)hash

这里value存放的是结构化的对象,比较方便的就是操作其中的某个字段。博主在做单点登录的时候,就是用这种数据结构存储用户信息,以cookieId作为key,设置30分钟为缓存过期时间,能很好的模拟出类似session的效果。

(三)list

使用List的数据结构,可以做简单的消息队列的功能。另外还有一个就是,可以利用lrange命令,做基于redis的分页功能,性能极佳,用户体验好。本人还用一个场景,很合适---取行情信息。就也是个生产者和消费者的场景。LIST可以很好的完成排队,先进先出的原则。

(四)set

因为set堆放的是一堆不重复值的集合。所以可以做全局去重的功能。

另外,就是利用交集、并集、差集等操作,可以计算共同喜好,全部的喜好,自己独有的喜好等功能。

(五)sorted set

sorted set多了一个权重参数score,集合中的元素能够按score进行排列。可以做排行榜应用,取TOP N操作。

2.3、管道

redis-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pipline实现一次请求指定多个命令,并且默认情况下一次pipline 是原子性操作。

  1. import redis
  2.  
  3. pool = redis.ConnectionPool(host='10.211.55.4', port=6379)
  4. r = redis.Redis(connection_pool=pool)
  5. # pipe = r.pipeline(transaction=False)
  6. pipe = r.pipeline(transaction=True)
  7.  
  8. pipe.set('name', 'alex')
  9. pipe.set('role', 'sb')
  10.  
  11. pipe.execute()

2.4、发布订阅

订阅者:

  1. import redis
  2.  
  3. r=redis.Redis(host='127.0.0.1')
  4. pub=r.pubsub()
  5.  
  6. pub.subscribe("fm104.5")
  7. pub.parse_response()
  8.  
  9. while 1:
  10. msg = pub.parse_response()
  11. print(msg)  

发布者:

  1. import redis
  2.  
  3. r=redis.Redis(host='127.0.0.1')
  4. r.publish("fm104.5", "Hi,yuan!")

发布订阅的特性用来做一个简单的实时聊天系统再适合不过了,当然这样的东西开发中很少涉及到。再比如在分布式架构中,常常会遇到读写分离的场景,在写入的过程中,就可以使用redis发布订阅,使得写入值及时发布到各个读的程序中,就保证数据的完整一致性。再比如,在一个博客网站中,有100个粉丝订阅了你,当你发布新文章,就可以推送消息给粉丝们拉。

 

 

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

  

redis数据库基础篇的更多相关文章

  1. 关于Redis数据库 ---- 基础篇

    Redis数据库也被称为数据结构数据库,因为存储基于key-value模式. 其中,value值可以为字符串(string),哈希(map),列表(list),集合(set)和有序集合(zset). ...

  2. Redis数据库-基础篇

    Redis Redis是一个开源的,先进的key-value存储. 它通常被称为数据结构服务器,因为键可以包含字符串,哈希,链表,集合和有序集合. Redis 简介 Redis 是完全开源免费的,遵守 ...

  3. 小白也能看懂的Redis教学基础篇——朋友面试被Skiplist跳跃表拦住了

    各位看官大大们,双节快乐 !!! 这是本系列博客的第二篇,主要讲的是Redis基础数据结构中ZSet(有序集合)底层实现之一的Skiplist跳跃表. 不知道那些是Redis基础数据结构的看官们,可以 ...

  4. 小白也能看懂的Redis教学基础篇——做一个时间窗限流就是这么简单

    不知道ZSet(有序集合)的看官们,可以翻阅我的上一篇文章: 小白也能看懂的REDIS教学基础篇--朋友面试被SKIPLIST跳跃表拦住了 书接上回,话说我朋友小A童鞋,终于面世通过加入了一家公司.这 ...

  5. python-MySQL数据库--- 基础篇

    MySQL数据库基础 数据库系统(database system) 1.数据库系统(database system)         数据库系统是计算机系统中一种专门管理数组资源的系统,数据库存储的是 ...

  6. 小白也能看懂的Redis教学基础篇——redis神秘的数据结构

    各位看官大大们,周末好! 作为一个Java后端开发,要想获得比较可观的工资,Redis基本上是必会的(不要问我为什么知道,问就是被问过无数次).那么Redis是什么,它到底拥有什么神秘的力量,能获得众 ...

  7. mysql数据库( 基础篇加破解)

    1.数据库(Database,DB)是按照数据结构来组织.存储和管理数据的,并且是建立在计算机存储设备上的仓库 2.什么是数据库:(用来存储数据的仓库) 数据库:(cs架构套接字) 数据库管理软件分类 ...

  8. 数据库 基础篇3(mysql语法)

    4 数据库管理(接上篇) 4.1 查询所有数据库 mysql> show databases; +--------------------+ | Database           | +-- ...

  9. Redis数据库 : 基础

    设置密码: /etc/redis/redis.conf 文件把 requirepass 取消注释并设置密码 取消只能本地登录的bind 同上面的配置文件 把 bind一行注释掉 带密码登录: redi ...

随机推荐

  1. PEP8之常用编码规范-摘自官网

    PEP8是广泛应用于Python编码中的规范,这里只会记录最重要的一部分:摘自官网 使用4个空格缩进,不要使用制表符. 4个空格是一个在小缩进(允许更大的嵌套深度)和大缩进(更容易阅读)的一种很好的折 ...

  2. 将map中的json转ObjecId

    我们直接从gridfs中取文件列表时取出来的文件_id为: "_id": { "timestamp": 1587091947, "counter&qu ...

  3. 使用opencv在Qt控件上播放mp4文件

    文章目录 简介 核心代码 运行结果 简介 opencv是一个开源计算机视觉库,功能非常多,这里简单介绍一下OpenCV解码播放Mp4文件,并将图像显示到Qt的QLabel上面. 核心代码 头文件 #i ...

  4. 026_go语言中的通道方向

    代码演示 package main import "fmt" func ping(pings chan<- string, msg string) { pings <- ...

  5. 解惑4:java是值传递还是引用传递

    一.概述 曾经纠结了很久java的参数传递方式是什么样的,后面粗略的了解了一鳞半爪以后有了大概的印象:"传参数就是值传递,传对象就是引用传递",后面进一步查找了相关资料和文章以后, ...

  6. Python使用pyexecjs代码案例解析

    针对现在大部分的网站都是使用js加密,js加载的,并不能直接抓取出来,这时候就不得不适用一些三方类库来执行js语句 execjs,一个比较好用且容易上手的类库(支持py2,与py3),支持 JS ru ...

  7. Html视频播放同时获取当前帧下的图片

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  8. 关于css布局中,inline-block元素间隙的处理方法

    关于inline-block元素间隙的处理 参考橱窗外的小孩,原文链接https://www.cnblogs.com/showcase/p/10469361.html 如下,两个inline-bloc ...

  9. 发布新版首页“外婆新家”升级版:全新的UI,熟悉的味道

    在7月30日我们我们忐忑不安地发布了新版网站首页,发布后迎接我们的不是新颜新风貌的惊喜,而是我们最担心的残酷现实——“让我们等这么多年,等来的就是这个新的丑容颜”,在大家的批评声中我们深深地认识到我们 ...

  10. Cayley-Hamilton 定理简要证明

    证明思路来源于 DZYO 发的博客 Cayley-Hamilton 定理: 设 \(\textbf A\) 是 n阶矩阵,\(f(\lambda)=\det(\lambda\textbf I-\tex ...