路飞项目----day09(登录与注册前端页面与后端接口接通,Redis介绍与安装,python普通连接和连接池连接 redis,python操作Redis之字符串类型相关方法)
昨日回顾
1 测试腾讯短信 v3 sdk 提供发送短信
-模板 {1} {2} {3}
2 发送短信做成包,以后无论在什么框架中,直接copy进去,直接导入使用
-包名 send_sms_v3
-__init__.py # 导入了给外部使用的函数
-settings.py # 配置信息---》APPID。。。
-sms.py # 核心:获取 n 位数字验证码,send_sms
3 发送短信接口
-csrf:解决方案
-前端使用post请求,携带手机号 {mobile:'13454646',sign:asfasdfas}
-后端路由---》使用action装饰 send_sms---》
-取出手机号,生成验证码,存到【缓存】中----》
cache.set(key,value,过期事件)
# 重点:value值可以是什么类型?任意类型都可以
# 如何存的?序列化 pickle
cache.get(key)
-调用封装发送短信,【同步发送异步发送】
4 短信登录接口
-前端:post请求 {mobile:1334535,code:8888}
-后端:action装饰器----》
-视图类的代码,跟之前多方式登录的代码一模一样,使用的序列化类不一样
-重写get_serializer_class
-把逻辑写在序列化类中
-封装
5 短信注册接口
-前端:post请求 {mobile:12344,code:123,password:123}
-后端:写了个新的视图类
-重写create---》自动生成路由
-核心逻辑再序列化类
.
.
.
.
.
今日内容
1 登录页面分析
# 点击登录,弹出登录组件,盖住整个屏幕(定位)
# 点击登录组件中的X,关闭登录组件(子传父)
.
.
.
.
.
.
Header.vue
<template>
<div class="header">
<div class="slogan">
<p>老男孩IT教育 | 帮助有志向的年轻人通过努力学习获得体面的工作和生活</p>
</div>
<div class="nav">
<ul class="left-part">
<li class="logo">
<router-link to="/">
<img src="../assets/img/head-logo.svg" alt="">
</router-link>
</li>
<!--active的作用,就是对应的值如果等于true该标签下面就会多一条下划线出来-->
<li class="ele">
<span @click="goPage('/free-course')" :class="{active: url_path === '/free-course'}">免费课</span>
</li>
<li class="ele">
<span @click="goPage('/actual-course')" :class="{active: url_path === '/actual-course'}">实战课</span>
</li>
<li class="ele">
<span @click="goPage('/light-course')" :class="{active: url_path === '/light-course'}">轻课</span>
</li>
</ul>
<div class="right-part">
<div v-if="!username">
<div>
<span @click="put_login">登录</span>
<span class="line">|</span>
<span @click="put_register">注册</span>
</div>
</div>
<div v-else>
<div>
<span >后面有空放个头像</span>
<span class="line">|</span>
<span >{{username}}</span>
<span class="line">|</span>
<span >注销</span>
</div>
</div>
</div>
</div>
<Login v-if="is_login" @close1="close_login" @go1="put_register" @success="success_login"/>
<Register v-if="is_register" @close2="close_register" @go2="put_login" @success2="success_register"/>
</div>
</template>
<script>
import Login from "@/components/Login"
import Register from "@/components/Register";
export default {
name: "Header",
data() {
return {
// 当前所在路径,去sessionStorage取的,如果取不到,就是 / 根路径
url_path: sessionStorage.url_path || '/',
is_login: false,
is_register: false,
username: this.$cookies.get('username'),
token: this.$cookies.get('token'),
}
},
methods: {
goPage(url_path) {
// 已经是当前路由就没有必要重新跳转
if (this.url_path !== url_path) {
this.$router.push(url_path);
}
sessionStorage.url_path = url_path;
},
put_login() {
this.is_login = true; // 点登录按钮,控制登录组件显示
this.is_register = false; // 控制注册组件不显示
},
put_register() {
this.is_login = false; // 控制登录组件不显示
this.is_register = true; // 控制注册组件显示
},
close_login() {
this.is_login = false; // 控制登录组件不显示
},
close_register() {
this.is_register = false; // 控制注册组件不显示
},
success_login(data) {
this.is_login = false;
this.username = this.$cookies.get('username');
this.token = this.$cookies.get('token');
},
logout() {
this.token = '';
this.username = '';
this.user_id = '';
this.$cookies.remove('username');
this.$cookies.remove('token');
this.$cookies.remove('user_id');
},
success_register() {
this.is_register = false;
this.is_login = true;
}
},
created() {
// 组件加载完成,就取出当前的路径this.$route.path ,存到sessionStorage里面去
sessionStorage.url_path = this.$route.path;
// 把url_path = 当前路径
this.url_path = this.$route.path;
},
components: {
Login,
Register,
}
}
</script>
<!--这个判断active的值的整体的思路是,一开始页面刚加载的时候,由于sessionStorage没有值,所以url_path的值是根/-->
<!--但是Vue对象创建完成,该头组件管理的标签模板未挂载前,执行created钩子,把当前的路径加到sessionStorage里面去,并将url_path重新赋值-->
<!--当点击跳转按钮时,先判断跳转的路由是否是当前路由,不是跳转到想要跳的路由上去,并改掉sessionStorage里面的路由,然后又会触发created-->
<!--往sessionStorage再写一次,并将url_path重新赋值,目的可能是如果用户不是触发点击事件来到的该页面,也能正常的在对应标签下多条下划线出来-->
<style scoped>
.header {
background-color: white;
box-shadow: 0 0 5px 0 #aaa;
}
.header:after {
content: "";
display: block;
clear: both;
}
.slogan {
background-color: #eee;
height: 40px;
}
.slogan p {
width: 1200px;
margin: 0 auto;
color: #aaa;
font-size: 13px;
line-height: 40px;
}
.nav {
background-color: white;
user-select: none;
width: 1200px;
margin: 0 auto;
}
.nav ul {
padding: 15px 0;
float: left;
}
.nav ul:after {
clear: both;
content: '';
display: block;
}
.nav ul li {
float: left;
}
.logo {
margin-right: 20px;
}
.ele {
margin: 0 20px;
}
.ele span {
display: block;
font: 15px/36px '微软雅黑';
border-bottom: 2px solid transparent;
cursor: pointer;
}
.ele span:hover {
border-bottom-color: orange;
}
.ele span.active {
color: orange;
border-bottom-color: orange;
}
.right-part {
float: right;
}
.right-part .line {
margin: 0 10px;
}
.right-part span {
line-height: 68px;
cursor: pointer;
}
</style>
.
.
.
.
.
.
.
2 登录小组件
2.1 Login.vue
<template>
<div class="login">
<div class="box">
<!-- 叉号,点击登录的弹窗页面就关闭了-->
<i class="el-icon-close" @click="close_login"></i>
<div class="content">
<div class="nav">
<span :class="{active: login_method === 'is_pwd'}"
@click="change_login_method('is_pwd')">密码登录</span>
<span :class="{active: login_method === 'is_sms'}"
@click="change_login_method('is_sms')">短信登录</span>
<!--通过点击事件修改login_method对应的值,然后让span标签下面多道杠-->
</div>
<!--多方式登录的表单标签-->
<el-form v-if="login_method === 'is_pwd'">
<el-input
placeholder="用户名/手机号/邮箱"
prefix-icon="el-icon-user"
v-model="username"
clearable>
</el-input>
<el-input
placeholder="密码"
prefix-icon="el-icon-key"
v-model="password"
clearable
show-password>
</el-input>
<!--clearable就是框里面的小叉号,点一下就清空框里面内容-->
<!--show-password 点一下就能看到被挡住的密码-->
<el-button type="primary" @click="login">登录</el-button>
<!--登录按钮点击后,发送ajax请求到后端的 2 多方式登录的接口-->
</el-form>
<!--短信验证码登录的表单标签-->
<el-form v-if="login_method === 'is_sms'">
<el-input
placeholder="手机号"
prefix-icon="el-icon-phone-outline"
v-model="mobile"
clearable
@blur="check_mobile">
<!--手机号输入完触发失去焦点事件,发送ajax请求到后端的 1 校验手机号是否存在的接口-->
</el-input>
<el-input
placeholder="验证码"
prefix-icon="el-icon-chat-line-round"
v-model="sms"
clearable>
<template slot="append">
<span class="sms" @click="send_sms">{{ sms_interval }}</span>
<!--获取验证码按钮点击后,发送ajax请求到后端的 3 发送短信验证码的接口-->
</template>
</el-input>
<el-button @click="mobile_login" type="primary">登录</el-button>
<!--登录按钮点击后,发送ajax请求到后端的 4 短信验证码登录接口-->
</el-form>
<div class="foot">
<span @click="go_register">立即注册</span>
</div>
</div> <!--content-->
</div> <!--box-->
</div>
</template>
<script>
export default {
name: "Login",
data() {
return {
username: '',
password: '',
mobile: '',
sms: '', // 验证码
login_method: 'is_pwd',
sms_interval: '获取验证码',
is_send: false,
}
},
methods: {
close_login() {
// 通过this.$emit 触发父组件的自定义事件close对应的函数
this.$emit('close1',)
},
go_register() {
// 通过this.$emit 触发父组件的自定义事件go对应的函数
this.$emit('go1',)
},
change_login_method(method) {
this.login_method = method;
},
// 手机号输入完触发失去焦点事件
check_mobile() {
// 先判断手机号的输入框有没有值,没有值return,函数直接结束
if (!this.mobile) return;
// js正则语法 '字符串'.match(/正则语法/)
if (!this.mobile.match(/^1[3-9][0-9]{9}$/)) {
// 如果不符合手机号码的正则匹配,走下面代码,就会有个带着信息弹出框弹出
this.$message({
message: '手机号有误',
type: 'warning',
duration: 1000, // 弹出框维持1秒
onClose: () => {
this.mobile = '';
}
// 弹出框一关闭,将输入框置为空
});
return false;
} // 走到这前端对手机号校验已经结束了
// 开始后台校验手机号是否已存在
this.$axios({
url: this.$settings.BASE_URL + '/user/userinfo/check_mobile/?mobile=' + this.mobile,
method: 'get',
}).then(res => {
if (res.data.code == 101) {
this.$message({
message: '账号正常',
type: 'success',
duration: 1000,
});
// 当在短信登录界面输入手机号后,失去焦点后,先进行正则匹配确认是手机号
// 在发送ajax请求,调用后端的查询手机号码是否存在接口,若得到的返回值code等于101 说明手机号存在
// 当this.is_send等于true后,才能让获取验证码按钮的点击事件函数正常往下走,不然点击事件就直接结束了
this.is_send = true;
} else {
this.$message({
message: '账号不存在',
type: 'warning',
duration: 1000,
onClose: () => {
this.mobile = '';
// 如果code不对,也弹出提示信息,并清空输入框
}
})
}
}).catch(() => {
});
},
// 发送短信验证码按钮的点击事件
send_sms() {
// this.is_send 如果是false 取反后,直接return 函数直接结束 不会往下走了
if (!this.is_send) return;
// 按钮点一次立即禁用,不让你一直点击获取验证码按钮,从而一直触发发送短信验证码的点击事件
this.is_send = false;
let sms_interval_time = 60; // 定义一个剩余时间的变量
this.sms_interval = "发送中..."; // 把按钮上原来获取验证码几个字变成 发送中...
// 定时器: setInterval(fn, time, args)
// 往后台发送验证码
this.$axios({
url: this.$settings.BASE_URL + '/user/userinfo/send_msg/',
method: 'post',
data: {
mobile: this.mobile
}
}).then(res => {
if (res.data.code == 100) { // 已发送短信
// 启动循环定时任务
let timer = setInterval(() => {
if (sms_interval_time <= 1) {
clearInterval(timer);
this.sms_interval = "获取验证码";
this.is_send = true; // 重新恢复点击按钮发送短信功能
// 如果剩余时间是否小于1s,清除循环定时任务
} else {
// 如果剩余时间大于1,就把剩余时间自减1s
sms_interval_time -= 1;
this.sms_interval = `${sms_interval_time}秒后再发`;
}
}, 1000);
// 每隔一秒执行一次 ,循环定时任务里面的函数
} else { // 发送失败
this.sms_interval = "重新获取";
this.is_send = true;
this.$message({
message: '短信发送失败',
type: 'warning',
duration: 3000
});
}
}).catch(() => {
// ajax 请求报错了,显示频率过快
this.sms_interval = "频率过快";
this.is_send = true;
})
},
// 多方式登录接口
login() {
//
if (!(this.username && this.password)) {
this.$message({
message: '请填好账号密码',
type: 'warning',
duration: 1500
});
return false // 直接结束逻辑
}
this.$axios({
url: this.$settings.BASE_URL + '/user/userinfo/login_multiple/',
method: 'post',
data: {
username: this.username,
password: this.password,
}
}).then(res => {
if (res.data.code == 100) {
let username = res.data.username;
let token = res.data.token;
this.$cookies.set('username', username, '7d');
this.$cookies.set('token', token, '7d');
this.$emit('success', res.data); // 调用父组件里的自定义success事件对应的方法运行,并传值
} else {
this.$message({
message: res.data.msg,
type: 'warning',
duration: 1500
});
}
}).catch(error => {
console.log(error.response.data)
})
},
// 手机号验证码登录接口
mobile_login() {
// 先判断两个输入框有没有为空的,有空就弹个框
if (!(this.mobile && this.sms)) {
this.$message({
message: '请填好手机与验证码',
type: 'warning',
duration: 1500
});
return false // 直接结束逻辑
}
// 两个框不是空继续往下走,带着手机号与验证码,发送post请求,调用短信验证码登录的接口,
this.$axios({
url: this.$settings.BASE_URL + '/user/userinfo/login_msg/',
method: 'post',
data: {
mobile: this.mobile,
code: this.sms,
}
}).then(res => {
if (res.data.code == 100) {
let username = res.data.username;
let token = res.data.token;
// 放到cookie中
this.$cookies.set('username', username, '7d');
this.$cookies.set('token', token, '7d');
this.$emit('success', res.data); // 关闭登录框
} else {
this.$message({
message: res.data.msg,
type: 'warning',
duration: 1500
});
}
}).catch(error => {
console.log(error.response.data)
})
}
}
}
</script>
<style scoped>
.login {
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
left: 0;
z-index: 10;
background-color: rgba(0, 0, 0, 0.4);
/* z-index 先沿着z轴浮动起来,再fixed,起巨幕遮盖的效果 */
}
.box {
width: 400px;
height: 420px;
background-color: white;
border-radius: 10px;
position: relative;
top: calc(50vh - 210px);
left: calc(50vw - 200px);
}
.el-icon-close {
position: absolute;
font-weight: bold;
font-size: 20px;
top: 10px;
right: 10px;
cursor: pointer;
}
.el-icon-close:hover {
color: darkred;
}
.content {
position: absolute;
top: 40px;
width: 280px;
left: 60px;
}
.nav {
font-size: 20px;
height: 38px;
border-bottom: 2px solid darkgrey; /* 让标签下面有一道杠 */
}
.nav > span {
margin: 0 20px 0 35px;
color: darkgrey;
user-select: none;
cursor: pointer;
padding-bottom: 10px;
border-bottom: 2px solid darkgrey;
}
.nav > span.active {
color: black;
border-bottom: 3px solid black;
padding-bottom: 9px;
}
.el-input, .el-button {
margin-top: 40px;
}
.el-button {
width: 100%;
font-size: 18px;
}
.foot > span {
float: right;
margin-top: 20px;
color: orange;
cursor: pointer;
}
.sms {
color: orange;
cursor: pointer;
display: inline-block;
width: 70px;
text-align: center;
user-select: none;
}
</style>
.
.
.
.
.
3 注册小组件
Register.vue
<template>
<div class="register">
<div class="box">
<i class="el-icon-close" @click="close_register"></i>
<div class="content">
<div class="nav">
<span class="active">新用户注册</span>
</div>
<el-form>
<el-input
placeholder="手机号"
prefix-icon="el-icon-phone-outline"
v-model="mobile"
clearable
@blur="check_mobile">
<!--手机号输入完触发失去焦点事件,发送ajax请求到后端的 1 校验手机号是否存在的接口-->
</el-input>
<el-input
placeholder="密码"
prefix-icon="el-icon-key"
v-model="password"
clearable
show-password>
</el-input>
<el-input
placeholder="验证码"
prefix-icon="el-icon-chat-line-round"
v-model="sms"
clearable>
<template slot="append">
<span class="sms" @click="send_sms">{{ sms_interval }}</span>
<!--获取验证码按钮点击后,发送ajax请求到后端的 3 发送短信验证码的接口-->
</template>
</el-input>
<el-button @click="register" type="primary">注册</el-button>
<!--注册按钮点击后,发送ajax请求到后端 5 手机号加短信验证码加密码注册账号接口-->
</el-form>
<div class="foot">
<span @click="go_login">立即登录</span>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "Register",
data() {
return {
mobile: '',
password: '',
sms: '',
sms_interval: '获取验证码',
is_send: false,
}
},
methods: {
close_register() {
this.$emit('close2', false)
},
go_login() {
this.$emit('go2')
},
// 手机号输入完触发失去焦点事件,核对手机号码是否存在
check_mobile() {
if (!this.mobile) return;
// js正则语法 '字符串'.match(/正则语法/)
if (!this.mobile.match(/^1[3-9][0-9]{9}$/)) {
this.$message({
message: '手机号有误',
type: 'warning',
duration: 1000,
onClose: () => {
this.mobile = '';
}
});
return false;
}
// 后台校验手机号是否已存在
this.$axios({
url: this.$settings.BASE_URL + '/user/userinfo/check_mobile/',
method: 'get',
params: {
mobile: this.mobile
}
}).then(res => {
if (res.data.code !== 101) {
// 手机号在数据库中不存在才能注册,和登录时判断手机号是否存在逻辑是反的
this.$message({
message: '欢迎注册我们的平台',
type: 'success',
duration: 1500,
});
// 发送验证码按钮才可以被点击
this.is_send = true;
} else {
this.$message({
message: '账号已存在,请直接登录',
type: 'warning',
duration: 1500,
})
}
}).catch(() => {
});
},
// 发送短信验证码按钮的点击事件
send_sms() {
// this.is_send必须允许发生验证码,才可以往下执行逻辑
if (!this.is_send) return;
// 按钮点一次立即禁用
this.is_send = false;
let sms_interval_time = 60;
this.sms_interval = "发送中...";
// 定时器: setInterval(fn, time, args)
// 往后台发送验证码
this.$axios({
url: this.$settings.BASE_URL + '/user/userinfo/send_msg/',
method: 'post',
data: {
mobile: this.mobile
}
}).then(res => {
if (res.data.code == 100) { // 发送成功
let timer = setInterval(() => {
if (sms_interval_time <= 1) {
clearInterval(timer);
this.sms_interval = "获取验证码";
this.is_send = true; // 重新回复点击发送功能的条件
} else {
sms_interval_time -= 1;
this.sms_interval = `${sms_interval_time}秒后再发`;
}
}, 1000)
} else { // 发送失败
this.sms_interval = "重新获取";
this.is_send = true;
this.$message({
message: '短信发送失败',
type: 'warning',
duration: 3000
});
}
}).catch(() => {
this.sms_interval = "频率过快";
this.is_send = true;
})
},
// 注册按钮的点击事件
register() {
if (!(this.mobile && this.sms && this.password)) {
this.$message({
message: '请填好手机、密码与验证码',
type: 'warning',
duration: 1500
});
return false // 直接结束逻辑
}
this.$axios({
url: this.$settings.BASE_URL + '/user/register/',
method: 'post',
data: {
mobile: this.mobile,
code: this.sms,
password: this.password
}
}).then(res => {
if (res.data.code == 108) {
this.$message({
message: '注册成功,3秒跳转登录页面',
type: 'success',
duration: 3000,
showClose: true,
onClose: () => {
// 注册成功,去向登录页面
this.$emit('success2')
}
});
} else {
this.$message({
message: res.data.msg,
type: 'warning',
duration: 1500
});
}
}).catch(error => {
this.$message({
message: '注册失败,请重新注册',
type: 'warning',
duration: 1500,
showClose: true,
onClose: () => {
// 清空所有输入框
this.mobile = '';
this.password = '';
this.sms = '';
}
});
})
}
}
}
</script>
<style scoped>
.register {
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
left: 0;
z-index: 10;
background-color: rgba(0, 0, 0, 0.3);
}
.box {
width: 400px;
height: 480px;
background-color: white;
border-radius: 10px;
position: relative;
top: calc(50vh - 240px);
left: calc(50vw - 200px);
}
.el-icon-close {
position: absolute;
font-weight: bold;
font-size: 20px;
top: 10px;
right: 10px;
cursor: pointer;
}
.el-icon-close:hover {
color: darkred;
}
.content {
position: absolute;
top: 40px;
width: 280px;
left: 60px;
}
.nav {
font-size: 20px;
height: 38px;
border-bottom: 2px solid darkgrey;
}
.nav > span {
margin-left: 90px;
color: darkgrey;
user-select: none;
cursor: pointer;
padding-bottom: 10px;
border-bottom: 2px solid darkgrey;
}
.nav > span.active {
color: black;
border-bottom: 3px solid black;
padding-bottom: 9px;
}
.el-input, .el-button {
margin-top: 40px;
}
.el-button {
width: 100%;
font-size: 18px;
}
.foot > span {
float: right;
margin-top: 20px;
color: orange;
cursor: pointer;
}
.sms {
color: orange;
cursor: pointer;
display: inline-block;
width: 70px;
text-align: center;
user-select: none;
}
</style>
.
.
.
.
.
.
4 Redis介绍与安装
# redis:缓存数据库【大部分时间做缓存,不仅仅可以做缓存】,非关系型数据库【区别于mysql关系型数据库】
-nosql:非关系型的数据库
-c语言写的 服务(监听端口),
用来存储数据的,数据是存储在内存中,取值,放值速度非常快, 10w qps
-----------------------------------
# 面试题:redis为什么这么快
-1 纯内存操作
-2 网络模型使用的IO多路复用(epoll)(可以处理的请求数更多)
-3 6.x之前,单进程,单线程架构,没有线程进程间切换,更少的消耗资源
-4 6.x之后,虽然使用多进程,多线程架构,但是操作数据的时候还是单进程单线程
# key-value形式存储,没有表的概念
-----------------------------------
-----------------------------------
# 版本
最新: 7.x
公司里 5.x比较多
# 安装
-mac 源码编译安装
-linux 源码编译安装
-win 微软自己,基于源码,改动,编译成安装包
# 最新5.x版本 https://github.com/tporadowski/redis/releases/
# 最新3.x版本 https://github.com/microsoftarchive/redis/releases
一路下一步,安装完释放出两个命令,会把redis自动加入到服务中
redis-server # 相当于mysqld 服务端的启动命令
redis-cli # 相当于mysql 客户端的启动命令
------------------------------------------
# 安装目录下主要文件
redis-server
redis-cli
redis.windows-service.conf # 配置文件
bind 127.0.0.1 # 服务端,跑在的地址
port 6379 # 监听的端口
# mysql与redis 网络传输的协议都不是用的http协议
# 配置文件打开后,可以改端口号,
# 绑定的ip地址,如果改成bind 0.0.0.0,所有局域网都能访问你的服务端了
------------------------------------------
# 启动redis服务端
1 方式一:
-在服务中,点击启动,后台启动
2 方式二:使用命令
redis-server 指定配置文件 如果不指定,会默认
redis-server --port 6380 # 启动了一个端口号是6380的redis服务端
------------------------------------------
# 客户端连接redis
1 方式一
redis-cli # 默认连接本地的6379端口
2 方式二: # 主要作用是连接远程的别人电脑的redis服务端用的
redis-cli -h 地址 -p 端口
redis-cli -h 127.0.0.1 -p 6379
3 方式三:使用图形化客户端操作
-Redis Desktop Manager :开源的,原来免费,后来收费了 推荐用
-resp-2022.1.0.0.exe 一路下一步,安装完启动起来
-Redis Client 小众
# 图形化界面,连接redis 输入地址和端口,点击连接即可
# redis默认有16个库,默认连进去就是第0个
# 配置文件里面可以改库的数量
------------------------------------------------
------------------------------------------------
补充
# Qt5 qt是个平台,专门用来做图形化界面的
-可以使用c++写
-可以使用python写 pyqt5 使用python写图形化界面 (少量公司在用)
------------------------------------------------
如何将redis做成开机自启动 ?
.
.
将程序做成服务的本质是
当启动服务的时候,执行了一条命令
"D:\Program Files\Redis\redis-server.exe" --service-run "D:\Program Files\Redis\redis.windows-service.conf"
最后面的路径是配置文件的路径
.
.
.
.
.
.
.
.
5 python普通连接和连接池连接 redis
# 使用python来操作redis
# python相当于客户端,操作redis
# 需要安装模块:pip install redis
#补充: django 中操作mysql,没有连接池的,一个请求就是一个mysql连接
-可能会有问题,并发数过高,导致mysql连接数过高,影响mysql性能
-使用django连接池:https://blog.51cto.com/liangdongchang/5140039
.
.
.
5.1 python普通连接
# 安装redis 模块:pip install redis
# 1 导入模块的Redis类
from redis import Redis
# 2 实例化得到对象
conn = Redis(host='127.0.0.1', port=6379)
# 3 使用conn,操作redis
# 获取name的值
# res = conn.get('name') # 返回数据是bytes格式
# 4 设置值
conn.set('age',19)
conn.close()
.
.
.
.
.
5.2 python连接池连接
# 连接池的目的: 就是不要创建出太多的连接数,影响服务的性能
###pool.py
import redis
POOL = redis.ConnectionPool(max_connections=10, host='127.0.0.1', port=6379) # 创建一个大小为10的redis连接池
-------------------------------------------
### 测试代码
from threading import Thread
import redis
from pool import POOL
# 做成模块后,导入,无论导入多少次,导入的都是那一个POOL对象
def task():
# 从池里面拿一个连接
conn = redis.Redis(connection_pool=POOL) # 如果报错了,可能是连接池的数量设置的太小,线程太多导致
print(conn.get('name'))
for i in range(100):
t = Thread(target=task, ) # 每次都是一个新的连接,会导致redis的连接数过多
t.start()
# 一般要把连接池对象做成单例,否则有可能在每个线程中创建一个连接池,性能更低
# 使用模块导入的方式
---------------------------------------------
# 单例模式:设计模式 23 中设计模式
-全局只有一个 这个对象
p1=Person() # p1 对象
p2=Person() # p2 新对象
-单例模式的6种方式
-1 模块导入方式
-2 。。。
# 小补充: django连接mysql默认是不带连接池的,一个请求就是一个mysql连接
# django使用连接池的用法,要下载第三方模块
# 参考 https://blog.51cto.com/liangdongchang/5140039
.
.
.
.
.
.
.
6 python操作Redis之字符串类型相关方法
# redis 是key-value形式存储
# redis 数据放在内存中,如果断电,数据丢失---》所以需要有持久化的方案
# redis 的数据 如果服务端正常关闭,数据是不会丢失的,
# 会自动把内存上的数据持久化到硬盘上,自动创 dump.rdb 文件保存数据
# redis有 5种数据类型,value类型
-字符串:用的最多,做缓存;做计数器
-列表: 简单的消息队列
-字典(hash):缓存
-集合:去重
-有序集合:排行榜
------------------------------------------
.
.
#字符串类型使用
'''
1 set(name, value, ex=None, px=None, nx=False, xx=False)
2 setnx(name, value)
3 setex(name, value, time)
4 psetex(name, time_ms, value)
5 mset(*args, **kwargs)
6 get(name)
7 mget(keys, *args)
8 getset(name, value)
9 getrange(key, start, end)
10 setrange(name, offset, value)
11 setbit(name, offset, value)
12 getbit(name, offset)
13 bitcount(key, start=None, end=None)
14 bitop(operation, dest, *keys)
15 strlen(name)
16 incr(self, name, amount=1)
# incrby
17 incrbyfloat(self, name, amount=1.0)
18 decr(self, name, amount=1)
19 append(key, value)
'''
import redis
conn = redis.Redis()
# 1 set(name, value, ex=None, px=None, nx=False, xx=False)
# ex,过期时间(秒)
# px,过期时间(毫秒)
# nx,如果设置为True,内存中有键对应的值,就不修改该键对应的值,没有就修改
# xx,如果设置为True,内存中有键对应的值,就修改该键对应的值,值不存在,不会设置新值
# conn.set('hobby','篮球',ex=3)
# conn.set('hobby','篮球',px=3)
# conn.set('name','lqz888',)
# conn.set('name','lqz',nx=False)
# conn.set('hobby','篮球',xx=True)
# conn.set('hobby','篮球',xx=False)
# redis---》实现分布式锁,底层基于nx实现的
# 2 setnx(name, value) # 内存中有键对应的值,就不改
# 等同于:conn.set('name','lqz',nx=True)
# conn.setnx('name', '刘亦菲')
# 3 setex(name, value, time)
# 等同于:conn.set('name','lqz',ex=3)
# conn.setex('wife', 3, '刘亦菲')
# 4 psetex(name, time_ms, value)
# conn.psetex('wife',3000,'刘亦菲')
# 5 mset(*args, **kwargs) # 批量设置值
# conn.mset({'wife': '刘亦菲', 'hobby': '篮球'})
# 6 get(name) # 获取值
# print(str(conn.get('wife'),encoding='utf-8'))
# print(conn.get('wife'))
# 7 mget(keys, *args) # 批量获取值
# res=conn.mget(['wife','hobby'])
# res=conn.mget('wife','hobby') # 两种方法都可以
# print(res)
# 8 getset(name, value) # 既获取值,又设置值,一次网络请求,完成两个操作
# res=str(conn.getset('wife','迪丽热巴'),encoding='utf-8')
# print(res)
# 9 getrange(key, start, end) # 拿对应字节长度区间的值
# res = str(conn.getrange('wife', 0, 2), encoding='utf-8') # 字节长度,不是字符长度 前闭后闭区间
# print(res)
# 10 setrange(name, offset, value) # 从对应的偏移量后,替换成设置的值
# conn.setrange('wife',2,'bbb') # 两个字节长度后的3个字符替换成bbb 其他字符不变
-------------------------------------
# ---- 比特位---操作
# 11 setbit(name, offset, value)
# 12 getbit(name, offset)
# 13 bitcount(key, start=None, end=None)
# 14 bitop(operation, dest, *keys) 获取多个值,并将值做位运算,将最后的结果保存至新的name对应的值
# ---- 比特位---操作
-------------------------------------
# 15 strlen(name)
# res=conn.strlen('hobby') # 统计值对应的字节长度
# print(res)
-------------------------------------------
# 16 incr(self, name, amount=1) # 自增一个整数
# 不会存在并发安全问题,单线程架构,并发量高
# conn.incr('age') 自增一
# incrby 和 incr 作用一样
# 17 incrbyfloat(self, name, amount=1.0) # 自增一个小数
# conn.incrbyfloat('age',1.2)
# 18 decr(self, name, amount=1) # 自减
# conn.decrby('age') 自减1
# 19 append(key, value) # 往对应的值上拼接字符串
# conn.append('hobby','sb')
# print(conn.strlen('hobby'))
conn.close()
'''
你需要记住的
set
get
strlen 字节长度
incr
'''
.
.
.
.
.
作业
1 前端登录注册完成
3 装好redis
4 使用普通和连接池连接
5 照着比较测试所有string类型的方法
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY