首页
留言
友情链接
标签页
Search
1
那些顶级不落俗套的“美好祝福”
1,754 阅读
2
如何使用JavaScript获取和设置CSS root变量值
1,262 阅读
3
中国历史朝代顺序图
930 阅读
4
春和 《江海共余生》
874 阅读
5
唐诗三百首1-5
590 阅读
分享
Web前端
html&css
javascript
Vue
shopify
shoplazza
后端
ThinkPHP
YII2
服务器端
软件安装
问题合集
故事
诗词
生活
学习
学科
语文
数学
英语
物理
化学
生物
政治
历史
地理
自然
其他
抖音
快手
小视频
随笔
易经
书摘
今日话题
登录
/
注册
Search
标签搜索
一年级语文
sunshine
累计撰写
169
篇文章
累计收到
15
条评论
首页
栏目
分享
Web前端
html&css
javascript
Vue
shopify
shoplazza
后端
ThinkPHP
YII2
服务器端
软件安装
问题合集
故事
诗词
生活
学习
学科
语文
数学
英语
物理
化学
生物
政治
历史
地理
自然
其他
抖音
快手
小视频
随笔
易经
书摘
今日话题
页面
留言
友情链接
标签页
搜索到
168
篇与
的结果
2022-10-13
JavaScript基础
第1章 JavaScript介绍1.1 JavaScript编程语言JavaScript,简称JS,是一种客户端脚本语言,主要用来向HTML网页添加各式各样的动态功能,为用户提供更流畅美观的浏览效果。可以直接嵌入HTML页面,但写成单独的js文件有利于结构和行为的分离。在绝大多数浏览器的支持下,可以在多种平台下运行(如Windows、Linux、Mac、Android、iOS等)JS主要运行于客户端(浏览器),也可以运行在服务端(操作系统)JavaScript 和 Java 是两种不同的编程语言:JavaScript主要用于客户端,Java用于服务端。JavaScript现在的意义(应用场景)JavaScript 发展到现在几乎无所不能。网页特效 *服务端开发(Node.js) *命令行工具(Node.js)桌面程序(Electron)App(Cordova)控制硬件-物联网(Ruff)游戏开发(cocos2d-js)1.2 发展及历史1994年Netscape公司推出免费版本浏览器 Netscape Navigator(网景浏览器1.0)1995年微软公司发布 Internet Explorer 1.0。1995年网景公司为适应市场变化,需要开发一门专门在浏览器运行的脚本语言,这个任务交给了布兰登,为了应付公司安排的任务,他只用10天时间就提交了工作,并将这门语言命名为 LiveScript;后来为了蹭sun公司java的热度,与sun公司合作,将其临时改名为“JavaScript”;1996年8月,微软模仿JavaScript开发了一种相近的语言,取名为JScript,首先内置于IE 3.01997年7月,ECMA组织发布ECMAScript 1.0版;此后,明争暗斗不断,1998年6月,ECMAScript 2.0版发布,1999年12月,ECMAScript 3.0版发布;2007年10月,ECMAScript 4.0版草案发布,2008年7月中止ECMAScript 4.0的开发,并发布3.1版本;会后不久,ECMAScript 3.1就改名为ECMAScript 5。2011年6月,ECMAscript 5.1版发布,现在使用最为广泛的版本 版发布,现在使用最为广泛的版本;2015年6月,ECMAScript 6正式发布,并且更名为“ECMAScript 2015”;随后,ECMA组织决定,每年发布一个升级版本,以年号来代替版本号,如:ECMAScript 2016、ECMAScript 2017;另外:1996年,样式表标准CSS第一版发布;1997年,DOM模式第一版正式应用,目前的通用版本是DOM3,下一代版本DOM 4正在拟定中。1999年,IE5部署了XMLHttpRequest接口,允许JavaScript发出HTTP请求;2001年,提出了JSON格式,用于取代XML格式。2002年,Mozilla项目发布第一版Firefox。2003年,苹果公司发布了Safari浏览器的第一版。2006年,jQuery函数库诞生2007年,Webkit引擎在iPhone手机中得到部署;2008年,为Chrome浏览器而开发的V8编译器(解析引擎)诞生;2009年,基于V8解析引擎的Node.js项目诞生,迎来前后端JS的霸权时代;2009年,Google发布Chrome OS2009年,Google发布Angular框架;2013年,Mozilla基金会发布手机操作系统Firefox OS,该操作系统的整个用户界面都使用JavaScript;2013年5月,Facebook发布UI框架库React;2014年,尤雨溪发布开源前端开发库Vue.js;2015年3月,Facebook公司发布了 React Native项目;1.3 JavaScript和HTML、CSSHTML:提供网页的结构,提供网页中的内容CSS: 用来样式排版、美化网页JavaScript: 可以用来控制网页内容,给网页增加动态的效果1.4 JavaScript的组成ECMA 欧洲计算机制造联合会;ECMAScript 是一套标准,定义了一种语言的标准,规定了基本语法、数据类型、关键字、具体API的设计规范等,解析引擎设计的参考标准,但与具体实现无关;1.4.1 ECMAScript - JavaScript的核心ECMAScript是一套语法标准,描述了JavaScript语言的基本语法和数据类型,是JavaScript的核心。 ES5 ES61.4.2 BOM - 浏览器对象模型一套操作浏览器功能的API通过BOM可以操作浏览器窗口,比如:弹出框、控制浏览器跳转、获取分辨率等1.4.3 DOM - 文档对象模型一套操作页面元素的APIDOM可以把HTML看做是文档树,通过DOM提供的API可以对树上的节点进行操作1.5 JS学习概况我们在学习JS时,需要学习的内容分为两部分,语言结构及宿主环境提供的API;语言结构部分主要时语言规则及内置对象;而宿主环境的API,根据宿主环境不同而不同,以浏览器为例(js还可以运行在服务器/操作系统),最常见的三个类型:浏览器控制类、DOM操作类、网络控制类;总结:JavaScript编程语言简称 JS,是一种嵌入式的脚本语言,应用范围及其广泛,由布兰登-艾奇开发,在20+年的发展中历经沧桑,学习 JS 分为语言规则及宿主环境两部分;第2章 入门2.1 如何写一段JS代码并运行写在行内01.html: <input type="button" value="按钮" onclick="alert('Hello World')" />写在script标签中 *02.html: <head> <script> alert('Hello World!'); </script> </head>写在外部js文件中,在页面引入03.html: <script src="main.js"></script>main.js: alert('Hello World!');注意点: 引用外部js文件的 script 标签中不可以再写JavaScript代码,即使写了也不会执行,没有作用温馨提示:下面开始进入 JS 基础语法的学习,非常枯燥,别睡着……音乐很优美很动听,但学五线谱真的是乏味无聊痛苦不堪;2.3 变量2.3.1 什么是变量什么是变量变量是计算机内存中存储数据的标识符,根据变量名称可以获取到内存中存储的数据为什么要使用变量使用变量可以方便的获取或者修改内存中的数据变量就是存储数据的容器;2.3.2 如何使用变量var声明变量var age;变量的赋值var age; age = 18;同时声明多个变量var age, name, sex; age = 10; name = 'zs';同时声明多个变量并赋值var age = 10, name = 'zs';2.3.3 变量的命名规则和规范规则 - 必须遵守的,不遵守会报错由字母、数字、下划线、$符号组成,且不能以数字开头区分大小写不能是关键字和保留字,例如:for、while。规范 - 建议遵守的,不遵守不会报错变量名必须有意义遵守驼峰命名法。(首字母小写,后面单词的首字母需要大写。例如:userName、userPassword)下面哪些变量名不合法a 1 age18 18age name $ $name _sex &sex theworld theWorldname变量名,本身不是保留字/关键字, 建议少用。 name在有的浏览器中,是自动声明过的。2.3.4 案例交换两个变量的值var a = '1'; var b = '2'; // 借助第三个变量 var c = a; a=b; b=c; console.log(a,b);不使用临时变量,交换两个数值变量的值//第二种方式 var num1 = 10; var num2 = 20; //计算的方式:累加,然后相减 num1 = num1 + num2;//num1的结果是30 num2 = num1 - num2;//num2的结果是10 num1 = num1 - num2;//num1的结果是20 console.log(num1); console.log(num2);2.3.5 代码调试(输出变量)alert 弹框 :浏览器页面弹框var num1 = 10; alert(num1);console.log() 浏览器console控制台var num1 = 10; var num2 = 20; console.log(num1); console.log(num1, num2);document.write() 浏览器页面中var num1 = 10; document.write(num1);2.4 数据类型2.4.1 简单数据类型Number、String、Boolean、Undefined、Null获取变量的类型typeofvar age = 18; console.log(typeof age); // 'number'Number类型数值字面量:数值的固定值的表示法(数值直接量)110 1024 60.5浮点数(小数)浮点数的精度问题浮点数 var n = 5e-324; // 科学计数法 5乘以10的-324次方 浮点数值的最高精度是 17 位小数,但在进行算术计算时其精确度远远不如整数 var result = 0.1 + 0.2; // 结果不是 0.3,而是:0.30000000000000004 console.log(0.07 * 100); 不要判断两个浮点数是否相等数值范围最小值:Number.MIN_VALUE,// 这个值为: 5e-324 5乘以10的-324次方 最大值:Number.MAX_VALUE,// 这个值为: 1.7976931348623157e+308 无穷大:Infinity 无穷小:-InfinityString类型'abc' "abc" 单双引号引起来的一连串字符字符串字面量(直接量)'程序猿','程序媛', "黑马程序猿"思考:如何打印以下字符串。我是一个 "正直" 的人我很喜欢 "黑马 '程序猿' "注: 转义后单双引号 只能 就近和转义后的单双引号进行配对转义符注: \b 退格符 \f又叫走纸或进纸或 换页符var s = '我很喜欢 \"黑马 \'程序猿\' \"'; console.log(s);字符串长度length属性用来获取字符串的长度var str = '黑马程序猿 Hello World'; console.log(str.length);字符串拼接字符串拼接使用 + 连接console.log(11 + 11); console.log('hello' + ' world'); console.log('100' + '100'); console.log('11' + 11); console.log('male:' + true);两边只要有一个是字符串,那么+就是字符串拼接功能两边如果都是数字,那么就是算术功能。Boolean类型Boolean字面量: true和false,区分大小写计算机内部存储:true为1,false为0Undefined和Nullundefined表示一个声明了没有赋值的变量,变量只声明的时候值默认是undefinednull表示一个空,变量的值如果想为null,必须手动设置注: 关于undefined和null是一个面试中很容易被问到的问题2.4.2 复杂数据类型 Object 对象:保存很多数据的一种数据类型后面详解;题外话如何使用谷歌浏览器,快速的查看数据类型?字符串的颜色是黑色的,数值类型是蓝色的,布尔类型也是蓝色的,undefined和null是灰色的console.log('ss',2,null,undefined,true);2.5 注释被注释的内容是不执行的,不管什么内容都不会运行;单行注释用来描述下面一个或多行代码的作用// 这是一个变量 var name = 'hm';多行注释用来注释多条代码/* var age = 18; var name = 'zs'; console.log(name, age); */总结:JS代码的书写,变量的声明方式,数据类型,注释;第3章 数据类型转换3.1 转换成字符串类型toString()var num = 5; console.log(num.toString());String()var s = null; console.log(s.toString()); console.log(String(s)); // String()函数存在的意义:有些值没有toString(), // 这个时候可以使用String()。比如:undefined和null拼接字符串方式num + "",当 + 两边一个操作符是字符串类型,一个操作符是其它类型的时候,会先把其它类型转换成字符串再进行字符串拼接,返回字符串3.2 转换成数值类型Number()var a = Number('1'); var b = Number(1); var c = Number('c'); var d = Number(null); var e = Number(undefined); console.log(a,b,c,d,e); // 1 1 NaN 0 NaN // Number()可以把任意值转换成数值,如果要转换的字符串中有一个不是数值的字符,返回NaNparseInt()var a = parseInt('1.2df'); var b = parseInt(1); var c = parseInt('c12'); var d = parseInt(null); var e = parseInt(undefined); console.log(a,b,c,d,e); //1 1 NaN NaN NaN // 如果第一个字符是数字会解析,直到遇到非数字结束 // 如果第一个字符不是数字或者符号就返回NaNparseFloat()var a = parseFloat('1.2df'); var b = parseFloat('1.3.4'); var c = parseFloat('c12'); var d = parseFloat(null); var e = parseFloat(undefined); console.log(a,b,c,d,e); //1.2 1.3 NaN NaN NaN // parseFloat() 把字符串转换成浮点数 // parseFloat()和parseInt非常相似, // 不同之处在与parseFloat会解析第一个 . 遇到第二个.或者非数字结束 // 如果解析的内容里只有整数,解析成整数+,-,-0 等运算var str = '500'; console.log(+str); // 取正 console.log(-str); // 取负 console.log(str - 0); 3.3 转换成布尔类型Boolean()var a = Boolean('0'); var b = Boolean(0); var c = Boolean('1'); var d = Boolean(null); var e = Boolean(undefined); var f = Boolean(NaN); console.log(a,b,c,d,e,f); //true false true false false false // 0、''(空字符串) 、null、 undefined 、NaN 会转换成false 其它都会转换成true总结:字符串、数值及布尔类型的数据类型转换第4章 操作符表达式:值和操作符,运算会有一个结果;同时,表达式中的每个数值及部分表达式,又称为 子表达式4.1 算术运算符+ - * / % 取余(取模)4.2 一元运算符 *一元运算符:只有一个操作数的运算符,一元运算会直接修改原始变量的数据;5 + 6 两个操作数的运算符 二元运算符++ 自身加 (自增)-- 自身减 (自减)前置++var num1 = 5; ++ num1; var num2 = 6; console.log(num1 + ++ num2); //13后置++var num1 = 5; num1 ++; var num2 = 6 console.log(num1 + num2 ++); //12猜猜看var a = 1; var b = ++a + ++a; console.log(b); //5 var a = 1; var b = a++ + ++a; console.log(b);//4 var a = 1; var b = a++ + a++; // console.log(b); // 3 var a = 1; var b = ++a + a++; console.log(b);//4总结前置++:先加1,后参与运算后置++:先参与运算,后加1后置++ 运算的两个条件,满其一就会执行1:整个表达式结束;2表达式没结束但是又被使用了;上面两个理解后,下面两个自通前置-- :先减1,后参与运算后置-- :先参与运算,后减14.3 逻辑运算符(布尔运算符) *&& 与 左边为真则取右边,左边为假则取左边 || 或 左边为真则取左边,左边为假则边右边 ! 非 取反var a = 1; var b = 2; var c = 0; console.log(a || b); //1 console.log(b || a); //2 console.log(c && a); //0 console.log(a || c && b); //1 // JS逻辑运算中的逻辑或和逻辑与的运算结果: // 决定整个表达式的子表达式的值4.4 关系运算符(比较运算符)< > >= <= == != === !====与===的区别:==只进行值得比较,===类型和值同时相等,则相等 var result = '55' == 55; // true var result = '55' === 55; // false 值相等,类型不相等 var result = 55 === 55; // true4.5 赋值运算符注意与数学符号的差别;= += -= *= /= %=例如: var num = 0; num += 5; //相当于 num = num + 5;4.6 运算符的优先级 *优先级从高到底 1. () 优先级最高 2. 一元运算符 ++ -- ! 3. 算数运算符 先* / % 后 + - 4. 关系运算符 > >= < <= 5. 相等运算符 == != === !== 6. 逻辑运算符 先&& 后|| 7. 赋值运算符// 练习1: var s = 4 >= 6 || '人' != '阿凡达' && !(12 * 2 == 144) && true console.log(s); //true // 练习2: var num = 10; var f = 5 == num / 2 && (2 + 2 * num) console.log(f.toString() === 22) //false总结:操作符的使用,基本数学运算,一元运算符自增自减及前置后置的区别,逻辑运算符及取值,关系比较运算符,赋值运算符,运算符优先级;第5章 流程控制程序的三种基本结构顺序结构: 从上到下执行的代码就是顺序结构程序默认就是由上到下顺序执行的;分支结构:根据不同的情况及判断,执行对应代码;循环结构:重复执行一段代码;5.1 分支结构if语句语法结构if (/* 条件表达式 */) { // 执行语句 } if (/* 条件表达式 */){ // 成立执行语句 } else { // 否则执行语句 } if (/* 条件1 */){ // 成立执行语句 } else if (/* 条件2 */){ // 成立执行语句 } else if (/* 条件3 */){ // 成立执行语句 } else { // 最后默认执行语句 }案例//获取两个数字中的最大值 var num1=100; var num2=20; if(num1>num2){ console.log(num1); }else{ console.log(num2); }// 判断一个数是偶数还是奇数 var n = 10; if(n%2==0){ console.log('偶数'); }else{ console.log('奇数'); } /* * 例子: * 获取考试的分数,如果成绩是在90(含)分以上的,则显示级别:A * 如果成绩是大于等于80的则:B * 如果成绩是大于等于70的则:C * 如果成绩是大于等于60的则:D * 如果成绩是小于60的则:E * * */ var score = 91; if (score >= 90) { console.log("A"); } else if (score >= 80) { console.log("B"); } else if (score >= 70) { console.log("C"); } else if (score >= 60) { console.log("D"); } else { console.log("E"); }练习:判断一个年份是闰年还是平年闰年:能被4整除,但不能被100整除的年份 或者 能被400整除的年份var n = 2016; if(n%4==0){ if(n%100 !=0){ console.log('闰年'); }else if(n%400 ==0){ console.log('闰年'); }else{ console.log('平年'); } }else{ console.log('平年'); }三元运算符表达式1 ? 表达式2 : 表达式3 是对if……else语句的一种简化写法案例:// 是否年满18岁 var age = 18; var s = age>=18?'Yes':'no'; console.log(s);// 从两个数中找最大值 var a1 = 110; var a2 = 19; var s = a1>a2?a1:a2; console.log(s);switch语句语法格式:switch (expression) { case 常量1: 语句; break; case 常量2: 语句; break; … case 常量n: 语句; break; default: 语句; break; } /* * 执行过程: * 获取表达式的值,和值1比较,相同则执行代码1,遇到break跳出整个语句,结束 * 如果和值1不匹配,则和值2比较,相同则执行代码2,遇到break跳出整个语句,结束 * 如果和值2不匹配,则和值3比较,相同则执行代码3,遇到break跳出整个语句,结束 * 如果和值3不匹配,则和值4比较,相同则执行代码4,遇到break跳出整个语句,结束 * 如果和之前的所有的值都不一样,则直接执行代码5,结束 */break可以省略,如果省略,代码会继续执行下一个case switch 语句在比较值时使用的是全等操作符, 因此不会发生类型转换(例如,字符串'10' 不等于数值 10)/* * * 判断这个人的成绩的级别: * 如果是A,则提示,分数在90分以上 * 如果是B,则提示,分数在80分以上 * 如果是C,则提示,分数在70分以上 * 如果是D,则提示,分数在60分以上 * 否则提示,不及格 * */ var jiBie="B"; switch (jiBie){ case "A" : console.log("分数在90分以上的"); break; case "B" : console.log("分数在80分以上的"); break; case "C" : console.log("分数在70分以上的"); break; case "D" : console.log("分数在60分以上的"); break; default : console.log("不及格"); } 5.2 循环结构在JS语言中,循环语句有三种,while、do..while、for循环。5.2.1 while语句基本语法:// 当循环条件为true时,执行循环体, // 当循环条件为false时,结束循环。 while (循环条件) { //循环体 }案例1:计算1-100之间所有数的和// 初始化变量 var i = 1; var sum = 0; // 判断条件 while (i <= 100) { // 循环体 sum += i; // 自增 i++; } console.log(sum);案例2:打印100以内 7的倍数var i = 1; while(i<100){ if(i%7==0){ console.log(i); } i++; }案例3:打印100以内所有偶数var i = 1; while(i<=100){ if(i%2==0){ console.log(i); } i++; }案例4:打印100以内所有偶数的和var i = 1; var s = 0; while(i<=100){ if(i%2==0){ s = s+i; } i++; } console.log(s);练习:打印100以内的奇数打印100以内的奇数的和5.2.2 do...while语句do..while循环和while循环非常像,二者经常可以相互替代,但是do..while的特点是不管条件成不成立,都会执行一次。do { // 循环体; } while (循环条件);案例:计算1+2+3+4+……+99+100 的结果// 初始化变量 var i = 0; var sum = 1; do { sum += i;//循环体 i++;//自增 } while (i <= 100);//循环条件5.2.3 for语句while和do...while一般用来解决无法确认次数的循环。for循环一般在循环次数确定的时候比较方便for循环语法:// for循环的表达式之间用的是;号分隔的,千万不要写成, for (初始化表达式1; 判断表达式2; 自增表达式3) { // 循环体4 }执行顺序:1243 ---- 243 -----243(直到循环条件变成false)初始化表达式判断表达式自增表达式循环体//打印1-100之间所有数 for(var i=1;i<=100;i++){ console.log(i); } //求1-100之间所有数的和 var s = 0; for(var i=0;i<=100;i++){ s+=i; } console.log(s); //求1-100之间所有偶数的和 var s = 0; for(var i=1;i<=100;i++){ if(i%2==0){ s+=i; } } console.log(s); //打印正方形 var start = ''; for (var i = 0; i < 10; i++) { for (var j = 0; j < 10; j++) { start += '* '; } start += '\n'; } console.log(start); //打印直角三角形 var start = ''; for (var i = 0; i < 10; i++) { for (var j = i; j < 10; j++) { start += '* '; } start += '\n'; } console.log(start); //打印9*9乘法表 var str = ''; for (var i = 1; i <= 9; i++) { for (var j = i; j <=9; j++) { str += i + ' * ' + j + ' = ' + i * j + '\t'; } str += '\n'; } console.log(str);5.2.4 continue和breakbreak:立即跳出整个循环,即循环结束,开始执行循环后面的内容(直接跳到大括号)continue:立即跳出当前循环,继续下一次循环(跳到i++的地方)案例1:求1-100之间不能被7整除的整数的和(用continue)var s = 0; for(var i=0;i<100;i++){ if(i%7==0){ continue; } s+=i; } console.log(s);案例2:求200-300之间所有的奇数的和(用continue)var s = 0; for(var i=200;i<=300;i++){ if(i%2==0){ continue; }else{ s+=i; } } console.log(s);案例3:求200-300之间第一个能被7整数的数(break)for(var i=200;i<=300;i++){ if(i%7==0){ console.log(i); break; } }总结:代码的执行流程分为顺序、分支和循环三种结构,顺序结构是默认的,判断结构主要有if-else和switch-case两种,循环结构有while、do-while、for三种,其中continue和break是跳出循环;第6章 JS中特殊的对象-数组之前学习的数据类型,只能存储一个值(比如:Number/String)。我们想在一个变量中存储多个值,应该如何存储?所谓数组,就是将多个元素(通常是同一类型)按一定顺序排列放到一个集合中,那么这个集合我们就称之为数组。6.1 数组的创建// 字面量方式创建数组 var arr1 = []; //空数组 // 创建一个包含3个数值的数组,多个数组项以逗号隔开 var arr2 = [1, 3, 4]; // 创建一个包含2个字符串的数组 var arr3 = ['a', 'c']; console.log(arr1); console.log(arr2); console.log(arr3); // 可以通过数组的length属性获取数组的长度 console.log(arr3.length); // 可以设置length属性改变数组中元素的个数 arr3.length = 0; console.log(arr3[0]);//undefined数组的元素可以是任意类型的数据,因此,有时数组中的某个元素的值又是一个数组,而这样的数组被称为多维数组,如果数组中只有其他类型的数据,而没有另外的数组值,这样的数组被称为一维数组;通常,数组被嵌套N层,则称为N维数组,最常见的就是二维数组、三维数组、四维数组,超过一维的数组都会被泛称为多维数组;数组的维度值越大,复杂度就越高,开发中尽量避免产生高维度值的数组;var arr1 = [a,b,c]; // 一维数组 var arr2 = [a,b,c,[d,e]]; // 二维数组 var arr3 = [a,b,c,[d,e,[f,g]]]; // 三维数组 var arr4 = [a,b,c,[d,e,[f,g,[h,t,y]]]]; // 四维数组6.2 获取数组元素// 格式:数组名[下标] 下标又称索引 // 下标从0开始 // 功能:获取数组对应下标的那个值,如果下标不存在,则返回undefined。 var arr = ['red',, 'green']; arr[0]; // red arr[1]; // undefined 下标位置没有数据 arr[2]; // green arr[5]; // 这个数组的最大下标为2,因此返回undefined// 获取多维数组的数据 var arr = ['路飞','娜美',['巴基','女帝',['佐助','乔巴']]]; console.log(arr[2][2][0]); //佐助6.3 遍历数组遍历:遍及所有,对数组的每一个元素都访问一次就叫遍历。for循环数组遍历的基本语法:for(var i = 0; i < arr.length; i++) { // 数组遍历的固定结构 }for循环示例:var arr1 = [1, 3, 4]; for(var i = 0;i<arr1.length;i++){ console.log(arr1[i]); }whil循环示例:var arr1 = [1, 3, 4]; var i = 0; while(i<arr1.length){ console.log(arr1[i]); i++; }6.4 为数组修改添加元素// 格式:数组名[下标/索引] = 值; // 如果下标有对应的值,会把原来的值覆盖,如果下标不存在,会给数组新增一个元素。 var arr = ["red", "green", "blue"]; // 把red替换成了yellow arr[0] = "yellow"; // 给数组新增加了一个pink的值 arr[3] = "pink";6.5 数组操作案例案例1:求数组中的所有数的和//求和 var arr = [10, 20, 30, 40, 50]; //定义变量存储和 var sum = 0; for (var i = 0; i < arr.length; i++) { sum += arr[i]; } console.log("和为:" + sum);案例2:获取数组中的最大值//最大值 var arr = [10, 20, 30, 40, 50, 60]; //假设这个变量中的值是最大的 var maxNum = arr[0]; //遍历数组 for (var i = 0; i < arr.length; i++) { //判断 if (maxNum < arr[i]) { maxNum = arr[i]; } } console.log("最大值是:" + maxNum);案例3: 遍历出数组中所有的偶数// 遍历出数组中所有的偶数 var arr = [1,2,3,4,5,6,7]; for(var i=0;i<arr.length;i++){ //判断 if(arr[i]%2==0){ console.log(arr[i]); } }案例4:将数组转为字符串并以 | 分割//把数组中的每个名字后面拼接一个|然后以字符串的方式输出 var names = ["卡卡西", "佐助", "凤姐", "鸣人", "黑崎一护"]; var str = "";//空的字符串,用来存储最后的拼接的结果的字符串 //不停的遍历数组的数据,并且拼接字符串 for (var i = 0; i < names.length - 1; i++) { str += names[i] + "|";//拼接字符串的方式 } str += names[names.length - 1]; console.log(str);总结:数组就是多个数据的集合,有一维数组和多维数组之分,可以使用字面量方式创建数组,使用下标来获取数组元素数据,使用for或者while循环来遍历数组元素;第7章 函数把一段相对独立的具有特定功能的代码块封装起来,形成一个独立实体,就是函数,起个名字(函数名),在后续开发中可以反复调用函数的作用就是封装一段代码,将来可以重复使用7.1 函数的声明及调用7.1.1 声明关键字声明function 函数名(){ // 函数体 }表达式声明var fn = function() { // 函数体 }特点:函数声明的时候,函数体并不会执行,只要当函数被调用的时候才会执行。一个函数一般都特定的用来干 一件 事情7.1.2 调用调用函数的语法:函数名();特点:函数体只有在调用的时候才会执行,调用需要()进行调用。可以调用多次(重复使用)// 声明函数 function sayHi() { console.log("吃了没?"); } // 调用函数 sayHi(); // 求1-100之间所有数的和 function getSum() { var sum = 0; for (var i = 0; i < 100; i++) { sum += i; } console.log(sum); } // 一段代码可以多次调用 getSum(); getSum(); getSum();7.2 参数为什么要有参数function getSum() { var sum = 0; for (var i = 1; i <= 100; i++) { sum += i; } console.log(); } // 虽然上面代码可以重复调用,但是只能计算1-100之间的值 // 如果想要计算n-m之间所有数的和,应该怎么办呢?语法:// 函数内部是一个封闭的环境,可以通过参数的方式,把外部的值传递给函数内部 // 带参数的函数声明 function 函数名(形参1, 形参2, 形参...){ // 函数体 } // 带参数的函数调用 函数名(实参1, 实参2, 实参3);形参和实参* 形式参数:在声明一个函数的时候,为了函数的功能更加灵活,有些值是固定不了的,对于这些固定不了的值。我们可以给函数设置参数。这个参数没有具体的值,仅仅起到一个占位置的作用,我们通常称之为形式参数,也叫形参。实际参数:如果函数在声明时,设置了形参,那么在函数调用的时候就需要传入对应的参数,我们把传入的参数叫做实际参数,也叫实参。function fn(a, b) { console.log(a + b); } var x = 5, y = 6; fn(x,y); // x,y实参,有具体的值。 // 函数执行的时候会把x,y复制一份给函数内部的a和b, // 函数内部的值是复制的新值,无法修改外部的x,yJS 函数在调用时,允许传多个实参,就是实参个数可以比形参个数多;7.3 函数的返回值当函数执行完的时候,并不是所有时候都要把结果打印。我们期望函数给我一些反馈(比如计算的结果返回进行后续的运算),这个时候可以让函数返回一些东西。也就是返回值。函数通过return返回一个值返回值语法://声明一个带返回值的函数 function 函数名(形参1, 形参2, 形参...){ //函数体 return 返回值; } //可以通过变量来接收这个返回值 var 变量 = 函数名(实参1, 实参2, 实参3);返回值详解:* 如果函数没有显示的使用 return语句 ,那么函数有默认的返回值:undefined如果函数使用 return语句,那么跟在return后面的值,就成了函数的返回值如果函数使用 return语句,但是return后面没有任何值,那么函数的返回值也是:undefined函数使用return语句后,这个函数会在执行完 return 语句之后停止并立即退出,也就是说return后面的所有其他代码都不会再执行。7.4 函数相关的其它事情7.4.1 匿名函数与自调用函数匿名函数:没有名字的函数匿名函数如何使用:将匿名函数赋值给一个变量,这样就可以通过变量进行调用var fun1 = function(){ console.log(1); } fun1();匿名函数如果没有任何变量来表示它,那么就不能直接调用来执行,因此可以通过匿名函数的自调用的方式来执行(function () { alert(123); })();关于自执行函数(匿名函数自调用)的作用:防止全局变量污染。7.4.2 函数本身也是值 *function fn() {} console.log(typeof fn);函数作为参数因为函数也是一种值类型,可以把函数作为另一个函数的参数,在另一个函数中调用function f1(f){ f(); } function f2(){ console.log(2); } f1(f2); //2函数做为返回值因为函数是一种类型,所以可以把函数可以作为返回值从函数内部返回。function fn(b) { var a = 10; return function () { alert(a+b); } } var f = fn(5); f(); //15总结:函数是一段代码的封装,可重复多次运行,函数的声明有表达式声明和关键字声明,使用 ·函数名()· 的方式进行调用,调用时传入的参数为实参,声明时的参数时形参,函数使用return返回值,函数可以是没有名字的匿名函数,函数本身也可以当做值使用;第8章 作用域与JS代码的运行 *作用域:变量可以起作用的范围和区域8.1 全局变量和局部变量 *全局变量与全局作用域在任何地方都可以访问到的变量就是全局变量,全局变量所在的区域就是全局作用域局部变量只在固定的代码片段内可访问到的变量,最常见的例如函数内部的变量,就是局部变量。局部变量所在的区域就是局部作用域(函数作用域)不使用var声明的变量是全局变量,不推荐使用。 变量退出作用域之后会销毁,全局变量关闭网页或浏览器才会销毁8.2 变量提升console.log(a); // undefined var a = 2;console.log(a); // a is not defined变量提升定义变量的时候,变量的声明会被提升到作用域的最上面,变量的赋值不会提升。函数提升JavaScript解析器首先会把当前作用域的函数声明提前到整个作用域的最前面f(); function f(){ console.log(12); //12 }var f = 1; function f(){ console.log(12); //12 } // 由于函数提升在前,所以被变量声明替换了; // 执行阶段,变量被复制为1,不再是一个函数, f(); // f is not a function注:不管是普通变量还是函数,尽量不要出现重名;8.3 JS代码的运行 *console.log(s); //undefined var s = 2;JavaScript代码的执行是由浏览器中的JavaScript解析器来执行的。JavaScript解析器执行JavaScript代码的时候,分为两个过程:预解析(编译)过程和代码执行过程预解析过程:语法检查,如果有错误,直接停止后续步骤不再运行。把变量和函数的声明提升到当前作用域的最前面,只会提升声明,不会提升赋值和调用。先提升变量后提升函数,如果函数和变量同名,则被替换;代码执行过程变量的赋值,函数的调用,循环判断等,根据代码由上往下顺序执行;var a = 25; function abc (){ alert(a);//undefined var a = 10; } abc(); // 如果变量和函数同名的话,函数优先做提升 console.log(a); function a() { console.log('aaaaa'); } var a = 1; console.log(a); // 1、---------------- var num = 10; fun(); function fun() { console.log(num); //undefined var num = 20; } // 2、---------------- var a = 18; f1(); function f1() { var b = 9; console.log(a); //undefined console.log(b); // 9 var a = '123'; }8.4 词法作用域变量的作用域是在定义时决定而不是执行时决定的,也就是说词法作用域取决于编译阶段,通过静态分析就能确定,因此词法作用域也叫做静态作用域。在 js 中词法作用域规则:函数允许访问函数外的数据.整个代码结构中只有函数可以限定作用域.作用域规则首先使用提升规则分析如果当前作用规则中有名字了, 就不考虑外面的名字var num = 123; function foo() { console.log( num ); } foo(); if ( false ) { var num = 123; } console.log( num ); // undefiend也就是说:函数内部可以访问函数外部的变量,但是函数外部不可以访问函数内部的变量;函数内部如果有变量,则优先使用内部的变量,如果函数内部没有,才会使用函数外部的变量;8.5 作用域链 *只有函数可以制造作用域结构, 那么只要是代码,就至少有一个作用域, 即全局作用域。凡是代码中有函数,那么这个函数就构成另一个作用域。如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域。 将这样的所有的作用域列出来,可以有一个结构: 函数内指向函数外的链式结构。就称作作用域链。var a = 1; function fn1(){ function fn2(){ function fn3(){ console.log(a); } fn3(); } fn2(); } fn1();var a = 1; function fn1(){ var a = 2; function fn2(){ var a = 3; function fn3(){ console.log(a); } fn3(); } fn2(); } fn1();总结:函数内部是JS代码的局部作用域,函数外部是全局作用域,JS 代码的运行分为与解析阶段和执行阶段,变量的声明实在与解析阶段的,所以变量存在提升,而变量只在自己的作用域中起作用,但是自己作用域是可以访问上级作用域的;第9章 对象(Object)9.1 什么是对象万物皆对象现实生活中:万物皆对象,对象是一个具体的事物,一个具体的事物就会有行为和特征。 举例: 一部车,一个手机 车是一类事物,门口停的那辆车才是对象 特征:红色、四个轮子 行为:驾驶、刹车9.2 JavaScript中的对象JavaScript中的对象其实就是生活中对象的一个抽象 JavaScript的对象是无序属性的集合。 其属性可以包含基本值、对象、数组或函数。 对象就是一组没有顺序的值。 我们可以把JavaScript中的对象想象成键值对,其中值可以是数据和函数。 对象的行为和特征 特征---属性 行为---方法事物的特征在对象中用属性来表示。事物的行为在对象中用方法来表示。属性和方法统称为对象的成员。9.3 如何得到一个对象字面量方式创建对象var obj1 = {};//得到一个空对象 var obj2 = {name:'张三',age:18};//得到拥有两个属性的对象 //得到拥有两个属性和一个方法的对象 var obj3 = { name:'张三', age:18, fei:function(){ console.log('你上天啊!'); } }new Object() 创建对象 (内置构造函数)var person = new Object(); person.name = 'lisi'; person.age = 35; person.sayHi = function(){ console.log('Hello,everyBody'); }自定义构造函数创建对象function Person(name,age,job){ this.name = name; this.age = age; this.job = job; this.sayHi = function(){ console.log('Hello,everyBody'); } } var p1 = new Person('张三', 22, 'actor');new关键字和构造函数构造函数 ,是一种特殊的函数,又叫做函数构造器。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。构造函数用于创建一类对象,首字母通常大写。构造函数要和new一起使用才有意义。new 关键字也读做实例化。实例化构造函数,得到一个对象。9.4 this 的指向JavaScript中的this指向问题,比较复杂,有时候会让人难以捉摸,随着学习的深入,我们会不断接触this,在学习过程中,我们可以不断总结,最终搞清楚this在何种情况下指向何处……目前,我们只需要记住以下两点就可以了:1: 函数如果在某个对象下,this就指向这个对象2: 函数如果被直接调用,this指向window对象var o1 = { name: '山治', f: function () { console.log(this.name); } } o1.f(); // 山治function f(){ console.log(this); } f(); console.log(window);9.5 对象的使用方法及属性的使用对象.方法名(); //调用对象的方法 对象.属性; //获取对象的属性遍历对象的属性通过for..in语法可以遍历一个对象var obj1 = { name:'路飞', age : 17, sex : '男', } for(var k in obj1){ console.log(k); console.log(obj1[k]); }注意:使用for …in语法,同样可以遍历数组注意:如果属性名或方法名,是一个变量,则使用对象[变量名] 语法删除对象的属性var obj1 = { name:'路飞', age : 17, sex : '男', } console.log(obj1.age); //17 delete obj1.age; //删除对象中指定的属性 console.log(obj1.age); // undefined总结:创建对象有三种方式,字面量、new内置构造函数及自定义构造函数;对象中有属性及方法,this指向当前对象,使用 . (点) 语法调用属性及方法;第10章 标准库对象(内置对象)JavaScript 提供了很多个内置对象:Math/Array/Number/String/Boolean...对象只是带有属性和方法的特殊数据类型。我们在学习时其实就是要记住对象的每个属性和方法怎么使用,代表什么含义;技术问题,遇到分歧,去哪里查找资料:火狐开发者社区--MDN微软开发者社区--MSDN10.1 Math对象https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Math10.1.1 常用属性和方法Math 是一个内置对象, 它具有数学常数和函数的属性和方法。不是一个函数对象。与其它全局对象不同的是, Math 不是一个构造函数. Math 的所有属性和方法都是静态的.跟数学相关的运算直接使用Math中的成员即可console.log(Math.PI); //圆周率3.141592653589793 Math.random();//介于 0 和 1 之间的伪随机数。 Math.ceil(6.6);//获取大于或等于提供数值的最小整数--向上取整 Math.floor(8.8);//获取小于或等于提供数值的最大整数--向下取整 Math.round(9.9);//四舍五入 Math.max(10,20,15);//取多个值中的最大值 Math.min(10,20,15);//取多个值中的最小值 Math.pow(10,2);//返回x的y次幂 Math.sqrt(100);//求平方根 10.1.2 案例求10-20之间的随机数Math.floor(Math.random() * (max - min)) + min; 10.1.3 属性方法对照表Math对象的属性(常量)属性(常量)描述Math.E 常量.aspx)数学常数 e。这是欧拉数,自然对数的底。Math.LN2 常量.aspx)2 的自然对数。Math.LN10 常量.aspx)10 的自然对数。Math.LOG2E 常量.aspx)以 2 为底 e 的对数。Math.LOG10E 常量.aspx)以 10 为底 e 的对数。Math.PI 常量.aspx)Pi。这是圆的周长与直径的比值。Math.SQRT1_2 常量.aspx)0.5 的平方根,或相当于 1 除以 2 的平方根。Math.SQRT2 常量.aspx)2 的平方根。Math对象的方法(函数)方法(函数)描述Math.abs 函数.aspx)返回数字的绝对值。Math.acos 函数.aspx)返回数字的反余弦值。Math.acosh 函数.aspx)返回数字的双曲反余弦值(或反双曲余弦值)。Math.asin 函数.aspx)返回数字的反正弦值。Math.asinh 函数.aspx)返回数字的反双曲正弦。Math.atan 函数.aspx)返回数字的反正切值。Math.atan2 函数.aspx)将与 X 轴的角度(以弧度为单位)返回到由 y 和 x 坐标表示的点。Math.atanh 函数.aspx)返回数字的反双曲正切。Math.ceil 函数.aspx)返回大于或等于提供的数值表达式的最小整数。Math.cos 函数.aspx)返回数字的余弦值。Math.cosh 函数.aspx)返回数字的双曲余弦。Math.exp 函数.aspx)返回 e(自然对数的底)的乘幂数。Math.expm1 函数.aspx)返回 e(自然对数的底)的乘幂数减去 1 的结果。Math.floor 函数.aspx)返回小于或等于提供的数值表达式的最大整数。Math.hypot 函数.aspx)返回参数平方和的平方根。Math.imul 函数.aspx)返回被视为 32 位带符号整数的两个数字的积。Math.log 函数.aspx)返回数字的自然对数。Math.log1p 函数.aspx)返回 1 加上一个数字的的自然对数。Math.log10 函数.aspx)返回数字以 10 为底的对数。Math.log2 函数.aspx)返回数字以 2 为底的对数。Math.max 函数.aspx)返回提供的两个数值表达式中的较大值。Math.min 函数.aspx)返回提供的两个数字中的较小值。Math.pow 函数.aspx)返回基表达式的指定乘幂数的值。Math.random 函数.aspx)返回介于 0 和 1 之间的伪随机数。Math.round 函数.aspx)返回舍入到最近整数的指定数值表达式。Math.sign 函数.aspx)返回数字符号,它指示数字为正数、负数还是 0。Math.sin 函数.aspx)返回数字的正弦值。Math.sinh 函数.aspx)返回数字的反双曲正弦。Math.sqrt 函数.aspx)返回数字的平方根。Math.tan 函数.aspx)返回数字的正切值。Math.tanh 函数.aspx)返回数字的双曲正切。Math.trunc 函数.aspx)返回数字的整数部分,删除任何小数数字。10.2 Date对象(构造函数)https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Date10.2.1 常用属性和方法创建 Date 实例用来处理日期和时间。Date 对象基于1970年1月1日(世界标准时间)起的毫秒数。// 获取当前时间,UTC世界时间,距1970年1月1日(世界标准时间)起的毫秒数 var now = new Date(); console.log(now.getTime()); // 获取距1970年1月1日(世界标准时间)起的毫秒数 console.log(now.valueOf()); // valueOf用于获取对象的原始值,与getTime()方法相同 Date构造函数的参数 1. 毫秒数 1498099000356 new Date(1498099000356) 2. 日期格式字符串 '2015-5-1' new Date('2015-5-1') 3. 年、月、日…… new Date(2015, 4, 1) // 月份从0开始获取日期的毫秒形式var now = new Date(); console.log(now.getTime()); // valueOf用于获取对象的原始值 console.log(now.valueOf()); // HTML5中提供的方法,有兼容性问题 var now = Date.now(); // 不支持HTML5的浏览器,可以用下面这种方式 var now = + new Date(); // 隐式调用 Date对象的valueOf() 日期格式化方法toString() // 转换成字符串 valueOf() // 获取毫秒值 // 下面格式化日期的方法,在不同浏览器可能表现不一致,一般不用 toDateString() toTimeString() toLocaleDateString() toLocaleTimeString()获取日期指定部分getTime() // 返回毫秒数和valueOf()结果一样,valueOf()内部调用的getTime() getSeconds() // 返回0-59 getMinutes() // 返回0-59 getHours() // 返回0-23 getDay() // 返回星期几 0周日 6周6 getDate() // 返回当前月的第几天 getMonth() // 返回月份,***从0开始*** getFullYear() //返回4位的年份 如 201610.2.2 案例案例1:写一个函数,格式化日期对象,返回yyyy-MM-dd HH:mm:ss的形式function formatDate(d) { //如果date不是日期对象,返回 if (!date instanceof Date) { return; } var year = d.getFullYear(), month = d.getMonth() + 1, date = d.getDate(), hour = d.getHours(), minute = d.getMinutes(), second = d.getSeconds(); month = month < 10 ? '0' + month : month; date = date < 10 ? '0' + date : date; hour = hour < 10 ? '0' + hour : hour; minute = minute < 10 ? '0' + minute:minute; second = second < 10 ? '0' + second:second; return year + '-' + month + '-' + date + ' ' + hour + ':' + minute + ':' + second; }计算时间差,返回相差的天/时/分/秒function getInterval(start, end) { var day, hour, minute, second, interval; interval = end - start; interval /= 1000; day = Math.round(interval / 60 /60 / 24); hour = Math.round(interval / 60 /60 % 24); minute = Math.round(interval / 60 % 60); second = Math.round(interval % 60); return { day: day, hour: hour, minute: minute, second: second } }10.2.3 方法对照表Date对象 的方法。方法描述getDate 方法.aspx)使用当地时间返回一个月某天的值。getDay 方法.aspx)使用当地时间返回一个星期某天的值。getFullYear 方法.aspx)使用当地时间返回年份值。getHours 方法.aspx)使用当地时间返回小时值。getMilliseconds 方法.aspx)使用当地时间返回毫秒值。getMinutes 方法.aspx)使用当地时间返回分钟值。getMonth 方法.aspx)使用当地时间返回月份值。getSeconds 方法.aspx)使用当地时间返回秒值。getTime 方法.aspx)将 Date 对象中的时间值返回为自 1970 年 1 月 1 日午夜起经过的毫秒数。getTimezoneOffset 方法.aspx)返回主机的时间与协调通用时间 (UTC) 之间的分钟差值。getUTCDate 方法.aspx)使用 UTC 返回一个月某天的值。getUTCDay 方法.aspx)使用 UTC 返回一个星期某天的值。getUTCFullYear 方法.aspx)使用 UTC 返回年份值。getUTCHours 方法.aspx)使用 UTC 返回小时值。getUTCMilliseconds 方法.aspx)使用 UTC 返回毫秒值。getUTCMinutes 方法.aspx)使用 UTC 返回分钟值。getUTCMonth 方法.aspx)使用 UTC 返回月份值。getUTCSeconds 方法.aspx)使用 UTC 返回秒值。getVarDate 方法.aspx)将 Date 对象中的 VT_DATE 值返回。getYear 方法.aspx)返回年份值。hasOwnProperty 方法.aspx)返回一个布尔值,该值指示一个对象是否具有指定名称的属性。isPrototypeOf 方法.aspx)返回一个布尔值,该值指示对象是否存在于另一个对象的原型链中。propertyIsEnumerable 方法.aspx)返回一个布尔值,该值指示指定属性是否为对象的一部分以及该属性是否是可枚举的。setDate 方法.aspx)使用当地时间设置一个月中某一日的数值。setFullYear 方法.aspx)使用当地时间设置年份值。setHours 方法.aspx)使用当地时间设置小时值。setMilliseconds 方法.aspx)使用当地时间设置毫秒值。setMinutes 方法.aspx)使用当地时间设置分钟值。setMonth 方法.aspx)使用当地时间设置月份值。setSeconds 方法.aspx)使用当地时间设置秒值。setTime 方法.aspx)设置 Date 对象中的日期和时间值。setUTCDate 方法.aspx)使用 UTC 设置一个月中某一日的数值。setUTCFullYear 方法.aspx)使用 UTC 设置年份值。setUTCHours 方法.aspx)使用 UTC 设置小时值。setUTCMilliseconds 方法.aspx)使用 UTC 设置毫秒值。setUTCMinutes 方法.aspx)使用 UTC 设置分钟值。setUTCMonth 方法.aspx)使用 UTC 设置月份值。setUTCSeconds 方法.aspx)使用 UTC 设置秒值。setYear 方法.aspx)使用当地时间设置年份值。toDateString 方法.aspx)以字符串值的形式返回一个日期。toGMTString 方法.aspx)返回使用格林尼治标准时间 (GMT) 转换为字符串的日期。toISOString 方法.aspx)以字符串值的形式返回采用 ISO 格式的日期。toJSON 方法.aspx)用于在 JSON 序列化之前转换目标类型的数据。toLocaleDateString 方法.aspx)将一个日期以字符串值的形式返回,该字符串应适合于宿主环境的当前区域设置。toLocaleString 方法.aspx)返回使用当前区域设置转换为字符串的对象。toLocaleTimeString 方法.aspx)以字符串值的形式返回一个时间,此字符串值应与宿主环境的当前区域设置相适应。toString 方法.aspx)返回表示对象的字符串。toTimeString 方法.aspx)以字符串值形式返回时间。toUTCString 方法.aspx)返回使用 UTC 转换为字符串的日期。valueOf 方法.aspx)返回指定对象的原始值。10.3 Array对象https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array10.3.1 常用属性和方法length属性: 返回数组的成员数量。var arr = ['a', 'b']; console.log(arr.length) // 2常用方法push方法用于在数组的末端添加一个或多个元素,并返回添加新元素后的数组长度。注意,该方法会改变原数组。var a = []; a.push(1) // 1 a.push('a') // 2 a.push(true, {}) // 4 console.log(a); //[1, 'a', true, {}]pop方法用于删除数组的最后一个元素,并返回该元素。注意,该方法会改变原数组var a = ['a', 'b', 'c']; a.pop() // 'c' console.log(a);// ['a', 'b']slice方法用于提取原数组的一部分,返回一个新数组,原数组不变。它的第一个参数为起始位置(从0开始),第二个参数为终止位置(但该位置的元素本身不包括在内)。 如果省略第二个参数,则一直返回到原数组的最后一个成员。var a = ['a', 'b', 'c']; a.pop() // 'c' console.log(a);// ['a', 'b']join方法用于将数组元素以指定字符拼接为字符串,返回一个字符串,原数组不变。var a = ['a','b','c','d','e']; console.log(a.join('-')) // 'a-b-c-d-e'返回数组的字符串表示形式。var arr = [1, 2, 3, 4]; console.log(arr.toString()); //1,2,3,410.3.2 方法和属性对照表Array 对象的属性。属性描述length 属性.aspx)返回一个整数值,此整数比数组中所定义的最高位元素大 1,是实际元素个数。Array 对象的方法。方法描述concat 方法(数组).aspx)返回由两个数组组合而成的新数组。entries 方法.aspx)返回包含数组的键/值对的迭代器。every 方法.aspx)检查定义的回调函数是否为数组中的所有元素返回 true。fill 方法.aspx)使用指定值填充数组。filter 方法.aspx)对数组的每个元素调用定义的回调函数,并返回回调函数为其返回 true 的值的数组。findIndex 方法.aspx)返回满足回调函数中指定的测试条件的第一个数组元素的索引值。forEach 方法.aspx)为数组中的每个元素调用定义的回调函数。hasOwnProperty 方法.aspx)返回一个布尔值,该值指示某个对象是否具有指定名称的属性。indexOf 方法(数组).aspx)返回某个值在数组中的第一个匹配项的索引。isPrototypeOf 方法.aspx)返回一个布尔值,该值指示某个对象是否存在于另一个对象的原型链中。join 方法.aspx)返回由一个数组的所有元素串联而成的 String 对象。keys 方法.aspx)返回包含数组的索引值的迭代器。lastIndexOf 方法(数组).aspx)返回指定值在数组中的最后一个匹配项的索引。map 方法.aspx)对数组的每个元素调用定义的回调函数并返回包含结果的数组。pop 方法.aspx)从数组中移除最后一个元素并将该元素返回。propertyIsEnumerable 方法.aspx)返回一个布尔值,该值指示指定属性是否为对象的一部分且是否可枚举。push 方法.aspx)将新元素追加到一个数组中,并返回数组的新长度。reduce 方法.aspx)通过对数组中的所有元素调用定义的回调函数来累积单个结果。 回调函数的返回值是累积的结果,并且作为对回调函数的下一个调用中的参数提供。reduceRight 方法.aspx)通过对数组中的所有元素调用定义的回调函数来按降序顺序累积单个结果。 回调函数的返回值是累积的结果,并且作为对回调函数的下一个调用中的参数提供。reverse 方法.aspx)将元素顺序被反转的 Array 对象返回。shift 方法.aspx)从数组中移除第一个元素并将返回该元素。slice 方法(数组).aspx)返回一个数组中的一部分。some 方法.aspx)检查定义的回调函数是否为数组的任何元素返回 true。sort 方法.aspx)返回一个元素已经进行了排序的 Array 对象。splice 方法.aspx)从一个数组中移除元素,如有必要,在所移除元素的位置上插入新元素,并返回所移除的元素。toLocaleString 方法.aspx)返回使用当前区域设置的字符串。toString 方法.aspx)返回数组的字符串表示形式。unshift 方法.aspx)在数组的开头插入新元素。valueOf 方法.aspx)获取对数组的引用。values 方法.aspx)返回包含数组的值的迭代器。10.4 String对象https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String10.4.1 常用属性和方法var s = 'JavaScript'; // length属性返回字符串的长度。 var i = s.length; //返回参数在字符串中第一次出现的位置 var i = s.indexOf('b'); //从原字符串取出子字符串并返回,不改变原字符串 var i = s.substr(2,4);//从下标第二个开始截取4个长度的字符串 //toLowerCase方法用于将一个字符串全部转为小写 //toUpperCase则是全部转为大写 var i = s.toLowerCase(); var i = s.toUpperCase(); // 用于替换匹配的子字符串,只替换第一个匹配 var i = s.replace('a','b'); console.log(i);10.4.2 方法和属性对照表String 对象的属性。属性描述constructor 属性.aspx)指定用于创建对象的函数。length 属性(字符串).aspx)返回 String 对象的长度。prototype 属性.aspx)为对象的类返回原型的引用。String 对象的方法。方法描述anchor 方法.aspx)将具有 NAME 特性的 HTML 定位点放置在文本两侧。big 方法.aspx)将 HTML 标记放置在文本两侧。blink 方法.aspx)将 HTML 标记放置在文本两侧。bold 方法.aspx)将 HTML 标记放置在文本两侧。charAt 方法.aspx)返回指定索引处的字符。charCodeAt 方法.aspx)返回指定字符的 Unicode 编码。codePointAt 方法.aspx)返回一个 Unicode UTF-16 字符的码位。concat 方法(字符串).aspx)返回由提供的两个字符串串联而成的字符串。EndsWith 方法.aspx)返回一个布尔值,该值指示字符串或子字符串是否以传入字符串结尾。includes 方法.aspx)返回一个布尔值,该值指示传入字符串是否包含在字符串对象中。fixed 方法.aspx)将 HTML 标记放置在文本两侧。fontcolor 方法.aspx)将具有 COLOR 特性的 HTML 标记放置在文本两侧。fontsize 方法.aspx)将具有 SIZE 特性的 HTML 标记放置在文本两侧。hasOwnProperty 方法.aspx)返回一个布尔值,该值指示某个对象是否具有指定名称的属性。indexOf 方法(字符串).aspx)返回字符串内第一次出现子字符串的字符位置。isPrototypeOf 方法.aspx)返回一个布尔值,该值指示某个对象是否存在于另一个对象的原型链中。italics 方法.aspx)将 HTML 标记放置在文本两侧。lastIndexOf 方法(字符串).aspx)返回字符串内子字符串的最后一个匹配项。link 方法.aspx)将具有 HREF 特性的 HTML 定位点放置在文本两侧。localeCompare 方法.aspx)返回一个值,该值指示两个字符串在当前区域设置中是否相等。match 方法.aspx)通过使用提供的正则表达式对象来搜索字符串并以数组形式返回结果。normalize 方法.aspx)返回指定字符串的 Unicode 范式。propertyIsEnumerable 方法.aspx)返回一个布尔值,该值指示指定属性是否为对象的一部分且是否可枚举。repeat 方法.aspx)返回一个新的字符串对象,它的值等于重复了指定次数的原始字符串。replace 方法.aspx)使用正则表达式替换字符串中的文本并返回结果。search 方法.aspx)返回正则表达式搜索中第一个子字符串匹配项的位置。slice 方法(字符串).aspx)返回字符串的片段。small 方法.aspx)将 HTML 标记放置在文本两侧。split 方法.aspx)返回一个字符串拆分为若干子字符串时所产生的字符串数组。StartsWith 方法.aspx)返回一个布尔值,该值指示字符串或子字符串是否以传入字符串开头。strike 方法.aspx)将 HTML 标记放置在文本两侧。sub 方法.aspx)将 HTML 标记放置在文本两侧。substr 方法.aspx)返回一个从指定位置开始且具有指定长度的子字符串。substring 方法.aspx)返回 String 对象中指定位置处的子字符串。sup 方法.aspx)将 HTML 标记放置在文本两侧。toLocaleLowerCase 方法.aspx)返回一个字符串,其中所有字母字符都转换为小写形式,并将考虑主机环境的当前区域设置。toLocaleString 方法.aspx)返回使用当前区域设置转换为字符串的对象。toLocaleUpperCase 方法.aspx)返回一个字符串,其中所有字母字符都转换为大写形式,并将考虑主机环境的当前区域设置。toLowerCase 方法.aspx)返回一个字符串,其中所有字母字符都转换为小写形式。toString 方法.aspx)返回字符串。toUpperCase 方法.aspx)返回一个字符串,其中所有字母字符都转换为大写形式。trim 方法.aspx)返回已移除前导空格、尾随空格和行终止符的字符串。valueOf 方法.aspx)返回字符串。10.5 包装对象对象是 JavaScript 语言最主要的数据类型,三种原始类型的值——数值、字符串、布尔值——在一定条件下,也会自动转为对象,也就是原始类型的“包装对象”。所谓“包装对象”,就是分别与数值、字符串、布尔值相对应的Number、String、Boolean三个原生对象。这三个原生对象可以把原始类型的值变成(包装成)对象。var v1 = new Number(123); var v2 = new String('abc'); var v3 = new Boolean(true); typeof v1 // "object" typeof v2 // "object" typeof v3 // "object" v1 === 123 // false v2 === 'abc' // false v3 === true // false包装对象的最大目的,首先是使得 JavaScript 的对象涵盖所有的值,其次使得原始类型的值可以方便地调用某些方法。原始类型的值,可以自动当作对象调用,即调用各种对象的方法和参数。这时,JavaScript 引擎会自动将原始类型的值转为包装对象实例,在使用后立刻销毁实例。比如,字符串可以调用length属性,返回字符串的长度。'abc'.length // 3上面代码中,abc是一个字符串,本身不是对象,不能调用length属性。JavaScript 引擎自动将其转为包装对象,在这个对象上调用length属性。调用结束后,这个临时对象就会被销毁。这就叫原始类型与实例对象的自动转换。注意:JS的内置对象还有很多,我们只不过是学习了比较常用的几个而已;在后面的学习中,我们还有讲解使用其他类型的内置对象;可以查看狐火和微软开发者社区,获取更多知识……课外知识:JS代码规范&编程风格缩进:空格和tab键都可以,尽量保持一致,使用一种; 两个空格和四个空格都行,尽量保持一致就行,但是使用4个空格的多一些; 分号:尽量不要忘记,每一行的结束都要加分号 while 与 for 循环后面不要加分号 if else、switch等分支语句后面不要加分号 关键字声明函数,后面不要加分号 表达式声明函数,函数后面加分号 区块:两种写法if(){ } if() { } 理论上两种都可以,但是尽量使用第一种,因为js会在行尾自动添加分号,有时会出现意外情况;圆括号函数的声明和调用、表达式运算1:函数调用时,函数名和括号之间没有空格2:函数声明时,函数名和括号之间没有空格3:参与表达式运算时,括号的前面和后面,都要加空格变量的声明console.log(x); var x = 10; //等价于 var x; console.log(x); x = 10;为了避免此种情况的出现,建议将所有在本作用域下声明的变量都提到最前面声明并赋值;自增自减运算因为 ++ 在前和++ 在后的运算结果不同,所以,尽量使用 +=1 -=1 替代,提高代码的可读性;你的团队中一定有搞不明白++在前和在后的区别的二傻子;生活不易,请善待他们;赋值 =赋值前后加空格;变量命名和代码缩进 规范,是一个程序员必备的基本编程素质;让别人给你调试BUG的第一前提条件就是 缩进要规范;
2022年10月13日
209 阅读
0 评论
0 点赞
2022-10-12
Redis及其基本操作
目标1、能够知道redis的5种数据结构;string list hash set zset2、能够运用set、get、del、keys命令;3、能够运用hset、hget、hmset、hmget、hgetall、hdel命令;4、能够运用lpush、lpop、rpush、rpop命令;5、能够运用sadd、zadd命令;一、Redis概述1.1、简介Redis是Remote Dictionary Server(远程词典服务)的缩写,Redis 是完全开源免费的,遵守BSD协议的NOSQL数据库,Redis使用C语言编写,它的数据模型为 key-value。Redis是一个单进程单线程,非阻塞I/ORedis 与其他 key - value 缓存产品有以下三个特点:Ø Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。Ø Redis不仅支持简单的key-value(string)类型的数据,同时还提供list[列表],set[集合],zset[有序集合],hash[hash]等数据结构的存储。Ø Redis支持服务器主从模式[集群-高可用]。redis和memcache区别² redis支持数据的持久化,而memcache不支持² redis不但有string类型的key-value还有更多的数据结构存储,而memcache则只有string类型的key和value² memcache的集群很弱,而redis支持主从集群的² 端口不同 memcache 11211 redis 63791.2、Redis优势Ø 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。Ø 丰富的数据类型 – Redis支持String, List, Hash, Set 及 Zset 数据类型操作。Ø 原子性 – Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。多个操作也支持事务,通过MULTI和EXEC指令包起来。Ø api支持的语言丰富,调用简单(面向对象)。二、 数据结构类型操作redis提供5种 string 字符串 list 列表 set 集合 zset 有序集合 hash3.1、Redis对key的操作命令【redis服务器相关】查找所有符合给定模式的keykeys 查询相应的key或通配符(*)图片工具添加2个keykeys查看用于检查给定 key 是否存在 返回0/1 0不存在,1存在exists key查看当前数据库中设置key的数量dbsize清除当前数据库中的数据flushdb切换数据库select N清除所有数据库中的数据flushall注:flushdb 还是flushall 两个尽量不要用,知道就行,在开发时,可以用一用,上线一定不要用。3.2、字符串(string)操作命令用于设置给定 key 的值。如果 key 已经存储其他值, SET 就覆写旧值,且无视类型set key value [ex 秒数]/[px 毫秒数] [nx]/[xx]注后两个参数一般不写ex/px 缓存有效期 exnx: 表示key不存在时,执行操作xx: 表示key存在时,执行操作 默认设置带过期时间的key查看value类型存在则添加失败,不存在则添加成功 nx存在则修改,不存在则添加 xx设置key有效期用于获取指定 key 的值。如果 key 不存在,返回 nil 。如果key 储存的值不是字符串类型,返回一个错误get key一次性设置多个键值mset key1 value1 key2 value2 …获取多个key的值mget key1 key2 key3 …自增与自减 直接用,key自动创建,不需要先setincr key # 自增 每次自增1 decr key # 自减 每次自减1 incrby key step # 指定步长的自增 可为负数 decrby key step # 指定步长的自减把value追加到key的原值上append key value设置新值同步返回旧值getset key newValue3.3、列表(list)操作命令类似于PHP中的索引数组,列表中的值是可以重复的。可以用列表来实现简单的队列。可以实现先进后出,还可以实现先进先出把值插入到列表的头部(左边)lpush key value从列表右边(尾部)删除元素,并返回删除的元素值rpop key注:使用lpush 和 rpop 实现了 先进先出。获取列表的长度llen key返回指定区间内的元素,下标从0开始lrange key startIndex endIndex注: 默认从左开始向右获取指定索引的值,从右开始负数开始,-1就是右边第1个元素。从左边开始从右边开始从尾部添加rpush key value从头部删除元素并返回删除元素值lpop key移除列表的最后一个元素,并将该元素添加到另一个列表并返回rpoplpush mylist otherlist3.4、哈希(hash)操作命令类似于PHP的关联数组。一般用于存储数据表中一条记录值。关于hash的key的起名称:一般和数据表关联表名:主键字段名:id值 user:id:1 hash的key值把key中 field字段的值设置为 value,如果没有field字段,直接添加,如果有,则覆盖原field字段的值hset key field value一次性设置多个hmset key field1 value1 field2 value2 …获取key中指定field字段的值hget key field一次性获取之个key中field字段的值hmget key field1 field2 …返回key中所有字段的值hgetall key把数据库中用户表中id为1的用户信息存到redis中给hash中的key值单个设置值和单个key中的字段来获取。批量获取和添加删除key中指定的field字段hdel key field返回key中元素的数量hlen key判断key中有没有field字段hexists key field把key中field字段的值自增长hincrby key field step 步长可以为负数返回所有key对应的field字段hkeys key返回所有key对应field字段对应的值hvals key3.5、集合(set)操作命令redis的set是无序集合。集合里不允许有重复的元素。set元素最大可以包含(2的32次方-1)个元素。场景:存放用户Id,不重复的信息 抽奖,好友关系向集合key中添加元素sadd key value1 value2返回key集合中所有的元素smembers key返回key集合中元素的个数scard key删除key集合中为value1的元素srem key value1随机删除key集合中的1个元素并返回spop key判断value是否存在于key集合中sismember key value把源集合中的value删除,并添加到目标集合中 【移动】smvoe sSet dSet value求出key1,key2两个集合的交集,并返回sinter key1 key2求出key1,key2两个集合的并集,并去重,并返回sunion key1 key2求出key1与key2的差集sdiff key1 key2 以key1集合为主,求出key1中和key2不同的元素并返回3.6、有序集合(zset)操作命令和set一样有序集合,元素不允许重复,不同的是每个元素都会关联一个分值。可以通过它的分值来进行排序。如实现手机APP市场的软件排名等需求的实现。给key有序集合中添加元素zadd key score(分值) value删除key有序集合中指定的元素zrem key value1返回有序集中,指定区间位置内的成员zrange key startIndex endIndex [withscores] # 从小到大排列 zrevrange key startIndex endIndex [withscores] # 从大到小排列按照分值来删除元素,删除score在 min<=score<=max之间的zremrangebyscore key min max返回集合元素个数zcard key返回min <= score <= max分值区间内元素的数量zcount key minScore maxScore返回有序集中,成员的分数值zscore key value对有序集合中指定成员的分数加上增量 把value的分数+score值zincrby key score 元素字符串set key value [ex/px nx/xx] get key mset key value key value mget key1 key2 key3 ttl key expire key time incrby key step append key value getset key newValue del key列表 listlpush rpop rpush lpop rpoplpush llen lrange key start endhashhset hmset hget key fileld hmget key f1 f2 f3 hgetall key hlen hexists hdel hincrby无序集合 setsadd smembers scards sismember smove sset dset value srem spop sinter 交集 sunion 并集 sdiff set1 set2 差集有序集合 zsetzadd key score value zrange key start end zrevrange zrem zcard zincrby 分值添加 zremrangebyscore 分值区间来删除 zcount 分值区间总数 zscore 元素分值
2022年10月12日
240 阅读
0 评论
1 点赞
2022-10-12
PDO-预处理、事务、异常处理、二次封装
1.1 目标理解PDO产生的价值;了解PDO中三个类各自主要的功能;掌握PDO类的对象实例化;了解PDO设置属性的原理;了解PDOStatement类对象产生的原理;掌握fetch数据获取的应用;掌握PDO中预处理的应用;了解PDO中事务处理的应用;了解PDO中的三种错误处理模式;掌握PDO异常的使用;理解PDO二次封装的意义;掌握PDO的二次封装;1.2 PDO介绍1.2.1 连接数据库方式方法一:mysql扩展【这种方式php7已经淘汰】方法二:mysqli扩展方法三:PDO扩展1.2.2 PDO介绍PDO(PHP Data Object)扩展为PHP访问各种数据库提供了一个轻量级,一致性的接口。无论访问什么数据库,都可以通过一致性的接口去操作。1.2.3 开启PDO扩展开启PDO连接MySQL扩展extension=php_pdo_mysql.dll1.3 PDO核心类1、PDO类:表示PHP和数据库之间的一个连接2、PDOStatement 类 第一:表示执行数据查询语句(select ,show)后的相关结果集 第二:预处理对象3、PDOException类:表示PDO的异常1.4 实例化PDO对象语法__construct($dsn,用户名,密码)1.4.1 DSNDSN:data source name,数据源名称,包含的是连接数据库的信息,格式如下:$dsn=数据库类型:host=主机地址;port=端口号;dbname=数据库名称;charset=字符集数据库类型:MySQL数据库 => mysql: oracle数据库 => oci: SQL Server =>sqlsrv: 具体驱动类型参见手册“PDO驱动”1.4.2 实例化PDO实例化PDO的过程就是连接数据库的过程<?php $dsn='mysql:host=localhost;port=3306;dbname=data;charset=utf8'; $pdo=new PDO($dsn,'root','root'); var_dump($pdo); //object(PDO)#1 (0) { } 1.4.3 注意事项1、如果连接的是本地数据库,host可以省略<?php $dsn='mysql:port=3306;dbname=data;charset=utf8'; $pdo=new PDO($dsn,'root','root'); var_dump($pdo); //object(PDO)#1 (0) { } 2、如果使用的是3306端口,port可以省略<?php $dsn='mysql:dbname=data;charset=utf8'; $pdo=new PDO($dsn,'root','root'); var_dump($pdo); //object(PDO)#1 (0) { } 3、charset也省略,如果省略,使用的是默认字符编码<?php $dsn='mysql:dbname=data'; $pdo=new PDO($dsn,'root','root'); var_dump($pdo); 4、dbname也可以省略,如果省略就没有选择数据库<?php $dsn='mysql:'; $pdo=new PDO($dsn,'root','root'); var_dump($pdo); 5、host、port、dbname、charset不区分大小写,没有先后顺序6、驱动名称不能省略,冒号不能省略(因为冒号是驱动名组成部分),数据库驱动只能小写1.5 使用PDO1.5.1 执行数据操作语句方法:$pdo->exec($sql),执行数据增、删、改语句,执行成功返回受影响的记录数,如果SQL语句错误返回false。<?php //1、实例化PDO $dsn='mysql:host=localhost;port=3306;dbname=data;charset=utf8'; $pdo=new PDO($dsn,'root','root'); //2执行数据操作语句 //2.1 执行增加 /* if($pdo->exec("insert into news values (null,'bb','bbbbbb',unix_timestamp())")) echo '自动增长的编号是:'.$pdo->lastInsertId (),'<br>'; */ //2.2 执行修改 //echo $pdo->exec("update news set title='静夜思' where id in (3,4)"); //2.3 执行删除 //echo $pdo->exec('delete from news where id=5');\ //2.4 完善 $sql="update news set title='静夜思1' where ids in (3,4)"; $rs=$pdo->exec($sql); if($rs){ echo 'SQL语句执行成功<br>'; if(substr($sql, 0,6)=='insert') echo '自动增长的编号是:'.$pdo->lastInsertId (),'<br>'; else echo '受到影响的记录数是:'.$rs,'<br>'; }elseif($rs===0){ echo '数据没有变化<br>'; }elseif($rs===false){ echo 'SQL语句执行失败<br>'; echo '错误编号:'.$pdo->errorCode(),'<br>'; //var_dump($pdo->errorInfo()); echo '错误信息:'.$pdo->errorInfo()[2]; }1.5.2 执行数据查询语句方法:$pdo->query($sql),返回的是PDOStatement对象<?php $dsn='mysql:dbname=data;charset=utf8'; $pdo=new PDO($dsn,'root','root'); //1、执行数据查询语句 $stmt=$pdo->query('select * from products'); //var_dump($stmt); //object(PDOStatement) //2、获取数据 //2.1 获取二维数组 //$rs=$stmt->fetchAll(); //默认返回关联和索引数组 //$rs=$stmt->fetchAll(PDO::FETCH_BOTH); //返回关联和索引数组 //$rs=$stmt->fetchAll(PDO::FETCH_NUM); //返回索引数组 //$rs=$stmt->fetchAll(PDO::FETCH_ASSOC); //返回关联数组 //$rs=$stmt->fetchAll(PDO::FETCH_OBJ); //返回对象数组 //2.2 获取一维数组,匹配完成后指针下移一条 //$rs=$stmt->fetch(); //关联和索引数组 //$rs=$stmt->fetch(PDO::FETCH_NUM); //索引数组 //例题:通过while循环获取所有数据 /* while($row=$stmt->fetch(PDO::FETCH_ASSOC)){ $rs[]=$row; } echo '<pre>'; var_dump($rs); */ //3.3 匹配列:匹配当前行的第n列,列的编号从0开始,匹配完毕后指针下移一条 //echo $stmt->fetchColumn(); //获取当前行的第0列 //echo $stmt->fetchColumn(1); //获取当前行的第1列 //3.4 总行数,总列数 /* echo '总行数:'.$stmt->rowCount(),'<br>'; echo '总列数:'.$stmt->columnCount(); */ //3.5 遍历PDOStatement对象(PDOStatement对象是有迭代器的) foreach($stmt as $row){ echo $row['proname'],'-',$row['proprice'],'<br>'; }stdClass类是所有PHP类的父类1.5.3 PDO操作事务事务:是一个整体,要么一起执行,要么一起回滚事务的特性:原子性,一致性,隔离性,永久性需要将多个SQL语句作为一个整体执行,就需要使用到事务语法start transaction 或 begin 开启事务 commit 提交事务 rollback 回滚事务例题创建测试数据create table bank( cardid char(4) primary key comment '卡号', balance decimal(10,2) not null comment '余额' )engine=innodb charset=utf8 comment '银行卡号表' insert into bank values ('1001',1000),('1002',1)PDO操作事务<body> <?php if(!empty($_POST)){ $dsn='mysql:dbname=data;charset=utf8'; $pdo=new PDO($dsn,'root','root'); $out=$_POST['card_out']; //转出卡号 $in=$_POST['card_in']; //注入卡号 $money=$_POST['money']; //金额 $pdo->beginTransaction(); //开启事务 //转账 $flag1=$pdo->exec("update bank set balance=balance-$money where cardid='$out'"); $flag2=$pdo->exec("update bank set balance=balance+$money where cardid='$in'"); //查看转出的账号是否大于0,大于0返回true,否则返回false $stmt=$pdo->query("select balance from bank where cardid='$out'"); $flag3=$stmt->fetchColumn()>=0?1:0; if($flag1 && $flag2 && $flag3){ $pdo->commit (); //提交事务 echo '转账成功'; } else{ $pdo->rollBack (); //回滚事务 echo '转账失败'; } } ?> <form action="" method="post"> 转出卡号: <input type="text" name="card_out" id=""> <br> 转入卡号: <input type="text" name="card_in" id=""> <br> 金额:<input type="text" name="money" id=""> <br> <input type="submit" value="提交"> </form> </body>运行结果小结: $pdo->beginTransaction() 开启事务 $pdo->commit () 提交事务 $pdo->rollBack() 回滚事务1.5.4 PDO操作预处理复习MySQL中预处理预处理好处:编译一次多次执行,用来解决一条SQL语句多次执行的问题,提高了执行效率。预处理语句:prepare 预处理名字 from 'sql语句'执行预处理execute 预处理名字 [using 变量]PDO中的预处理——位置占位符<?php $dsn='mysql:dbname=data;charset=utf8'; $pdo=new PDO($dsn,'root','root'); //创建预处理对象 $stmt=$pdo->prepare("insert into bank values (?,?)"); //?是占位符 //执行预处理 $cards=[ ['1003',500], ['1004',100] ]; foreach($cards as $card){ //绑定参数,并执行预处理, //方法一: /* $stmt->bindParam(1, $card[0]); //占位符的位置从1开始 $stmt->bindParam(2, $card[1]); $stmt->execute(); //执行预处理 */ //方法二: /* $stmt->bindValue(1, $card[0]); $stmt->bindValue(2, $card[1]); $stmt->execute(); */ //方法三:如果占位符的顺序和数组的顺序一致,可以直接传递数组 $stmt->execute($card); }PDO中的预处理——参数占位符<?php $dsn='mysql:dbname=data;charset=utf8'; $pdo=new PDO($dsn,'root','root'); //创建预处理对象 $stmt=$pdo->prepare("insert into bank values (:p1,:p2)"); //:p1,:p2是参数占位符 //执行预处理 $cards=[ ['p1'=>'1003','p2'=>500], ['p1'=>'1004','p2'=>1000] ]; foreach($cards as $card){ //方法一: /* $stmt->bindParam(':p1', $card['p1']); $stmt->bindParam(':p2', $card['p2']); $stmt->execute(); */ //方法二:但数组的下标和参数名一致的时候就可以直接传递关联数组 $stmt->execute($card); }小结:1、?是位置占位符2、参数占位符以冒号开头3、$stmt->bindParam()和$stmt->bindValue()区别4、预处理的好处a)提高执行效率 b)提高安全性1.6 PDO异常处理<?php try{ $dsn='mysql:dbname=data;charset=utf8'; $pdo=new PDO($dsn,'root','root'); //这是PDO错误模式属性,PDO自动抛出异常 $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->query('select * from newsssssss'); //自动抛出异常 } catch (PDOException $ex) { echo '错误信息:'.$ex->getMessage(),'<br>'; echo '错误文件:'.$ex->getFile(),'<br>'; echo '错误行号:'.$ex->getLine(); }小结:1、PDOException是PDO的异常类2、实例化PDO会自动抛出异常3、其他操作不会抛出异常,需要设置PDO的异常模式4、PDO异常模式PDO::ERRMODE_EXCEPTION 抛出异常 PDO::ERRMODE_SILENT 中断 PDO::ERRMODE_WARNING 警告1.7 单例模式封装MyPDO类1.7.1 步骤1、单例模式2、初始化参数3、连接数据库4、执行增删改5、执行查询 a)返回二维数组 b)返回一维数组 c)返回一行一列1.7.2 代码实现第一部分:单例、初始化参数、实例化PDO<?php class MyPDO{ private $type; //数据库类别 private $host; //主机地址 private $port; //端口号 private $dbname; //数据库名 private $charset; //字符集 private $user; //用户名 private $pwd; //密码 private $pdo; //保存PDO对象 private static $instance; private function __construct($param) { $this->initParam($param); $this->initPDO(); } private function __clone() { } public static function getInstance($param=array()){ if(!self::$instance instanceof self) self::$instance=new self($param); return self::$instance; } //初始化参数 private function initParam($param){ $this->type=$param['type']??'mysql'; $this->host=$param['host']??'127.0.0.1'; $this->port=$param['port']??'3306'; $this->dbname=$param['dbname']??'data'; $this->charset=$param['charset']??'utf8'; $this->user=$param['user']??'root'; $this->pwd=$param['pwd']??'root'; } //初始化PDO private function initPDO(){ try{ $dsn="{$this->type}:host={$this->host};port={$this->port};dbname={$this->dbname};charset={$this->charset}"; $this->pdo=new PDO($dsn, $this->user, $this->pwd); } catch (PDOException $ex) { echo '错误编号:'.$ex->getCode(),'<br>'; echo '错误行号:'.$ex->getLine(),'<br>'; echo '错误文件:'.$ex->getFile(),'<br>'; echo '错误信息:'.$ex->getMessage(),'<br>'; exit; } } } //测试 $param=array( ); $mypdo= MyPDO::getInstance($param); var_dump($mypdo);第二部分:数据操作部分<?php class MyPDO{ private $type; //数据库类别 private $host; //主机地址 private $port; //端口号 private $dbname; //数据库名 private $charset; //字符集 private $user; //用户名 private $pwd; //密码 private $pdo; //保存PDO对象 private static $instance; private function __construct($param) { $this->initParam($param); $this->initPDO(); $this->initException(); } private function __clone() { } public static function getInstance($param=array()){ if(!self::$instance instanceof self) self::$instance=new self($param); return self::$instance; } //初始化参数 private function initParam($param){ $this->type=$param['type']??'mysql'; $this->host=$param['host']??'127.0.0.1'; $this->port=$param['port']??'3306'; $this->dbname=$param['dbname']??'data'; $this->charset=$param['charset']??'utf8'; $this->user=$param['user']??'root'; $this->pwd=$param['pwd']??'root'; } //初始化PDO private function initPDO(){ try{ $dsn="{$this->type}:host={$this->host};port={$this->port};dbname={$this->dbname};charset={$this->charset}"; $this->pdo=new PDO($dsn, $this->user, $this->pwd); } catch (PDOException $ex) { $this->showException($ex); exit; } } //显示异常 private function showException($ex,$sql=''){ if($sql!=''){ echo 'SQL语句执行失败<br>'; echo '错误的SQL语句是:'.$sql,'<br>'; } echo '错误编号:'.$ex->getCode(),'<br>'; echo '错误行号:'.$ex->getLine(),'<br>'; echo '错误文件:'.$ex->getFile(),'<br>'; echo '错误信息:'.$ex->getMessage(),'<br>'; } //设置异常模式 private function initException(){ $this->pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION); } //执行增、删、改操作 public function exec($sql){ try{ return $this->pdo->exec($sql); } catch (PDOException $ex) { $this->showException($ex, $sql); exit; } } //获取自动增长的编号 public function lastInsertId(){ return $this->pdo->lastInsertId(); } } //测试 $param=array( ); $mypdo= MyPDO::getInstance($param); //echo $mypdo->exec('delete from news where id=6'); if($mypdo->exec("insert into news values (null,'11','1111',unix_timestamp())")) echo '自动增长的编号是:'.$mypdo->lastInsertId ();第三部分:数据查询部分<?php class MyPDO{ ... //判断匹配的类型 private function fetchType($type){ switch ($type){ case 'num': return PDO::FETCH_NUM; case 'both': return PDO::FETCH_BOTH; case 'obj': return PDO::FETCH_OBJ; default: return PDO::FETCH_ASSOC; } } //获取所有数据 ,返回二维数组 public function fetchAll($sql,$type='assoc'){ try{ $stmt=$this->pdo->query($sql); //获取PDOStatement对象 $type= $this->fetchType($type); //获取匹配方法 return $stmt->fetchAll($type); } catch (Exception $ex) { $this->showException($ex, $sql); } } //获取一维数组 public function fetchRow($sql,$type='assoc'){ try{ $stmt=$this->pdo->query($sql); //获取PDOStatement对象 $type= $this->fetchType($type); //获取匹配方法 return $stmt->fetch($type); } catch (Exception $ex) { $this->showException($ex, $sql); exit; } } //返回一行一列 public function fetchColumn($sql){ try{ $stmt=$this->pdo->query($sql); return $stmt->fetchColumn(); } catch (Exception $ex) { $this->showException($ex, $sql); exit; } } } //测试 $param=array( ); $mypdo= MyPDO::getInstance($param); //echo $mypdo->exec('delete from news where id=6'); /* if($mypdo->exec("insert into news values (null,'11','1111',unix_timestamp())")) echo '自动增长的编号是:'.$mypdo->lastInsertId (); */ //$list=$mypdo->fetchAll('select * from news'); //$list=$mypdo->fetchRow('select * from news where id=1'); $list=$mypdo->fetchColumn('select count(*) from news'); echo '<pre>'; var_dump($list);
2022年10月12日
393 阅读
0 评论
0 点赞
2022-10-12
MySQL数据库(五)-数据备份和封装
1.1 目标理解数据备份与还原的重要性;掌握mysqldump.exe备份方式;掌握SQL备份后的还原方式;掌握Mysqli操作MySQL服务器的过程;掌握PHP利用Mysqli实现数据表的增删改查操作掌握PHP操作数据库的封装含义及意义能够实现新增新闻入库;能够实现更新新闻信息能够实现删除新闻信息能够实现显示新闻列表1.2 连接数据库通过PHP做MySQL的客户端1.2.1 开启mysqli扩展在php.ini中开启mysqli扩展extension=php_mysqli.dll开启扩展后重启服务器,就可以使用mysqli_函数了,1.2.2 连接数据库创建news数据库-- 创建表 drop table if exists news; create table news( id int unsigned auto_increment primary key comment '主键', title varchar(20) not null comment '标题', content text not null comment '内容', createtime int not null comment '添加时间' )engine=innodb charset=utf8 comment '新闻表'; -- 插入测试数据 insert into news values (null,'锄禾','锄禾日当午',unix_timestamp()); insert into news values (null,'草','离离原上草',unix_timestamp());思考:时间字段可以用datetime类型,也可以使用int类型。一般用int,因为datetime占用8个字节,int占用4个字节。连接数据库mysqli_connect(主机IP,用户名,密码,数据库名,端口号) //如果端口号是3306可以省略 mysqli_connect_error():获取连接数据库的错误信息 mysqli_connect_errno():获取连接数据库的错误编码 mysqli_set_charset(连接对象,字符编码) 代码如下:<?php //连接数据库,连接成功返回连接对象 $link=@mysqli_connect('localhost','root','root','data','3306'); //var_dump($link); //object(mysqli) if(mysqli_connect_error()){ echo '错误号:'.mysqli_connect_errno(),'<br>'; //显示错误编码 echo '错误信息:'.mysqli_connect_error(); //显示错误信息 exit; } //设置字符编码 mysqli_set_charset($link,'utf8'); 脚下留心:与数据库相关用utf8,与页面显示相关用utf-81.3 操作数据1.3.1 数据操作语句通过mysqli_query()执行SQL语句增、删、改语句执行成功返回true,失败返回false<?php //1、连接数据库 $link=mysqli_connect('localhost','root','root','data'); //2、设置支付编码 mysqli_set_charset($link,'utf8'); //3、执行SQL语句 //3.1 执行insert语句 /* $rs=mysqli_query($link,"insert into news values (null,'静夜思','床前明月光',unix_timestamp())"); if($rs) echo '自动增长的编号是:'.mysqli_insert_id($link); */ //3.2 执行update语句 /* $rs=mysqli_query($link,"update news set content='疑是地上霜' where id=4"); if($rs) echo '受影响的记录数是:'.mysqli_affected_rows($link); else{ echo '错误码:'.mysqli_errno($link),'<br>'; echo '错误信息:'.mysqli_error($link); } */ //3.3 执行delete语句 mysqli_query($link,"delete from news where id=5"); 用到的函数mysqli_query():执行SQL语句 mysqli_insert_id():获取插入记录自动增长的ID mysqli_affected_rows():获取受影响的记录数 mysqli_error():获取执行SQL语句的错误信息 mysqli_errno():获取执行SQL语句的错误码1.3.2 数据查询语句数据查询用select、desc、show,成功会返回结果集,失败返回false<?php //1、连接数据库 $link=@mysqli_connect('localhost','root','root','data') or die('错误信息:'.mysqli_connect_error()); //2、设置字符编码 mysqli_query($link,'set names utf8'); //3、执行查询语句 $rs=mysqli_query($link,'select * from news'); //var_dump($rs); //object(mysqli_result) //4、获取对象中的数据 //4.1 将对象中的一条数据匹配成索引数组,指针下移一条 //$rows=mysqli_fetch_row($rs); //4.2 将对象中的一条数据匹配成关联数组,指针下移一条 //$rows=mysqli_fetch_assoc($rs); //4.3 将对象中的一条数据匹配成索引,关联数组,指针下移一条 //$rows=mysqli_fetch_array($rs); //4.4 总列数、总行数 //echo '总行数'.mysqli_num_rows($rs),'<br>'; //echo '总列数'.mysqli_num_fields($rs),'<br>'; //4.5 获取所有数据 //$list=mysqli_fetch_all($rs); //默认是索引数组 //$list=mysqli_fetch_all($rs,MYSQLI_NUM); //匹配成索引数组 //$list=mysqli_fetch_all($rs,MYSQLI_ASSOC); //匹配成关联数组 $list=mysqli_fetch_all($rs,MYSQLI_BOTH); //匹配成关联、索引数组 echo '<pre>'; print_r($list); //5、销毁结果集 mysqli_free_result($rs); //6、关闭连接 mysqli_close($link); 使用的函数mysqli_fetch_assoc():将一条数组匹配关联数组 mysqli_fetch_row():将一条记录匹配成索引数组 mysqli_fetch_array():将一条记录匹配成既有关联数组又有索引数组 mysqli_fetch_all():匹配所有记录 mysqli_num_rows():总行数 mysqli_num_fields():总记录数 mysqli_free_result():销毁结果集 mysqli_close():关闭连接1.4 新闻模块1.4.1 包含文件由于所有的操作都要连接数据库,将连接数据库的代码存放到包含文件中步骤1、在站点下创建inc文件夹2、在inc下创建conn.php文件,用来连接数据库,代码就是上面连接数据库的代码代码实现<?php //连接数据库 $link=@mysqli_connect('localhost','root','root','data') or die('错误:'.mysqli_connect_error()); mysqli_set_charset($link,'utf8');1.4.2 显示新闻步骤:1、连接数据库2、获取数据3、遍历循环数据代码<style type="text/css"> table{ width:780px; border:solid 1px #000; margin:auto; } th,td{ border:solid 1px #000; } </style> <body> <?php //1、连接数据库 require './inc/conn.php'; //2、获取数据 $rs=mysqli_query($link,'select * from news order by id desc'); //返回结果集对象 $list=mysqli_fetch_all($rs,MYSQLI_ASSOC); //将结果匹配成关联数组 ?> <table> <tr> <th>编号</th> <th>标题</th> <th>内容</th> <th>时间</th> <th>修改</th> <th>删除</th> <!--3、循环显示数据--> <?php foreach($list as $rows):?> <tr> <td><?php echo $rows['id']?></td> <td><?php echo $rows['title']?></td> <td><?php echo $rows['content']?></td> <td><?php echo date('Y-m-d H:i:s',$rows['createtime'])?></td> <td><input type="button" value="修改" onclick=""></td> <td><input type="button" value="删除" onclick=""></td> </tr> <?php endforeach;?> </tr> </table> </body>运行结果1.4.3 添加新闻步骤:1、创建表单2、连接数据库3、将新闻数据写入到数据库中入口(list.php)<a href="./add.php">添加新闻</a>代码实现<body> <?php if(!empty($_POST)) { //2、连接数据库 require './inc/conn.php'; //3、插入数据 $time=time(); //获取时间戳 $sql="insert into news values (null,'{$_POST['title']}','{$_POST['content']}',$time)"; //拼接SQL语句 if(mysqli_query($link,$sql)) //执行SQL语句 header('location:./list.php'); //插入成功就跳转到list.php页面 else{ echo 'SQL语句插入失败<br>'; echo '错误码:'.mysqli_errno($link),'<br>'; echo '错误信息:'.mysqli_error($link); } } ?> <!--1、创建表单--> <form method="post" action=""> 标题: <input type="text" name="title"> <br /> <br /> 内容: <textarea name="content" rows="5" cols="30"></textarea> <br /> <br /> <input type="submit" name="button" value="提交"> </form> </body>运行结果1.4.4 删除新闻步骤:1、在list.php页面点击删除按钮,跳转到del.php页面,传递删除的id2、在del.php页面连接数据库3、通过id删除数据4、删除成功后,跳转到list.php入口(list.php)<input type="button" value="删除" onclick="if(confirm('确定要删除吗'))location.href='./del.php?id=<?php echo $rows['id']?>'">del.php<?php //1、连接数据库 require './inc/conn.php'; //2、拼接SQL语句 $sql="delete from news where id={$_GET['id']}"; //3、执行SQL语句 if(mysqli_query($link,$sql)) header('location:./list.php'); else{ echo '删除失败'; }小结:1、一个页面是否写HTML架构,取决于是否有显示功能。2、如果一个页面只是做业务逻辑,没有显示功能,就不需要写HTML架构,比如del.php页面1.4.5 修改新闻入口(list.php)<input type="button" value="修改" onclick="location.href='edit.php?id=<?php echo $rows['id']?>'">edit.php页面步骤第一步:显示修改界面 1、连接数据库 2、获取修改的数据 3、将数据显示到表单中第二步:执行修改逻辑 1、获取新数据 2、拼接修改的SQL语句,执行修改逻辑代码如下<?php //连接数据库 require './inc/conn.php'; //1、获取修改的数据库 $sql="select * from news where id={$_GET['id']}"; //拼接SQL语句 $rs=mysqli_query($link,$sql); //获取修改的数据 $rows=mysqli_fetch_assoc($rs); //将修改的数据匹配成一维关联数组 //2、执行修改的逻辑 if(!empty($_POST)) { $id=$_GET['id']; //获取修改的id $title=$_POST['title']; //修改的标题 $content=$_POST['content']; //修改的内容 $sql="update news set title='$title',content='$content' where id=$id"; //拼接SQL语句 if(mysqli_query($link,$sql)) header('location:list.php'); //修改成功跳转到list.php页面 else echo '错误:'.mysqli_error($link); exit; } ?> <!doctype html> <html> <head> <meta charset="utf-8"> <title>无标题文档</title> </head> <body> <form method="post" action=""> 标题: <input type="text" name="title" value='<?php echo $rows['title']?>'> <br /> <br /> 内容: <textarea name="content" rows="5" cols="30"><?php echo $rows['content']?></textarea> <br /> <br /> <input type="submit" name="button" value="提交"> <input type="button" value="返回" onclick="location.href='list.php'"> </form> </body> </html>运行结果1.5 数据备份与还原数据库中的数据需要定期备份,数据量小的可以一周备份一次,数据量的可以一天备份一次。1.5.1 数据备份利用mysqldump工具,语法:mysqldump 数据库连接 数据库 > SQL文件备份地址例题:-- 将data数据库中所有的表导出到data.sql中 F:\wamp\PHPTutorial\MySQL\bin>mysqldump -uroot -proot data>c:\data.sql -- 将data数据库中的stuinfo、stumarks表 F:\wamp\PHPTutorial\MySQL\bin>mysqldump -uroot -proot data stuinfo stumarks>c:\data.sql -- 导出data数据库,导出的语句中带有创建数据库的语法 F:\wamp\PHPTutorial\MySQL\bin>mysqldump -uroot -proot -B data>c:\data1.sql1.5.2 数据还原方法一:MySQL的source指令(需要登录MySQL才能使用)mysql> source c:/data.sql; 注意:地址分隔符用斜线,不能用反斜线方法二:通过mysql指令数据还原(不需要登录MySQL)语法:mysql 连接数据库 导入的数据库名 < 导入的SQL文件例题:F:\wamp\PHPTutorial\MySQL\bin>mysql -uroot -proot data1 < c:\data.sql1.6 作业:1、通过循环的方式获取表中的所有记录2、通过异步实现增、删、改异步添加add.html<body> <script src='./js/jquery-3.3.1.min.js'></script> <script> $(document).ready(function() { $(':button:first').click(function(){ var title=$('#title').val(); var content=$('#content').val(); $.post('./add.php',{'title':title,'content':content},function(data){ if(data){ alert('添加成功'); location.href='list.php'; }else{ alert('添加失败'); } }) }) }); </script> <!--1、创建表单--> <form method="post" action=""> 标题: <input type="text" id="title"> <br /> <br /> 内容: <textarea id="content" rows="5" cols="30"></textarea> <br /> <br /> <input type="button" name="button" value="提交"> </form> </body>add.php<?php require './inc/conn.php'; $title=$_POST['title']; $content=$_POST['content']; $time=time(); $sql="insert into news values (null,'$title','$content',$time)"; echo mysqli_query($link,$sql)?1:0;异步删除list.php-- button按钮 <td><input type="button" value="删除" op='del' newsid=<?php echo $rows['id']?>></td> <script src='./js/jquery-3.3.1.min.js'></script> <script> $(document).ready(function() { $(':button').click(function(){ var tr=$(this).parents('tr'); //按钮所在的行 if($(this).attr('op')=='del'){ var id=$(this).attr('newsid'); //获取新闻的id $.post('./del.php',{'id':id},function(data){ if(data==1) tr.remove(); else alert('删除失败'); }) } }) }); </script>del.php<?php //1、连接数据库 require './inc/conn.php'; //2、拼接SQL语句 $sql="delete from news where id={$_POST['id']}"; //3、执行SQL语句 echo mysqli_query($link,$sql)?1:0;
2022年10月12日
164 阅读
0 评论
1 点赞
2022-10-12
MySQL 数据库(四)-多表查询、子查询、预处理和事务
1.1 目标理解查询五子句的顺序关系;掌握两张表的联合查询方法;理解连接查询的原理;掌握子查询的使用方式;掌握预处理的实现步骤;理解事务的基本工作原理;掌握事务的四个特点;理解视图的概念和作用;1.2 多表查询1.2.1 内连接规则:返回两个表的公共记录语法:-- 语法一 select * from 表1 inner join 表2 on 表1.公共字段=表2.公共字段 -- 语法二 select * from 表1,表2 where 表1.公共字段=表2.公共字段 例题-- inner join mysql> select * from stuinfo inner join stumarks on stuinfo.stuno=stumarks.stuno; +--------+----------+--------+--------+---------+------------+---------+--------+-------------+---------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | examNo | stuNo | writtenExam | labExam | +--------+----------+--------+--------+---------+------------+---------+--------+-------------+---------+ | s25303 | 李斯文 | 女 | 22 | 2 | 北京 | s271811 | s25303 | 80 | 58 | | s25302 | 李文才 | 男 | 31 | 3 | 上海 | s271813 | s25302 | 50 | 90 | | s25304 | 欧阳俊雄 | 男 | 28 | 4 | 天津 | s271815 | s25304 | 65 | 50 | | s25301 | 张秋丽 | 男 | 18 | 1 | 北京 | s271816 | s25301 | 77 | 82 | | s25318 | 争青小子 | 男 | 26 | 6 | 天津 | s271819 | s25318 | 56 | 48 | +--------+----------+--------+--------+---------+------------+---------+--------+-------------+---------+ 5 rows in set (0.00 sec) -- 相同的字段只显示一次 mysql> select s.stuno,stuname,stusex,writtenexam,labexam from stuinfo s inner join stumarks m on s.stuno=m.stuno; +--------+----------+--------+-------------+---------+ | stuno | stuname | stusex | writtenexam | labexam | +--------+----------+--------+-------------+---------+ | s25303 | 李斯文 | 女 | 80 | 58 | | s25302 | 李文才 | 男 | 50 | 90 | | s25304 | 欧阳俊雄 | 男 | 65 | 50 | | s25301 | 张秋丽 | 男 | 77 | 82 | | s25318 | 争青小子 | 男 | 56 | 48 | +--------+----------+--------+-------------+---------+ 5 rows in set (0.00 sec) -- 使用where mysql> select * from stuinfo,stumarks where stuinfo.stuno=stumarks.stuno; +--------+----------+--------+--------+---------+------------+---------+--------+-------------+---------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | examNo | stuNo | writtenExam | labExam | +--------+----------+--------+--------+---------+------------+---------+--------+-------------+---------+ | s25303 | 李斯文 | 女 | 22 | 2 | 北京 | s271811 | s25303 | 80 | 58 | | s25302 | 李文才 | 男 | 31 | 3 | 上海 | s271813 | s25302 | 50 | 90 | | s25304 | 欧阳俊雄 | 男 | 28 | 4 | 天津 | s271815 | s25304 | 65 | 50 | | s25301 | 张秋丽 | 男 | 18 | 1 | 北京 | s271816 | s25301 | 77 | 82 | | s25318 | 争青小子 | 男 | 26 | 6 | 天津 | s271819 | s25318 | 56 | 48 | +--------+----------+--------+--------+---------+------------+---------+--------+-------------+---------+ 5 rows in set (0.00 sec)多学一招:-- 1、内连接中inner可以省略 select * from 表1 join 表2 on 表1.公共字段=表2.公共字段 mysql> select * from stuinfo join stumarks on stuinfo.stuno=stumarks.stuno; +--------+----------+--------+--------+---------+------------+---------+--------+-------------+---------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | examNo | stuNo | writtenExam | labExam | +--------+----------+--------+--------+---------+------------+---------+--------+-------------+---------+ | s25303 | 李斯文 | 女 | 22 | 2 | 北京 | s271811 | s25303 | 80 | 58 | | s25302 | 李文才 | 男 | 31 | 3 | 上海 | s271813 | s25302 | 50 | 90 | | s25304 | 欧阳俊雄 | 男 | 28 | 4 | 天津 | s271815 | s25304 | 65 | 50 | | s25301 | 张秋丽 | 男 | 18 | 1 | 北京 | s271816 | s25301 | 77 | 82 | | s25318 | 争青小子 | 男 | 26 | 6 | 天津 | s271819 | s25318 | 56 | 48 | +--------+----------+--------+--------+---------+------------+---------+--------+-------------+---------+ 5 rows in set (0.00 sec) -- 如何实现三表查询 select * from 表1 inner join 表2 on 表1.公共字段=表2.公共字段 inner join 表3 on 表2.公共字段=表3.公共字段 -- 表连接越多,效率越低思考:select * from 表1 inner join 表2 on 表1.公共字段=表2.公共字段 和 select * from 表2 inner join 表1 on 表1.公共字段=表2.公共字段 一样吗? 答:一样的1.2.2 左外连接规则:以左边的表为准,右边如果没有对应的记录用null显示语法:select * from 表1 left join 表2 on 表1.公共字段=表2.公共字段例题:mysql> select stuname,writtenexam,labexam from stuinfo left join stumarks on stuinfo.stuno=stumarks.stuno; +----------+-------------+---------+ | stuname | writtenexam | labexam | +----------+-------------+---------+ | 张秋丽 | 77 | 82 | | 李文才 | 50 | 90 | | 李斯文 | 80 | 58 | | 欧阳俊雄 | 65 | 50 | | 诸葛丽丽 | NULL | NULL | | 争青小子 | 56 | 48 | | 梅超风 | NULL | NULL | +----------+-------------+---------+ 7 rows in set (0.01 sec)思考:select * from 表1 left join 表2 on 表1.公共字段=表2.公共字段 和 select * from 表2 left join 表1 on 表1.公共字段=表2.公共字段 一样吗? 答:不一样,第一个SQL以表1为准,第二个SQL以表2为准。1.2.3 右外连接规则:以右边的表为准,左边如果没有对应的记录用null显示语法:select * from 表1 right join 表2 on 表1.公共字段=表2.公共字段例题:mysql> select stuname,writtenexam,labexam from stuinfo right join stumarks on stuinfo.stuno=stumarks.stuno; +----------+-------------+---------+ | stuname | writtenexam | labexam | +----------+-------------+---------+ | 李斯文 | 80 | 58 | | 李文才 | 50 | 90 | | 欧阳俊雄 | 65 | 50 | | 张秋丽 | 77 | 82 | | 争青小子 | 56 | 48 | | NULL | 66 | 77 | +----------+-------------+---------+ 6 rows in set (0.00 sec)思考select * from 表1 left join 表2 on 表1.公共字段=表2.公共字段 和 select * from 表2 right join 表1 on 表1.公共字段=表2.公共字段 一样吗? 答:一样1.2.4 交叉连接语法,返回笛卡尔积select * from 表1 cross join 表2例题-- 交叉连接 mysql> select * from stuinfo cross join stumarks; -- 交叉连接有连接表达式与内连接是一样的 mysql> select * from stuinfo cross join stumarks on stuinfo.stuno=stumarks.stuno; +--------+----------+--------+--------+---------+------------+---------+--------+-------------+---------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | examNo | stuNo | writtenExam | labExam | +--------+----------+--------+--------+---------+------------+---------+--------+-------------+---------+ | s25303 | 李斯文 | 女 | 22 | 2 | 北京 | s271811 | s25303 | 80 | 58 | | s25302 | 李文才 | 男 | 31 | 3 | 上海 | s271813 | s25302 | 50 | 90 | | s25304 | 欧阳俊雄 | 男 | 28 | 4 | 天津 | s271815 | s25304 | 65 | 50 | | s25301 | 张秋丽 | 男 | 18 | 1 | 北京 | s271816 | s25301 | 77 | 82 | | s25318 | 争青小子 | 男 | 26 | 6 | 天津 | s271819 | s25318 | 56 | 48 | +--------+----------+--------+--------+---------+------------+---------+--------+-------------+---------+ 5 rows in set (0.00 sec)小结1、交叉连接如果没有连接条件返回笛卡尔积2、如果有连接条件和内连接是一样的。1.2.5 自然连接自动判断条件连接,判断的条件是依据同名字段1、自然内连接(natural join)mysql> select * from stuinfo natural join stumarks; +--------+----------+--------+--------+---------+------------+---------+-------------+---------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | examNo | writtenExam | labExam | +--------+----------+--------+--------+---------+------------+---------+-------------+---------+ | s25303 | 李斯文 | 女 | 22 | 2 | 北京 | s271811 | 80 | 58 | | s25302 | 李文才 | 男 | 31 | 3 | 上海 | s271813 | 50 | 90 | | s25304 | 欧阳俊雄 | 男 | 28 | 4 | 天津 | s271815 | 65 | 50 | | s25301 | 张秋丽 | 男 | 18 | 1 | 北京 | s271816 | 77 | 82 | | s25318 | 争青小子 | 男 | 26 | 6 | 天津 | s271819 | 56 | 48 | +--------+----------+--------+--------+---------+------------+---------+-------------+---------+ 5 rows in set (0.00 sec)2、自然左外连接(natural left join)mysql> select * from stuinfo natural left join stumarks; +--------+----------+--------+--------+---------+------------+---------+-------------+---------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | examNo | writtenExam | labExam | +--------+----------+--------+--------+---------+------------+---------+-------------+---------+ | s25301 | 张秋丽 | 男 | 18 | 1 | 北京 | s271816 | 77 | 82 | | s25302 | 李文才 | 男 | 31 | 3 | 上海 | s271813 | 50 | 90 | | s25303 | 李斯文 | 女 | 22 | 2 | 北京 | s271811 | 80 | 58 | | s25304 | 欧阳俊雄 | 男 | 28 | 4 | 天津 | s271815 | 65 | 50 | | s25305 | 诸葛丽丽 | 女 | 23 | 7 | 河南 | NULL | NULL | NULL | | s25318 | 争青小子 | 男 | 26 | 6 | 天津 | s271819 | 56 | 48 | | s25319 | 梅超风 | 女 | 23 | 5 | 河北 | NULL | NULL | NULL | +--------+----------+--------+--------+---------+------------+---------+-------------+---------+ 7 rows in set (0.00 sec)3、自然右外连接(natural right join)mysql> select * from stuinfo natural right join stumarks; +--------+---------+-------------+---------+----------+--------+--------+---------+------------+ | stuNo | examNo | writtenExam | labExam | stuName | stuSex | stuAge | stuSeat | stuAddress | +--------+---------+-------------+---------+----------+--------+--------+---------+------------+ | s25303 | s271811 | 80 | 58 | 李斯文 | 女 | 22 | 2 | 北京 | | s25302 | s271813 | 50 | 90 | 李文才 | 男 | 31 | 3 | 上海 | | s25304 | s271815 | 65 | 50 | 欧阳俊雄 | 男 | 28 | 4 | 天津 | | s25301 | s271816 | 77 | 82 | 张秋丽 | 男 | 18 | 1 | 北京 | | s25318 | s271819 | 56 | 48 | 争青小子 | 男 | 26 | 6 | 天津 | | s25320 | s271820 | 66 | 77 | NULL | NULL | NULL | NULL | NULL | +--------+---------+-------------+---------+----------+--------+--------+---------+------------+ 6 rows in set (0.00 sec)小结:1、表连接是通过同名字段来连接的2、如果没有同名字段就返回笛卡尔积3、同名的连接字段只显示一个,并且将该字段放在最前面1.2.6 usingusing用来指定连接字段mysql> select * from stuinfo inner join stumarks using(stuno); +--------+----------+--------+--------+---------+------------+---------+-------------+---------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | examNo | writtenExam | labExam | +--------+----------+--------+--------+---------+------------+---------+-------------+---------+ | s25303 | 李斯文 | 女 | 22 | 2 | 北京 | s271811 | 80 | 58 | | s25302 | 李文才 | 男 | 31 | 3 | 上海 | s271813 | 50 | 90 | | s25304 | 欧阳俊雄 | 男 | 28 | 4 | 天津 | s271815 | 65 | 50 | | s25301 | 张秋丽 | 男 | 18 | 1 | 北京 | s271816 | 77 | 82 | | s25318 | 争青小子 | 男 | 26 | 6 | 天津 | s271819 | 56 | 48 | +--------+----------+--------+--------+---------+------------+---------+-------------+---------+ 5 rows in set (0.00 sec)using的结果也会对公共字段进行优化,优化的规则和自然连接是一样的;1.2.7 练习1、显示地区及每个地区参加笔试的人数,并按人数降序排列-- 第一步: 显示地区及每个地区参加笔试的人数 mysql> select stuaddress,count(writtenexam) from stuinfo left join stumarks using(stuno) group by stuaddress; +------------+--------------------+ | stuaddress | count(writtenexam) | +------------+--------------------+ | 上海 | 1 | | 北京 | 2 | | 天津 | 2 | | 河北 | 0 | | 河南 | 0 | +------------+--------------------+ 5 rows in set (0.00 sec) -- 第二步:将结果降序排列 mysql> select stuaddress,count(writtenexam) c from stuinfo left join stumarks using(stuno) group by stuaddress order by c desc; +------------+---+ | stuaddress | c | +------------+---+ | 北京 | 2 | | 天津 | 2 | | 上海 | 1 | | 河北 | 0 | | 河南 | 0 | +------------+---+ 5 rows in set (0.00 sec)2、显示有学生参加考试的地区-- having筛选 mysql> select stuaddress,count(writtenexam) c from stuinfo left join stumarks using(stuno) group by stuaddress having c>0; +------------+---+ | stuaddress | c | +------------+---+ | 上海 | 1 | | 北京 | 2 | | 天津 | 2 | +------------+---+ 3 rows in set (0.00 sec) -- 表连接实现 -- 第一步:右连接获取有成绩的地区 mysql> select stuaddress from stuinfo right join stumarks using(stuno); +------------+ | stuaddress | +------------+ | 北京 | | 上海 | | 天津 | | 北京 | | 天津 | | NULL | +------------+ 6 rows in set (0.00 sec) -- 第二步:去重复 mysql> select distinct stuaddress from stuinfo right join stumarks using(stuno); +------------+ | stuaddress | +------------+ | 北京 | | 上海 | | 天津 | | NULL | +------------+ 4 rows in set (0.00 sec) -- 去除null mysql> select distinct stuaddress from stuinfo right join stumarks using(stuno) having stuaddress is not null; +------------+ | stuaddress | +------------+ | 北京 | | 上海 | | 天津 | +------------+ 3 rows in set (0.00 sec)3、显示男生和女生的人数-- 方法一: 分组查询 mysql> select stusex,count(*) from stuinfo group by stusex; +--------+----------+ | stusex | count(*) | +--------+----------+ | 女 | 3 | | 男 | 4 | +--------+----------+ 2 rows in set (0.00 sec) -- 方法二: union mysql> select stusex,count(*) from stuinfo where stusex='男' union select stusex,count(*) from stuinfo where stusex='女'; +--------+----------+ | stusex | count(*) | +--------+----------+ | 男 | 4 | | 女 | 3 | +--------+----------+ 2 rows in set (0.00 sec) -- 方法三:直接写条件 mysql> select sum(stusex='男') 男,sum(stusex='女') 女 from stuinfo; +------+------+ | 男 | 女 | +------+------+ | 4 | 3 | +------+------+ 1 row in set (0.00 sec)4、显示每个地区男生、女生、总人数mysql> select stuaddress,count(*) 总人数,sum(stusex='男') 男,sum(stusex='女') 女 from stuinfo group by stuaddress; +------------+--------+------+------+ | stuaddress | 总人数 | 男 | 女 | +------------+--------+------+------+ | 上海 | 1 | 1 | 0 | | 北京 | 2 | 1 | 1 | | 天津 | 2 | 2 | 0 | | 河北 | 1 | 0 | 1 | | 河南 | 1 | 0 | 1 | +------------+--------+------+------+ 5 rows in set (0.00 sec)1.3 子查询语法:select * from 表1 where (子查询)外面的查询称为父查询子查询为父查询提供查询条件1.3.1 标量子查询特点:子查询返回的值是一个-- 查找笔试成绩是80的学生 mysql> select * from stuinfo where stuno=(select stuno from stumarks where writtenexam=80); +--------+---------+--------+--------+---------+------------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | +--------+---------+--------+--------+---------+------------+ | s25303 | 李斯文 | 女 | 22 | 2 | 北京 | +--------+---------+--------+--------+---------+------------+ 1 row in set (0.00 sec) -- 查找最高分的学生 -- 方法一 mysql> select * from stuinfo where stuno=(select stuno from stumarks order by writtenexam desc limit 1); +--------+---------+--------+--------+---------+------------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | +--------+---------+--------+--------+---------+------------+ | s25303 | 李斯文 | 女 | 22 | 2 | 北京 | +--------+---------+--------+--------+---------+------------+ 1 row in set (0.00 sec) -- 方法二: mysql> select * from stuinfo where stuno=(select stuno from stumarks where writtenexam=(select max(writtenexam) from stumarks)) +--------+---------+--------+--------+---------+------------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | +--------+---------+--------+--------+---------+------------+ | s25303 | 李斯文 | 女 | 22 | 2 | 北京 | +--------+---------+--------+--------+---------+------------+ 1 row in set (0.00 sec)1.3.2 列子查询特点: 子查询返回的结果是一列如果子查询的结果返回多条记录,不能使用等于,用in或not in-- 查找及格的同学 mysql> select * from stuinfo where stuno in (select stuno from stumarks where writtenexam>=60); +--------+----------+--------+--------+---------+------------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | +--------+----------+--------+--------+---------+------------+ | s25301 | 张秋丽 | 男 | 18 | 1 | 北京 | | s25303 | 李斯文 | 女 | 22 | 2 | 北京 | | s25304 | 欧阳俊雄 | 男 | 28 | 4 | 天津 | +--------+----------+--------+--------+---------+------------+ 3 rows in set (0.00 sec) -- 查询不及格的同学 mysql> select * from stuinfo where stuno in (select stuno from stumarks where writtenexam<60); +--------+----------+--------+--------+---------+------------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | +--------+----------+--------+--------+---------+------------+ | s25302 | 李文才 | 男 | 31 | 3 | 上海 | | s25318 | 争青小子 | 男 | 26 | 6 | 天津 | +--------+----------+--------+--------+---------+------------+ 2 rows in set (0.00 sec) -- 查询需要补考的学生 mysql> select * from stuinfo where stuno not in (select stuno from stumarks where writtenexam>=60); +--------+----------+--------+--------+---------+------------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | +--------+----------+--------+--------+---------+------------+ | s25302 | 李文才 | 男 | 31 | 3 | 上海 | | s25305 | 诸葛丽丽 | 女 | 23 | 7 | 河南 | | s25318 | 争青小子 | 男 | 26 | 6 | 天津 | | s25319 | 梅超风 | 女 | 23 | 5 | 河北 | +--------+----------+--------+--------+---------+------------+ 4 rows in set (0.00 sec)1.3.3 行子查询特点:子查询返回的结果是多个字段组成-- 查找语文成绩最高的男生和女生 mysql> select * from stu where(stusex,ch) in (select stusex,max(ch) from stu group by stusex); +--------+----------+--------+--------+---------+------------+------+------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | ch | math | +--------+----------+--------+--------+---------+------------+------+------+ | s25318 | 争青小子 | 男 | 26 | 6 | 天津 | 86 | 92 | | s25321 | Tabm | 女 | 23 | 9 | 河北 | 88 | 77 | +--------+----------+--------+--------+---------+------------+------+------+ 2 rows in set (0.00 sec)1.3.4 表子查询特点:将子查询的结果作为表-- 查找语文成绩最高的男生和女生 mysql> select * from (select * from stu order by ch desc) t group by stusex; +--------+----------+--------+--------+---------+------------+------+------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | ch | math | +--------+----------+--------+--------+---------+------------+------+------+ | s25321 | Tabm | 女 | 23 | 9 | 河北 | 88 | 77 | | s25318 | 争青小子 | 男 | 26 | 6 | 天津 | 86 | 92 | +--------+----------+--------+--------+---------+------------+------+------+ 2 rows in set (0.00 sec)注意:from后面跟的是数据源,如果将子查询当成表来看, 必须给结果集取别名。1.3.5 exists子查询-- 如果笔试成绩有人超过80人,就显示所有学生信息 mysql> select * from stuinfo where exists (select * from stumarks where writtenexam>=80); -- 没有超过80的学生,就显示所有学生信息 mysql> select * from stuinfo where not exists (select * from stumarks where writtenexam>=80); Empty set (0.00 sec)作用:提高查询效率1.4 视图1.4.1 概述1、视图是一张虚拟表,它表示一张表的部分数据或多张表的综合数据,其结构和数据是建立在对表的查询基础上2、视图中并不存放数据,而是存放在视图所引用的原始表(基表)中3、同一张原始表,根据不同用户的不同需求,可以创建不同的视图1.4.2 作用1、筛选表中的行2、防止未经许可的用户访问敏感数据3、隐藏数据表的结构4、降低数据表的复杂程度1.4.3 创建视图语法:-- 创建视图 create view 视图名 as select 语句; -- 查询视图 select 列名 from 视图例题-- 创建视图 mysql> create view view1 -> as -> select * from stu where ch>=60 and math>=60; Query OK, 0 rows affected (0.00 sec) -- 查询视图 mysql> select * from view1; +--------+----------+--------+--------+---------+------------+------+------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | ch | math | +--------+----------+--------+--------+---------+------------+------+------+ | s25302 | 李文才 | 男 | 31 | 3 | 上海 | 77 | 76 | | s25318 | 争青小子 | 男 | 26 | 6 | 天津 | 86 | 92 | | s25319 | 梅超风 | 女 | 23 | 5 | 河北 | 74 | 67 | | s25320 | Tom | 男 | 24 | 8 | 北京 | 65 | 67 | | s25321 | Tabm | 女 | 23 | 9 | 河北 | 88 | 77 | +--------+----------+--------+--------+---------+------------+------+------+ 5 rows in set (0.02 sec) -- 视图可以使得降低SQL语句的复杂度 mysql> create view view2 -> as -> select stuno,stusex,writtenexam,labexam from stuinfo natural join stumarks; Query OK, 0 rows affected (0.01 sec)1.4.4 修改视图语法alter view 视图名 as select 语句例题:mysql> alter view view2 -> as -> select stuname from stuinfo; Query OK, 0 rows affected (0.00 sec)1.4.5 删除视图语法drop view [if exists ] 视图1,视图,...例题mysql> drop view view2; Query OK, 0 rows affected (0.00 sec)1.4.6 查看视图信息-- 方法一; mysql> show tables; -- 显示所有的表和视图 -- 方法二:精确查找视图(视图信息存储在information_schema下的views表中) mysql> select table_name from information_schema.views; +------------+ | table_name | +------------+ | view1 | +------------+ 1 row in set (0.05 sec) -- 方法三:通过表的comment属性查询视图 mysql> show table status\G; -- 查询所有表和视图的详细状态信息 mysql> show table status where comment='view'\G -- 只查找视图信息查询视图的结构mysql> desc view1;查询创建视图的语法mysql> show create view view1\G1.4.7 视图算法场景:找出语文成绩最高的男生和女生方法一:mysql> select * from (select * from stu order by ch desc) t group by stusex; +--------+----------+--------+--------+---------+------------+------+------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | ch | math | +--------+----------+--------+--------+---------+------------+------+------+ | s25321 | Tabm | 女 | 23 | 9 | 河北 | 88 | 77 | | s25318 | 争青小子 | 男 | 26 | 6 | 天津 | 86 | 92 | +--------+----------+--------+--------+---------+------------+------+------+ 2 rows in set (0.00 sec)方法二:mysql> create view view3 -> as -> select * from stu order by ch desc; Query OK, 0 rows affected (0.00 sec) mysql> select * from view3 group by stusex; +--------+---------+--------+--------+---------+------------+------+------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | ch | math | +--------+---------+--------+--------+---------+------------+------+------+ | s25301 | 张秋丽 | 男 | 18 | 1 | 北京 | 80 | NULL | | s25303 | 李斯文 | 女 | 22 | 2 | 北京 | 55 | 82 | +--------+---------+--------+--------+---------+------------+------+------+ 2 rows in set (0.00 sec)结论:方法一和方法二的结果不一样,这是因为视图的算法造成的。视图的算法有:1、merge:合并算法(将视图语句和外层语句合并后再执行)2、temptable:临时表算法(将视图作为一个临时表来执行)3、undefined:未定义算法(用哪种算法有MySQL决定,这是默认算法,视图一般会选merge算法)重新通过视图实现-- 创建视图,指定算法为临时表算法 mysql> create or replace algorithm=temptable view view3 -> as -> select * from stu order by ch desc; Query OK, 0 rows affected (0.00 sec) mysql> select * from view3 group by stusex; +--------+----------+--------+--------+---------+------------+------+------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | ch | math | +--------+----------+--------+--------+---------+------------+------+------+ | s25321 | Tabm | 女 | 23 | 9 | 河北 | 88 | 77 | | s25318 | 争青小子 | 男 | 26 | 6 | 天津 | 86 | 92 | +--------+----------+--------+--------+---------+------------+------+------+ 2 rows in set (0.00 sec)结论:和子查询结果一致。1.5 事务1.5.1 概述事务(TRANSACTION)是一个整体,要么一起执行,要么一起不执行1.5.2 事务特性事务必须具备以下四个属性,简称ACID 属性:原子性(Atomicity):事务是一个完整的操作。事务的各步操作是不可分的(原子的);要么都执行,要么都不执行一致性(Consistency):当事务完成时,数据必须处于一致状态隔离性(Isolation):对数据进行修改的所有并发事务是彼此隔离的。永久性(Durability):事务完成后,它对数据库的修改被永久保持。1.5.3 事务处理开启事务start transaction 或 begin [work]提交事务commit回滚事务rollback例题:-- 插入测试数据 mysql> create table bank( -> card char(4) primary key comment '卡号', -> money decimal(10,2) not null -> )engine=innodb charset=utf8; Query OK, 0 rows affected (0.05 sec) mysql> insert into bank values ('1001',1000),('1002',1); Query OK, 2 rows affected (0.00 sec) Records: 2 Duplicates: 0 Warnings: 0 -- 开启事务 mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> delimiter // -- 更改定界符 mysql> update bank set money=money-100 where card='1001'; -> update bank set money=money+100 where card='1002' // Query OK, 1 row affected (0.04 sec) Rows matched: 1 Changed: 1 Warnings: 0 -- 回滚事务 mysql> rollback // Query OK, 0 rows affected (0.00 sec) mysql> select * from bank // +------+---------+ | card | money | +------+---------+ | 1001 | 1000.00 | | 1002 | 1.00 | +------+---------+ 2 rows in set (0.00 sec) ------------------------------------------------------------------ -- 开启事务 mysql> start transaction // Query OK, 0 rows affected (0.00 sec) mysql> update bank set money=money-100 where card='1001'; -> update bank set money=money+100 where card='1002' // Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 -- 提交事务 mysql> commit // Query OK, 0 rows affected (0.00 sec) mysql> select * from bank // +------+--------+ | card | money | +------+--------+ | 1001 | 900.00 | | 1002 | 101.00 | +------+--------+设置事务的回滚点-- 开启事务 mysql> begin // Query OK, 0 rows affected (0.00 sec) mysql> insert into bank values ('1003',500) // Query OK, 1 row affected (0.00 sec) -- 记录事务的回滚点 mysql> savepoint a1 // Query OK, 0 rows affected (0.00 sec) mysql> insert into bank values ('1004',200) // Query OK, 1 row affected (0.00 sec) -- 回滚到回滚点 mysql> rollback to a1 // Query OK, 0 rows affected (0.00 sec) -- 查询 mysql> select * from bank // +------+--------+ | card | money | +------+--------+ | 1001 | 900.00 | | 1002 | 101.00 | | 1003 | 500.00 | +------+--------+ 3 rows in set (0.00 sec) 自动提交事务每一个SQL语句都是一个独立的事务小结:1、事务是事务开启的时候开始2、提交事务、回滚事务后事务都结束3、只有innodb支持事务4、一个SQL语句就是一个独立的事务,开启事务是将多个SQL语句放到一个事务中执行1.6 索引1.6.1 概述优点加快查询速度缺点:带索引的表在数据库中需要更多的存储空间 增、删、改命令需要更长的处理时间,因为它们需要对索引进行更新1.6.2 创建索引的指导原则适合创建索引的列1、该列用于频繁搜索 2、该列用于对数据进行排序 3、在WHERE子句中出现的列,在join子句中出现的列。请不要使用下面的列创建索引:1、列中仅包含几个不同的值。 2、表中仅包含几行。为小型表创建索引可能不太划算,因为MySQL在索引中搜索数据所花的时间比在表中逐行搜索所花的时间更长 1.6.3 创建索引1、主键索引:主要创建了主键就会自动的创建主键索引2、唯一索引:创建唯一键就创建了唯一索引-- 创建表的时候添加唯一索引 create table t5( id int primary key, name varchar(20), unique ix_name(name) -- 添加唯一索引 ); -- 给表添加唯一索引 mysql> create table t5( -> name varchar(20), -> addr varchar(50) -> ); Query OK, 0 rows affected (0.00 sec) mysql> create unique index ix_name on t5(name); Query OK, 0 rows affected (0.06 sec) Records: 0 Duplicates: 0 Warnings: 0 -- 通过更改表的方式创建唯一索引 mysql> alter table t5 add unique ix_addr (addr); Query OK, 0 rows affected (0.00 sec) Records: 0 Duplicates: 0 Warnings: 0普通索引-- 创建表的时候添加普通索引 mysql> create table t6( -> id int primary key, -> name varchar(20), -> index ix_name(name) -> ); Query OK, 0 rows affected (0.02 sec) -- 给表添加普通索引 mysql> create table t7( -> name varchar(20), -> addr varchar(50) -> ); Query OK, 0 rows affected (0.00 sec) mysql> create index ix_name on t7(name) ; Query OK, 0 rows affected (0.08 sec) Records: 0 Duplicates: 0 Warnings: 0 -- 通过更改表的方式创建索引 mysql> alter table t7 add index ix_addr(addr); Query OK, 0 rows affected (0.02 sec) Records: 0 Duplicates: 0 Warnings: 0小结:1、创建主键就会创建主键索引2、创建唯一键就会创建唯一索引3、创建唯一键的语法--语法一 create unique [index] 索引名 on 表名(字段名) -- 方法二 alter table 表名 add uniqe [index] 索引名(字段名)4、创建普通索引-- 语法一 create index 索引名 on 表名(字段名) -- 语法二 alter table 表名 add index 索引名(字段名)5、索引创建后,数据库根据查询语句自动选择索引1.6.4 删除索引语法:drop index 索引名 on 表名mysql> drop index ix_name on t7; Query OK, 0 rows affected (0.01 sec) Records: 0 Duplicates: 0 Warnings: 01.7 函数1.7.1 数字类-- 获取随机数 mysql> select rand(); +------------------+ | rand() | +------------------+ | 0.25443412666622 | +------------------+ 1 row in set (0.00 sec) -- 随机排序 mysql> select * from stuinfo order by rand(); -- 随机获取一条记录 mysql> select * from stuinfo order by rand() limit 1; -- 四舍五入,向上取整,向下取整 mysql> select round(3.1415926,3) '四舍五入',truncate(3.14159,3) '截取数据',ceil(3.1) '向上取整',floor(3.9) '向下取整'; +----------+----------+----------+----------+ | 四舍五入 | 截取数据 | 向上取整 | 向下取整 | +----------+----------+----------+----------+ | 3.142 | 3.141 | 4 | 3 | +----------+----------+----------+----------+ 1 row in set (0.04 sec) 注意: 截取数据直接截取,不四舍五入1.7.2 字符串类-- 大小写转换 mysql> select ucase('i name is tom') '转成大写',lcase('My Name IS TOM') '转成小写'; +---------------+----------------+ | 转成大写 | 转成小写 | +---------------+----------------+ | I NAME IS TOM | my name is tom | +---------------+----------------+ 1 row in set (0.00 sec) -- 截取字符串 mysql> select left('abcdef',3) '从左边截取',right('abcdef',3) '从右边截取',substring('abcdef',2,3) '字符串'; +------------+------------+--------+ | 从左边截取 | 从右边截取 | 字符串 | +------------+------------+--------+ | abc | def | bcd | +------------+------------+--------+ 1 row in set (0.00 sec) -- 字符串相连 mysql> select concat('中国','北京','顺义') '地址'; +--------------+ | 地址 | +--------------+ | 中国北京顺义 | +--------------+ 1 row in set (0.00 sec) mysql> select concat(stuname,'-',stusex) 信息 from stuinfo; +-------------+ | 信息 | +-------------+ | 张秋丽-男 | | 李文才-男 | | 李斯文-女 | | 欧阳俊雄-男 | | 诸葛丽丽-女 | | 争青小子-男 | | 梅超风-女 | +-------------+ 7 rows in set (0.00 sec) -- coalesce(str1,str2) :str1有值显示str1,如果str1为空就显示str2 -- 将成绩为空的显示为缺考 mysql> select stuname,coalesce(writtenexam,'缺考'),coalesce(labexam,'缺考') from stuinfo natural left join stumarks; +----------+------------------------------+--------------------------+ | stuname | coalesce(writtenexam,'缺考') | coalesce(labexam,'缺考') | +----------+------------------------------+--------------------------+ | 张秋丽 | 77 | 82 | | 李文才 | 50 | 90 | | 李斯文 | 80 | 58 | | 欧阳俊雄 | 65 | 50 | | 诸葛丽丽 | 缺考 | 缺考 | | 争青小子 | 56 | 48 | | 梅超风 | 缺考 | 缺考 | +----------+------------------------------+--------------------------+ 7 rows in set (0.02 sec) -- length():字节长度,char_length():字符长度 mysql> select length('锄禾日当午') 字节,char_length('锄禾日当午') 字符; +------+------+ | 字节 | 字符 | +------+------+ | 10 | 5 | +------+------+ 1 row in set (0.00 sec)1.7.3 时间类-- 时间戳 mysql> select unix_timestamp(); +------------------+ | unix_timestamp() | +------------------+ | 1560330458 | +------------------+ 1 row in set (0.00 sec) -- 格式化时间戳 mysql> select from_unixtime(unix_timestamp()); +---------------------------------+ | from_unixtime(unix_timestamp()) | +---------------------------------+ | 2019-06-12 17:08:18 | +---------------------------------+ 1 row in set (0.05 sec) -- 获取当前格式化时间 mysql> select now(); +---------------------+ | now() | +---------------------+ | 2019-06-12 17:08:50 | +---------------------+ 1 row in set (0.00 sec) -- 获取年,月,日,小时,分钟,秒 mysql> select year(now()) 年,month(now()) 月,day(now()) 日,hour(now()) 小时,minute(now()) 分钟,second(now())秒; +------+------+------+------+------+------+ | 年 | 月 | 日 | 小时 | 分钟 | 秒 | +------+------+------+------+------+------+ | 2019 | 6 | 12 | 17 | 10 | 48 | +------+------+------+------+------+------+ 1 row in set (0.00 sec) -- 星期,本年第几天; mysql> select dayname(now()) 星期,dayofyear(now()) 本年第几天; +-----------+------------+ | 星期 | 本年第几天 | +-----------+------------+ | Wednesday | 163 | +-----------+------------+ 1 row in set (0.00 sec) -- 日期相减 mysql> select datediff(now(),'2010-08-08') 相距天数; +----------+ | 相距天数 | +----------+ | 3230 | +----------+ 1 row in set (0.00 sec)1.7.4 加密函数1、md5()2、sha()mysql> select md5('aa'); +----------------------------------+ | md5('aa') | +----------------------------------+ | 4124bc0a9335c27f086f24ba207a4912 | +----------------------------------+ 1 row in set (0.00 sec) mysql> select sha('aa'); +------------------------------------------+ | sha('aa') | +------------------------------------------+ | e0c9035898dd52fc65c41454cec9c4d2611bfb37 | +------------------------------------------+ 1 row in set (0.00 sec)1.8 预处理每个代码的段的执行都要经历:词法分析——语法分析——编译——执行预编译一次,可以多次执行。用来解决一条SQL语句频繁执行的问题。预处理语句:prepare 预处理名字 from ‘sql语句’ 执行预处理:execute 预处理名字 [using 变量]例题:不带参数的预处理-- 创建预处理 mysql> prepare stmt from 'select * from stuinfo'; Query OK, 0 rows affected (0.06 sec) Statement prepared -- 执行预处理 mysql> execute stmt; +--------+----------+--------+--------+---------+------------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | +--------+----------+--------+--------+---------+------------+ | s25301 | 张秋丽 | 男 | 18 | 1 | 北京 | | s25302 | 李文才 | 男 | 31 | 3 | 上海 | | s25303 | 李斯文 | 女 | 22 | 2 | 北京 | | s25304 | 欧阳俊雄 | 男 | 28 | 4 | 天津 | | s25305 | 诸葛丽丽 | 女 | 23 | 7 | 河南 | | s25318 | 争青小子 | 男 | 26 | 6 | 天津 | | s25319 | 梅超风 | 女 | 23 | 5 | 河北 | +--------+----------+--------+--------+---------+------------+ 7 rows in set (0.00 sec)例题:带一个参数的预处理-- 创建带有位置占位符的预处理语句 mysql> prepare stmt from 'select * from stuinfo where stuno=?' ; Query OK, 0 rows affected (0.00 sec) Statement prepared -- 调用预处理,并传参数 mysql> delimiter // mysql> set @id='s25301'; -> execute stmt using @id // Query OK, 0 rows affected (0.00 sec) +--------+---------+--------+--------+---------+------------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | +--------+---------+--------+--------+---------+------------+ | s25301 | 张秋丽 | 男 | 18 | 1 | 北京 | +--------+---------+--------+--------+---------+------------+ 1 row in set (0.00 sec)例题:传递多个参数mysql> prepare stmt from 'select * from stuinfo where stuage>? and stusex=?' // Query OK, 0 rows affected (0.00 sec) Statement prepared mysql> set @age=20; -> set @sex='男'; -> execute stmt using @age,@sex // Query OK, 0 rows affected (0.00 sec) Query OK, 0 rows affected (0.00 sec) +--------+----------+--------+--------+---------+------------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | +--------+----------+--------+--------+---------+------------+ | s25302 | 李文才 | 男 | 31 | 3 | 上海 | | s25304 | 欧阳俊雄 | 男 | 28 | 4 | 天津 | | s25318 | 争青小子 | 男 | 26 | 6 | 天津 | +--------+----------+--------+--------+---------+------------+ 3 rows in set (0.00 sec)小结:1、MySQL中变量以@开头2、通过set给变量赋值3、?是位置占位符
2022年10月12日
206 阅读
0 评论
1 点赞
2022-10-12
MySQL数据库(三)
1.1 目标掌握一对多关系的数据表设计方案和原理;掌握多对多关系的数据表设计方案和原理;掌握where子句进行数据筛选;掌握group by子句进行数据分类统计;掌握order by子句进行数据排序;了解mysql数据库的设计规范;1.2 实体之间的关系1.2.1 一对多(1:N)主表中的一条记录对应从表中的多条记录实现一对多的方式:主键和非主键建关系问题:说出几个一对多的关系?班主任表——学生表 品牌表——商品表1.2.2 多对一(N:1)多对一就是一对多1.2.3 一对一(1:1)如何实现一对一:主键和主键建关系思考:一对一两个表完全可以用一个表实现,为什么还要分成两个表?答:在字段数量很多情况下,数据量也就很大,每次查询都需要检索大量数据,这样效率低下。我们可以将所有字段分成两个部分,“常用字段”和“不常用字段”,这样对大部分查询者来说效率提高了。【表的垂直分割】1.2.3 多对多(N:M)主表中的一条记录对应从表中的多条记录,从表中的一条记录,对应主表中的多条记录如何实现多对多:利用第三张关系表问题:说出几个多对多的关系?讲师表——学生表 课程表——学生表 商品表——订单表小结:如何实现一对一:主键和主键建关系 如果实现一对多:主键和非主键建关系 如何实现多对多:引入第三张关系表1.3 数据库设计1.3.1 数据库设计的步骤收集信息:与该系统有关人员进行交流、坐谈,充分理解数据库需要完成的任务标识对象(实体-Entity):标识数据库要管理的关键对象或实体标识每个实体的属性(Attribute)标识对象之间的关系(Relationship)将模型转换成数据库规范化1.3.2 例题第一步:收集信息BBS论坛的基本功能: 用户注册和登录,后台数据库需要存放用户的注册信息和在线状态信息; 用户发贴,后台数据库需要存放贴子相关信息,如贴子内容、标题等; 用户可以对发帖进行回复; 论坛版块管理:后台数据库需要存放各个版块信息,如版主、版块名称、贴子数等;第二步:标识对象实体一般是名词: 1、用户对象 2、板块对象 3、帖子对象 4、跟帖对象第三步:标识每个实体的属性第四步:标识对象之间的关系1.3.3 绘制E-R图E-R(Entity-Relationship)实体关系图)完整的E-R图1.3.4 将E-R图转成表实体转成表,属性转成字段如果没有合适的字段做主键,给表添加一个自动增长列做主键。1.4 数据规范化1.4.1 第一范式:确保每列原则性第一范式:的目标是确保每列的原子性,一个字段表示一个含义思考如下表是否满足第一范式思考:地址包含省、市、县、地区是否需要拆分?答:如果仅仅起地址的作用,不需要统计,可以不拆分;如果有按地区统计的功能需要拆分。在实际项目中,建议拆分。1.4.2 第二范式:非键字段必须依赖于键字段第二范式:在满足第一范式的前提下,要求每个表只描述一件事情思考:如下表设计是否合理1.4.3 第三范式:消除传递依赖第三范式:在满足第二范式的前提下,除了主键以外的其他列消除传递依赖。思考:如下表设计是否合理?结论:不满足第三范式,因为语文和数学确定了,总分就确定了1.4.4 反3NF范式越高,数据冗余越少,但是效率有时就越地下,为了提高运行效率,可以适当让数据冗余。学号姓名语文数学总分1李白7788165上面的设计不满足第三范式,但是高考分数表就是这样设计的,为什么?答:高考分数峰值访问量非常大,这时候就是性能更重要。当性能和规范化冲突的时候,我们首选性能。这就是“反三范式”。小结1、第一范式约束的所有字段2、第二范式约束的主键和非主键的关系3、第三范式约束的非主键之间的关系4、范式越高,冗余越少,但表业越多。5、规范化和性能的关系 :性能比规范化更重要1.4.5 例题需求假设某建筑公司要设计一个数据库。公司的业务规 则概括说明如下: 公司承担多个工程项目,每一项工程有:工程号、工程名称、施工人员等 公司有多名职工,每一名职工有:职工号、姓名、性别、职务(工程师、技术员)等 公司按照工时和小时工资率支付工资,小时工资率由职工的职务决定(例如,技术员的小时工资率与工程师不同)标识实体1、工程 2、职工 3、工时 4、小时工资率1.5 查询语句语法:select [选项] 列名 [from 表名] [where 条件] [group by 分组] [order by 排序][having 条件] [limit 限制]1.5.1 字段表达式-- 可以直接输出内容 mysql> select '锄禾日当午'; +------------+ | 锄禾日当午 | +------------+ | 锄禾日当午 | +------------+ 1 row in set (0.00 sec) -- 输出表达式 mysql> select 10*10; +-------+ | 10*10 | +-------+ | 100 | +-------+ 1 row in set (0.00 sec) mysql> select ch,math,ch+math from stu; +------+------+---------+ | ch | math | ch+math | +------+------+---------+ | 80 | NULL | NULL | | 77 | 76 | 153 | | 55 | 82 | 137 | | NULL | 74 | NULL | -- 表达式部分可以用函数 mysql> select rand(); +--------------------+ | rand() | +--------------------+ | 0.6669325378415478 | +--------------------+ 1 row in set (0.00 sec)通过as给字段取别名mysql> select '锄禾日当午' as '标题'; -- 取别名 +------------+ | 标题 | +------------+ | 锄禾日当午 | +------------+ 1 row in set (0.00 sec) mysql> select ch,math,ch+math as '总分' from stu; +------+------+------+ | ch | math | 总分 | +------+------+------+ | 80 | NULL | NULL | | 77 | 76 | 153 | | 55 | 82 | 137 | | NULL | 74 | NULL | -- 多学一招:as可以省略 mysql> select ch,math,ch+math '总分' from stu; +------+------+------+ | ch | math | 总分 | +------+------+------+ | 80 | NULL | NULL | | 77 | 76 | 153 | | 55 | 82 | 137 | | NULL | 74 | NULL |1.5.2 from子句from:来自,from后面跟的是数据源。数据源可以有多个。返回笛卡尔积。插入测试表create table t1( str char(2) ); insert into t1 values ('aa'),('bb'); create table t2( num int ); insert into t2 values (10),(20);测试-- from子句 mysql> select * from t1; +------+ | str | +------+ | aa | | bb | +------+ 2 rows in set (0.00 sec) -- 多个数据源,返回笛卡尔积 mysql> select * from t1,t2; +------+------+ | str | num | +------+------+ | aa | 10 | | bb | 10 | | aa | 20 | | bb | 20 | +------+------+ 4 rows in set (0.00 sec)1.5.3 dual表dual表是一个伪表。在有些特定情况下,没有具体的表的参与,但是为了保证select语句的完整又必须要一个表名,这时候就使用伪表。mysql> select 10*10 as 结果 from dual; +------+ | 结果 | +------+ | 100 | +------+ 1 row in set (0.00 sec)1.5.4 where子句where后面跟的是条件,在数据源中进行筛选。返回条件为真记录MySQL支持的运算符-- 比较运算符 > 大于 < 小于 >= 大于等于 <= 小于等于 = 等于 != 不等于 -- 逻辑运算符 and 与 or 或 not 非 -- 其他 in | not in 字段的值在枚举范围内 between…and|not between…and 字段的值在数字范围内 is null | is not null 字段的值不为空例题:-- 查找语文成绩及格的学生 mysql> select * from stu where ch>=60; -- 查询语文和数学都及格的学生 mysql> select * from stu where ch>=60 and math>=60; -- 查询语文或数学不及格的学生 mysql> select * from stu where ch<60 or math<60;思考:如下语句输出什么?mysql> select * from stu where 1; -- 输出所有数据 mysql> select * from stu where 0; -- 不输出数据思考:如何查找北京和上海的学生-- 通过or实现 mysql> select * from stu where stuaddress='北京' or stuaddress='上海'; -- 通过in语句实现 mysql> select * from stu where stuaddress in ('北京','上海'); -- 查询不是北京和上海的学生 mysql> select * from stu where stuaddress not in ('北京','上海');思考:查找年龄在20~25之间-- 方法一: mysql> select * from stu where stuage>=20 and stuage<=25; -- 方法二: mysql> select * from stu where not(stuage<20 or stuage>25); -- 方法三:between...and... mysql> select * from stu where stuage between 20 and 25; -- 年龄不在20~25之间 mysql> select * from stu where stuage not between 20 and 25;思考:-- 查找缺考的学生 mysql> select * from stu where ch is null or math is null; +--------+----------+--------+--------+---------+------------+------+------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | ch | math | +--------+----------+--------+--------+---------+------------+------+------+ | s25301 | 张秋丽 | 男 | 18 | 1 | 北京 | 80 | NULL | | s25304 | 欧阳俊雄 | 男 | 28 | 4 | 天津 | NULL | 74 | +--------+----------+--------+--------+---------+------------+------+------+ -- 查找没有缺考的学生 mysql> select * from stu where ch is not null and math is not null; +--------+----------+--------+--------+---------+------------+------+------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | ch | math | +--------+----------+--------+--------+---------+------------+------+------+ | s25302 | 李文才 | 男 | 31 | 3 | 上海 | 77 | 76 | | s25303 | 李斯文 | 女 | 22 | 2 | 北京 | 55 | 82 | | s25305 | 诸葛丽丽 | 女 | 23 | 7 | 河南 | 72 | 56 | | s25318 | 争青小子 | 男 | 26 | 6 | 天津 | 86 | 92 | | s25319 | 梅超风 | 女 | 23 | 5 | 河北 | 74 | 67 | | s25320 | Tom | 男 | 24 | 8 | 北京 | 65 | 67 | | s25321 | Tabm | 女 | 23 | 9 | 河北 | 88 | 77 | +--------+----------+--------+--------+---------+------------+------+------+ 7 rows in set (0.00 sec) -- 查找需要补考的学生 mysql> select * from stu where ch<60 or math<60 or ch is null or math is null; +--------+----------+--------+--------+---------+------------+------+------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | ch | math | +--------+----------+--------+--------+---------+------------+------+------+ | s25301 | 张秋丽 | 男 | 18 | 1 | 北京 | 80 | NULL | | s25303 | 李斯文 | 女 | 22 | 2 | 北京 | 55 | 82 | | s25304 | 欧阳俊雄 | 男 | 28 | 4 | 天津 | NULL | 74 | | s25305 | 诸葛丽丽 | 女 | 23 | 7 | 河南 | 72 | 56 | +--------+----------+--------+--------+---------+------------+------+------+ 4 rows in set (0.00 sec)练习:-- 1、查找学号是s25301,s25302,s25303的学生 mysql> select * from stu where stuno in ('s25301','s25302','s25303'); +--------+---------+--------+--------+---------+------------+------+------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | ch | math | +--------+---------+--------+--------+---------+------------+------+------+ | s25301 | 张秋丽 | 男 | 18 | 1 | 北京 | 80 | NULL | | s25302 | 李文才 | 男 | 31 | 3 | 上海 | 77 | 76 | | s25303 | 李斯文 | 女 | 22 | 2 | 北京 | 55 | 82 | +--------+---------+--------+--------+---------+------------+------+------+ 3 rows in set (0.00 sec) -- 2、查找年龄是18~20的学生 mysql> select * from stu where stuage between 18 and 20; +--------+---------+--------+--------+---------+------------+------+------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | ch | math | +--------+---------+--------+--------+---------+------------+------+------+ | s25301 | 张秋丽 | 男 | 18 | 1 | 北京 | 80 | NULL | +--------+---------+--------+--------+---------+------------+------+------+ 1 row in set (0.00 sec)1.5.5 group by 【分组查询】将查询的结果分组,分组查询目的在于统计数据。-- 查询男生和女生的各自语文平均分 mysql> select stusex,avg(ch) '平均分' from stu group by stusex; +--------+---------+ | stusex | 平均分 | +--------+---------+ | 女 | 72.2500 | | 男 | 77.0000 | +--------+---------+ 2 rows in set (0.00 sec) -- 查询男生和女生各自多少人 mysql> select stusex,count(*) 人数 from stu group by stusex; +--------+------+ | stusex | 人数 | +--------+------+ | 女 | 4 | | 男 | 5 | +--------+------+ 2 rows in set (0.00 sec) -- 查询每个地区多少人 mysql> select stuaddress,count(*) from stu group by stuaddress; +------------+----------+ | stuaddress | count(*) | +------------+----------+ | 上海 | 1 | | 北京 | 3 | | 天津 | 2 | | 河北 | 2 | | 河南 | 1 | +------------+----------+ 5 rows in set (0.00 sec) -- 每个地区的数学平均分 mysql> select stuaddress,avg(math) from stu group by stuaddress; +------------+-----------+ | stuaddress | avg(math) | +------------+-----------+ | 上海 | 76.0000 | | 北京 | 74.5000 | | 天津 | 83.0000 | | 河北 | 72.0000 | | 河南 | 56.0000 | +------------+-----------+ 5 rows in set (0.00 sec)查询字段是普通字段,只取第一个值通过group_concat()函数将同一组的值连接起来显示mysql> select group_concat(stuname),stusex,avg(math) from stu group by stusex; +-------------------------------------+--------+-----------+ | group_concat(stuname) | stusex | avg(math) | +-------------------------------------+--------+-----------+ | 李斯文,诸葛丽丽,梅超风,Tabm | 女 | 70.5000 | | 张秋丽,李文才,欧阳俊雄,争青小子,Tom | 男 | 77.2500 | +-------------------------------------+--------+-----------+ 2 rows in set (0.00 sec)多列分组mysql> select stuaddress,stusex,avg(math) from stu group by stuaddress,stusex; +------------+--------+-----------+ | stuaddress | stusex | avg(math) | +------------+--------+-----------+ | 上海 | 男 | 76.0000 | | 北京 | 女 | 82.0000 | | 北京 | 男 | 67.0000 | | 天津 | 男 | 83.0000 | | 河北 | 女 | 72.0000 | | 河南 | 女 | 56.0000 | +------------+--------+-----------+ 6 rows in set (0.00 sec)小结:1、如果是分组查询,查询字段是分组字段和聚合函数。 2、查询字段是普通字段,只取第一个值 3、group_concat()将同一组的数据连接起来1.5.6 order by排序asc:升序【默认】desc:降序-- 按年龄的升序排列 mysql> select * from stu order by stuage asc; mysql> select * from stu order by stuage; -- 默认是升序 -- 按总分降序 mysql> select *,ch+math '总分' from stu order by ch+math desc;多列排序-- 年龄升序,如果年龄一样,按ch降序排列 mysql> select * from stu order by stuage asc,ch desc;思考如下代码表示什么含义select * from stu order by stuage desc,ch desc; #年龄降序,语文降序 select * from stu order by stuage desc,ch asc; #年龄降序,语文升序 select * from stu order by stuage,ch desc; #年龄升序、语文降序 select * from stu order by stuage,ch; #年龄升序、语文升序1.5.7 having条件having:是在结果集上进行条件筛选例题-- 查询女生 mysql> select * from stu where stusex='女'; +--------+----------+--------+--------+---------+------------+------+------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | ch | math | +--------+----------+--------+--------+---------+------------+------+------+ | s25303 | 李斯文 | 女 | 22 | 2 | 北京 | 55 | 82 | | s25305 | 诸葛丽丽 | 女 | 23 | 7 | 河南 | 72 | 56 | | s25319 | 梅超风 | 女 | 23 | 5 | 河北 | 74 | 67 | | s25321 | Tabm | 女 | 23 | 9 | 河北 | 88 | 77 | +--------+----------+--------+--------+---------+------------+------+------+ 4 rows in set (0.00 sec) -- 查询女生 mysql> select * from stu having stusex='女'; +--------+----------+--------+--------+---------+------------+------+------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | ch | math | +--------+----------+--------+--------+---------+------------+------+------+ | s25303 | 李斯文 | 女 | 22 | 2 | 北京 | 55 | 82 | | s25305 | 诸葛丽丽 | 女 | 23 | 7 | 河南 | 72 | 56 | | s25319 | 梅超风 | 女 | 23 | 5 | 河北 | 74 | 67 | | s25321 | Tabm | 女 | 23 | 9 | 河北 | 88 | 77 | +--------+----------+--------+--------+---------+------------+------+------+ 4 rows in set (0.00 sec) -- 查询女生姓名 mysql> select stuname from stu where stusex='女'; +----------+ | stuname | +----------+ | 李斯文 | | 诸葛丽丽 | | 梅超风 | | Tabm | +----------+ 4 rows in set (0.00 sec) -- 使用having报错,因为结果集中没有stusex字段 mysql> select stuname from stu having stusex='女'; ERROR 1054 (42S22): Unknown column 'stusex' in 'having clause'小结:having和where的区别:where是对原始数据进行筛选,having是对记录集进行筛选。1.5.8 limit语法:limit [起始位置],显示长度-- 从第0个位置开始取,取3条记录 mysql> select * from stu limit 0,3; -- 从第2个位置开始取,取3条记录 mysql> select * from stu limit 2,3; +--------+----------+--------+--------+---------+------------+------+------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | ch | math | +--------+----------+--------+--------+---------+------------+------+------+ | s25303 | 李斯文 | 女 | 22 | 2 | 北京 | 55 | 82 | | s25304 | 欧阳俊雄 | 男 | 28 | 4 | 天津 | NULL | 74 | | s25305 | 诸葛丽丽 | 女 | 23 | 7 | 河南 | 72 | 56 | +--------+----------+--------+--------+---------+------------+------+------+ 3 rows in set (0.00 sec)起始位置可以省略,默认是从0开始mysql> select * from stu limit 3; +--------+---------+--------+--------+---------+------------+------+------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | ch | math | +--------+---------+--------+--------+---------+------------+------+------+ | s25301 | 张秋丽 | 男 | 18 | 1 | 北京 | 80 | NULL | | s25302 | 李文才 | 男 | 31 | 3 | 上海 | 77 | 76 | | s25303 | 李斯文 | 女 | 22 | 2 | 北京 | 55 | 82 | +--------+---------+--------+--------+---------+------------+------+------+ 3 rows in set (0.00 sec)例题:找出班级总分前三名mysql> select *,ch+math total from stu order by (ch+math) desc limit 0,3; +--------+----------+--------+--------+---------+------------+------+------+-------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | ch | math | total | +--------+----------+--------+--------+---------+------------+------+------+-------+ | s25318 | 争青小子 | 男 | 26 | 6 | 天津 | 86 | 92 | 178 | | s25321 | Tabm | 女 | 23 | 9 | 河北 | 88 | 77 | 165 | | s25302 | 李文才 | 男 | 31 | 3 | 上海 | 77 | 76 | 153 | +--------+----------+--------+--------+---------+------------+------+------+-------+ 3 rows in set (0.00 sec)多学一招:limit在update和delete语句中也是可以使用的。-- 前3名语文成绩加1分 mysql> update stu set ch=ch+1 order by ch+math desc limit 3; Query OK, 3 rows affected (0.00 sec) Rows matched: 3 Changed: 3 Warnings: 0 -- 前3名删除 mysql> delete from stu order by ch+math desc limit 3; Query OK, 3 rows affected (0.00 sec)1.5.9 查询语句中的选项查询语句中的选项有两个:1、 all:显示所有数据 【默认】2、 distinct:去除结果集中重复的数据mysql> select all stuaddress from stu; +------------+ | stuaddress | +------------+ | 北京 | | 北京 | | 天津 | | 河南 | | 河北 | | 北京 | +------------+ 6 rows in set (0.00 sec) -- 去除重复的项 mysql> select distinct stuaddress from stu; +------------+ | stuaddress | +------------+ | 北京 | | 天津 | | 河南 | | 河北 | +------------+ 4 rows in set (0.00 sec)1.6 聚合函数sum() 求和avg() 求平均值max() 求最大值min() 求最小值count() 求记录数# 语文最高分 mysql> select max(ch) '语文最大值' from stu; +------------+ | 语文最大值 | +------------+ | 88 | +------------+ 1 row in set (0.00 sec) #求语文总分、语文平均分、语文最低分、总人数 mysql> select max(ch) 语文最高分,min(ch) 语文最低分,sum(ch) 语文总分,avg(ch) 语文平均分,count(*) 总人数 from stu; +------------+------------+----------+------------+--------+ | 语文最高分 | 语文最低分 | 语文总分 | 语文平均分 | 总人数 | +------------+------------+----------+------------+--------+ | 88 | 55 | 597 | 74.6250 | 9 | +------------+------------+----------+------------+--------+ 1 row in set (0.00 sec)1.7 模糊查询1.7.1 通配符_ [下划线] 表示任意一个字符% 表示任意字符练习1、满足“T_m”的有(A、C) A:Tom B:Toom C:Tam D:Tm E:Tmo 2、满足“T_m_”的有( B C) A:Tmom B:Tmmm C:T1m2 D:Tmm E:Tm 3、满足“张%”的是(ABCD) A:张三 B:张三丰 C:张牙舞爪 D:张 E:小张 4、满足“%诺基亚%”的是(ABCD) A:诺基亚2100 B:2100诺基亚 C:把我的诺基亚拿过来 D:诺基亚1.7.2 模糊查询(like)模糊查询的条件不能用'=',要使用like。mysql> select * from stu where stuname like 'T_m'; +--------+---------+--------+--------+---------+------------+------+------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | ch | math | +--------+---------+--------+--------+---------+------------+------+------+ | s25320 | Tom | 男 | 24 | 8 | 北京 | 65 | 67 | +--------+---------+--------+--------+---------+------------+------+------+ 1 row in set (0.00 sec) -- 查询姓张的学生 mysql> select * from stu where stuname like '张%'; +--------+---------+--------+--------+---------+------------+------+------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | ch | math | +--------+---------+--------+--------+---------+------------+------+------+ | s25301 | 张秋丽 | 男 | 18 | 1 | 北京 | 80 | NULL | +--------+---------+--------+--------+---------+------------+------+------+ 1 row in set (0.00 sec)1.8 union(联合)插入测试数据create table emp( id tinyint unsigned auto_increment primary key, name varchar(20) not null, skill set('PHP','mysql','java') ); insert into emp values (null,'李白',1),(null,'杜甫',2),(null,'白居易',4) insert into emp values (null,'争青小子',3)1.8.1 union的使用作用:将多个select语句结果集纵向联合起来语法:select 语句 union [选项] select 语句 union [选项] select 语句-- 查询stu表中的姓名和emp表中姓名 结果自动合并的重复的记录 mysql> select stuname from stu union select name from emp;例题:查询上海的男生和北京的女生-- 方法一: mysql> select * from stu where (stuaddress='上海' and stusex='男') or (stuaddress='北京' and stusex='女'); +--------+---------+--------+--------+---------+------------+------+------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | ch | math | +--------+---------+--------+--------+---------+------------+------+------+ | s25302 | 李文才 | 男 | 31 | 3 | 上海 | 77 | 76 | | s25303 | 李斯文 | 女 | 22 | 2 | 北京 | 55 | 82 | +--------+---------+--------+--------+---------+------------+------+------+ 2 rows in set (0.00 sec) -- 方法二:union mysql> select * from stu where stuaddress='上海' and stusex='男' union select * from stu where stuaddress='北京' and stusex='女'; +--------+---------+--------+--------+---------+------------+------+------+ | stuNo | stuName | stuSex | stuAge | stuSeat | stuAddress | ch | math | +--------+---------+--------+--------+---------+------------+------+------+ | s25302 | 李文才 | 男 | 31 | 3 | 上海 | 77 | 76 | | s25303 | 李斯文 | 女 | 22 | 2 | 北京 | 55 | 82 | +--------+---------+--------+--------+---------+------------+------+------+ 2 rows in set (0.00 sec) 结论:union可以将一个复杂的条件转成两个简单的条件1.8.2 union的选项union的选项有两个1、 all:显示所有数据2、 distinct:去除重复的数据【默认】mysql> select stuname from stu union all select name from emp;1.8.3 union的注意事项1、 union两边的select语句的字段个数必须一致2、 union两边的select语句的字段名可以不一致,最终按第一个select语句的字段名。3、 union两边的select语句中的数据类型可以不一致。1.9 补充1.9.1 插入数据时主键冲突-- 插入测试表 mysql> create table stu( -> id char(4) primary key, -> name varchar(20) -> )engine=innodb; Query OK, 0 rows affected (0.06 sec) -- 插入测试数据 mysql> insert into stu values ('s001','tom'); Query OK, 1 row affected (0.00 sec)如果插入的主键重复会报错解决方法:如果插入的主键重复就执行替换语法一:mysql> replace into stu values('s002','ketty'); Query OK, 2 rows affected (0.00 sec) # 原理:如果插入的主键不重复就直接插入,如果主键重复就替换(删除原来的记录,插入新记录)语法二(推荐):on duplicate key update # 当插入的值与主键或唯一键有冲突执行update操作 -- 例题 mysql> insert into stu values ('s002','李白') on duplicate key update name='李白'; Query OK, 2 rows affected (0.00 sec) # 插入的数据和主键或唯一键起冲突,将s002的name字段改为‘李白’
2022年10月12日
190 阅读
0 评论
0 点赞
2022-10-12
MySQL数据库(二)
1.1 目标掌握char和varchar的应用;了解text类型是用来存储长文本数据;了解字段属性的作用;掌握主键primary key的应用以及效果;掌握逻辑主键的自增长auto_increment应用;掌握唯一键与主键的区别;了解外键的约束作用;掌握主键冲突的两种解决方案;1.2 数据类型MySQL中的数据类型是强类型1.2.1 数值型1、 整型整形占用字节数范围tinyint1-128~127smallint2-32768~32767mediumint3-8388608~8388607int4-2147483648~2147483647bigint8-9223372036854775808~9223372036854775807选择的范围尽可能小,范围越小占用资源越少mysql> create table stu1( -> id tinyint, # 范围要尽可能小,范围越小,占用空间越少 -> name varchar(20) -> ); Query OK, 0 rows affected (0.02 sec) -- 超出范围会报错 mysql> insert into stu1 values (128,'tom'); ERROR 1264 (22003): Out of range value for column 'id' at row 1无符号整形(unsigned) 无符号整形就是没有负数,无符号整数是整数的两倍mysql> create table stu2( -> id tinyint unsigned # 无符号整数 -> ); Query OK, 0 rows affected (0.02 sec) mysql> insert into stu2 values (128); Query OK, 1 row affected (0.00 sec)整形支持显示宽度,显示宽带是最小的显示位数,如int(11)表示整形最少用11位表示,如果不够位数用0填充。显示宽度默认不起作用,必须结合zerofill才起作用。mysql> create table stu4( -> id int(5), -> num int(5) zerofill # 添加前导0,int(5)显示宽带是5 -> ); Query OK, 0 rows affected (0.05 sec) mysql> insert into stu4 values (12,12); Query OK, 1 row affected (0.00 sec) mysql> select * from stu4; +------+-------+ | id | num | +------+-------+ | 12 | 00012 | +------+-------+ 1 row in set (0.00 sec)小结:1、范围要尽可能小,范围越小,占用空间越少 2、无符号整数是整数的两倍 3、整形支持显示宽度,显示宽带是最小的显示位数,必须结合zerofill才起作用2、浮点型浮点型占用字节数范围float(单精度型)4-3.4E+38~3.4E+38double(双精度型)8-1.8E+308~1.8E+308浮点型的声明:float(M,D) double(M,D) M:总位数 D:小数位数例题mysql> create table stu5( -> num1 float(5,2), -- 浮点数 -> num2 double(6,1) -- 双精度数 -> ); Query OK, 0 rows affected (0.05 sec) mysql> insert into stu5 values (3.1415,12.96); Query OK, 1 row affected (0.00 sec) mysql> select * from stu5; +------+------+ | num1 | num2 | +------+------+ | 3.14 | 13.0 | +------+------+ 1 row in set (0.00 sec)MySQL浮点数支持科学计数法mysql> create table stu6( -> num float # 不指定位数,默认是小数点后面6位 double默认是17位 -> ); Query OK, 0 rows affected (0.03 sec) mysql> insert into stu6 values (5E2),(6E-2); # 插入科学计数法 Query OK, 2 rows affected (0.00 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> select * from stu6; +------+ | num | +------+ | 500 | | 0.06 | +------+ 2 rows in set (0.00 sec)浮点数精度会丢失mysql> insert into stu6 values(99.999999999); Query OK, 1 row affected (0.00 sec) mysql> select * from stu6; +------+ | num | +------+ | 100 | +------+小结:1、浮点数有单精度和双精度 2、浮点数支持科学计数法 3、浮点数精度会丢失3、小数(定点数)原理:将整数部分和小数部分分开存储语法:decimal(M,D)例题:mysql> create table stu8( -> num decimal(20,9) # 存放定点数 -> ); Query OK, 0 rows affected (0.00 sec) mysql> insert into stu8 values(12.999999999); Query OK, 1 row affected (0.00 sec) mysql> select * from stu8; +--------------+ | num | +--------------+ | 12.999999999 | +--------------+ 1 row in set (0.00 sec)小结:1、decimal是变长的,大致是每9个数字用4个字节存储,整数和小数分开计算。M最大是65,D最大是30,默认是(10,2)。 2、定点和浮点都支持无符号、显示宽度0填充。1.2.2 字符型在数据库中没有字符串概念,只有字符,所以数据库中只能用单引号数据类型描述char定长字符,最大可以到255varchar可变长度字符,最大可以到65535tinytext2^8^–1 =255text2^16^–1 =65535mediumtext2^24^–1longtext2^32^–1char(4):存放4个字符,中英文一样。varchar(L)实现变长机制,需要额外的空间来记录数据真实的长度。L的理论长度是65535,但事实上达不到,因为有的字符是多字节字符,所以L达不到65535。text系列的类型在表中存储的是地址,占用大小大约10个字节一个记录的所有字段的总长度也不能超过65535个字节。小结:1、char是定长,var是变长 2、char最大值是255,varchar最大值是65535,具体要看字符编码 3、text系列在表中存储的是地址 4、一条记录的总长度不能超过655351.2.3 枚举(enum)从集合中选择一个值作为数据(单选)mysql> create table stu12( -> name varchar(20), -> sex enum('男','女','保密') # 枚举 -> ); Query OK, 0 rows affected (0.06 sec) -- 插入的枚举值只能是枚举中提供的选项 mysql> insert into stu12 values ('tom','男'); Query OK, 1 row affected (0.00 sec) -- 报错,只能插入男、女、保密 mysql> insert into stu12 values ('tom','不告诉你'); ERROR 1265 (01000): Data truncated for column 'sex' at row 1枚举值是通过整形数字来管理的,第一个值是1,第二个值是2,以此类推,枚举值在数据库存储的是整形数字。mysql> insert into stu12 values ('berry',2); -- 插入数字 Query OK, 1 row affected (0.00 sec) mysql> select * from stu12; +-------+------+ | name | sex | +-------+------+ | tom | 男 | | berry | 女 | +-------+------+ mysql> select * from stu12 where sex=2; -- 2表示第二个枚举值 +-------+------+ | name | sex | +-------+------+ | berry | 女 | +-------+------+ 1 row in set (0.00 sec)枚举优点:(1)、限制值 (2)、节省空间 (3)、运行速度快(整形比字符串运行速度快)思考:已知枚举占用两个字节,所以最多可以有多少个枚举值?答:2字节=16位,2^16^=65536,范围是(0-65535),由于枚举从1开始,所以枚举值最多有65535个1.2.4 集合(set)从集合中选择一些值作为数据(多选)mysql> create table stu13( -> name varchar(20), -> hobby set('爬山','读书','游泳','烫头') -- 集合 -> ); Query OK, 0 rows affected (0.00 sec) mysql> insert into stu13 values ('tom','爬山'); mysql> insert into stu13 values ('Berry','爬山,游泳'); Query OK, 1 row affected (0.00 sec) mysql> insert into stu13 values ('Berry','游泳,爬山'); -- 插入的顺序不一样,但显示的顺序一样 Query OK, 1 row affected (0.00 sec) mysql> select * from stu13; +-------+-----------+ | name | hobby | +-------+-----------+ | tom | 爬山 | | Berry | 爬山,游泳 | | Berry | 爬山,游泳 | +-------+-----------+ 3 rows in set (0.00 sec)集合和枚举一样,也为每个集合元素分配一个固定值,分配方式是从前往后按2的0、1、2、…次方,转换成二进制后只有一位是1,其他都是0。'爬山','读书','游泳','烫头' 1 2 4 8 mysql> select hobby+0 from stu13; +---------+ | hobby+0 | +---------+ | 1 | | 5 | | 5 | +---------+ mysql> insert into stu13 values ('rose',15); Query OK, 1 row affected (0.00 sec)已知集合类型占8个字节,那么集合中最多有多少选项答:有64个选项。1.2.5 日期时间型数据类型描述datetime日期时间,占用8个字节date日期 占用3个字节time时间 占用3个字节year年份,占用1个字节timestamp时间戳,占用4个字节1、datetime和datedatetime格式:年-月-日 小时:分钟:秒。支持的范围是'1000-01-01 00:00:00'到'9999-12-3123:59:59'。mysql> create table stu14( -> t1 datetime, -- 日期时间 -> t2 date -- 日期 -> ); Query OK, 0 rows affected (0.05 sec) -- 插入测试数据 mysql> insert into stu14 values ('2019-01-15 12:12:12','2019-01-15 12:12:12'); Query OK, 1 row affected, 1 warning (0.00 sec) -- 查询 mysql> select * from stu14; +---------------------+------------+ | t1 | t2 | +---------------------+------------+ | 2019-01-15 12:12:12 | 2019-01-15 | +---------------------+------------+ 1 row in set (0.00 sec)2、timestamp(时间戳)datetime类型和timestamp类型表现上是一样的,他们的区别在于:datetime从1000到9999,而timestamp从1970年~2038年(原因在于timestamp占用4个字节,和整形的范围一样,2038年01月19日11:14:07以后的秒数就超过了4个字节的长度)mysql> create table stu15( -> t1 timestamp -> ); Query OK, 0 rows affected (0.06 sec) mysql> insert into stu15 values ('2038-01-19 11:14:07'); Query OK, 1 row affected (0.00 sec)3、year只能表示1901~2155之间的年份,因为只占用1个字节,只能表示255个数mysql> create table stu16( -> y1 year -> ); Query OK, 0 rows affected (0.08 sec) mysql> insert into stu16 values (2155); Query OK, 1 row affected (0.00 sec)4、time可以表示时间,也可以表示时间间隔。范围是:-838:59:59~838:59:59mysql> create table stu17( -> t1 time -> ); Query OK, 0 rows affected (0.02 sec) mysql> insert into stu17 values ('12:12:12'); Query OK, 1 row affected (0.00 sec) mysql> insert into stu17 values ('212:12:12'); Query OK, 1 row affected (0.00 sec) mysql> insert into stu17 values ('-212:12:12'); Query OK, 1 row affected (0.00 sec) mysql> insert into stu17 values ('839:00:00'); -- 报错 ERROR 1292 (22007): Incorrect time value: '839:00:00' for column 't1' at row 1 -- time支持以天的方式来表示时间间隔 mysql> insert into stu17 values ('10 10:25:25'); -- 10天10小时25分25秒 Query OK, 1 row affected (0.00 sec) mysql> select * from stu17; +------------+ | t1 | +------------+ | 12:12:12 | | 212:12:12 | | -212:12:12 | | 250:25:25 | +------------+ 4 rows in set (0.00 sec)1.2.6 BooleanMySQL不支持布尔型,true和false在数据库中对应的是1和0mysql> create table stu18( -> flag boolean -> ); Query OK, 0 rows affected (0.05 sec) mysql> desc stu18; +-------+------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+------------+------+-----+---------+-------+ | flag | tinyint(1) | YES | | NULL | | +-------+------------+------+-----+---------+-------+ 1 row in set (0.00 sec) mysql> insert into stu18 values (true),(false); Query OK, 2 rows affected (0.00 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> select * from stu18; +------+ | flag | +------+ | 1 | | 0 | +------+ 2 rows in set (0.00 sec小结:boolean型在MySQL中对应的是tinyint。1.2.6 练习题电话号码一般使用什么数据类型存储? varchar 手机号码用什么数据类型 char 性别一般使用什么数据类型存储? char tinyint enum 年龄信息一般使用什么数据类型存储? tinyint 照片信息一般使用什么数据类型存储? binary 薪水一般使用什么数据类型存储? decimal1.3 列属性1.3.1 是否为空(null|not null)null表示字段值可以为null not null字段值不能为空练习学员姓名允许为空吗? not null 家庭地址允许为空吗? not null 电子邮件信息允许为空吗? null 考试成绩允许为空吗? null1.3.2 默认值(default)如果一个字段没有插入值,可以默认插入一个指定的值mysql> create table stu19( -> name varchar(20) not null default '姓名不详', -> addr varchar(50) not null default '地址不详' -> ); Query OK, 0 rows affected (0.05 sec) mysql> insert into stu19(name) values ('tom'); Query OK, 1 row affected (0.00 sec) mysql> insert into stu19 values (default,default); Query OK, 1 row affected (0.00 sec) mysql> select * from stu19; +----------+----------+ | name | addr | +----------+----------+ | tom | 地址不详 | | 姓名不详 | 地址不详 | +----------+----------+ 2 rows in set (0.00 sec)小结:default关键字用来插入默认值1.3.3 自动增长(auto_increment)字段值从1开始,每次递增1,自动增长的值就不会有重复,适合用来生成唯一的id。在MySQL中只要是自动增长列必须是主键1.3.4 主键(primary key)主键概念:唯一标识表中的记录的一个或一组列称为主键。特点:1、不能重复、不能为空 2、一个表只能有一个主键。作用:1、保证数据完整性 2、加快查询速度选择主键的原则最少性:尽量选择单个键作为主键 稳定性:尽量选择数值更新少的列作为主键 比如:学号,姓名、地址 这三个字段都不重复,选哪个做主键 选学号,因为学号最稳定练习-- 创建主键方法一 mysql> create table stu20( -> id int auto_increment primary key, -> name varchar(20) -> ); Query OK, 0 rows affected (0.04 sec) -- 创建主键方法二 mysql> create table stu21( -> id int auto_increment, -> name varchar(20), -> primary key(id) -> ); Query OK, 0 rows affected (0.02 sec)组合键mysql> create table stu22( -> classname varchar(20), -> stuname varchar(20), -> primary key(classname,stuname) -- 创建组合键 -> ); Query OK, 0 rows affected (0.00 sec) mysql> desc stu22; +-----------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-----------+-------------+------+-----+---------+-------+ | classname | varchar(20) | NO | PRI | | | | stuname | varchar(20) | NO | PRI | | | +-----------+-------------+------+-----+---------+-------+ 2 rows in set (0.00 sec)通过更改表添加主键mysql> create table stu23( -> id int, -> name varchar(20) -> ); Query OK, 0 rows affected (0.05 sec) -- 添加主键 mysql> alter table stu23 add primary key(id); Query OK, 0 rows affected (0.09 sec) Records: 0 Duplicates: 0 Warnings: 0删除主键mysql> alter table stu23 drop primary key; Query OK, 0 rows affected (0.03 sec) Records: 0 Duplicates: 0 Warnings: 0插入数据mysql> create table stu25( -> id tinyint unsigned auto_increment primary key, -> name varchar(20) -> ); Query OK, 0 rows affected (0.05 sec) -- 插入数据 mysql> insert into stu25 values (3,'tom'); -- 可以直接插入数字 Query OK, 1 row affected (0.06 sec) -- 自动增长列可以插入null,让列的值自动递增 mysql> insert into stu25 values (null,'berry'); Query OK, 1 row affected (0.00 sec)小结:1、只要是auto_increment必须是主键,但是主键不一定是auto_increment2、主键特点是不能重复不能为空3、一个表只能有一个主键,但是一个主键可以有多个字段组成4、自动增长列通过插入null值让其递增5、自动增长列的数据被删除,默认不再重复使用。truncate table删除数据后,再次插入从1开始练习在主键列输入的数值,允许为空吗? 不可以 一个表可以有多个主键吗? 不可以 在一个学校数据库中,如果一个学校内允许重名的学员,但是一个班级内不允许学员重名,可以组合班级和姓名两个字段一起来作为主键吗? 对 标识列(自动增长列)允许为字符数据类型吗? 不允许 一个自动增长列中,插入3行,删除2行,插入3行,删除2行,插入3行,删除2行,再次插入是多少? 101.3.5 唯一键(unique)键区别主键1、不能重复,不能为空2、一个表只能有一个主键唯一键1、不能重刻,可以为空2、一个表可以有多个唯一键例题-- 创建表的时候创建唯一键 mysql> create table stu26( -> id int auto_increment primary key, -> name varchar(20) unique -- 唯一键 -> ); Query OK, 0 rows affected (0.05 sec) -- 方法二 mysql> create table stu27( -> id int primary key, -> name varchar(20), -> unique(name) -> ); Query OK, 0 rows affected (0.05 sec) 多学一招: unique 或 unique key 是一样的通过修改表添加唯一键-- 将name设为唯一键 mysql> alter table stu28 add unique(name); -- 将name,addr设为唯一键 mysql> alter table stu28 add unique(name),add unique(addr); Query OK, 0 rows affected (0.00 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> desc stu28; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | int(11) | NO | PRI | NULL | | | name | varchar(20) | YES | UNI | NULL | | | addr | varchar(20) | YES | UNI | NULL | | +-------+-------------+------+-----+---------+-------+ 3 rows in set (0.02 sec)通过show create table 查看唯一键的名字通过唯一键的名字删除唯一键mysql> alter table stu28 drop index name; Query OK, 0 rows affected (0.00 sec) Records: 0 Duplicates: 0 Warnings: 01.3.6 备注(comment)说明性文本mysql> create table stu29( -> id int primary key comment '学号', -> name varchar(20) not null comment '姓名' -> ); Query OK, 0 rows affected (0.03 sec)注意:备注属于SQL代码的一部分1.4 SQL注释单行注释-- 单行注释 # 单行注释 多行注释 /* */1.5 数据完整性1.5.1 数据完整性包括1、实体完整性1、主键约束 2、唯一约束 3、标识列2、 域完整性1、数据类型约束 2、非空约束 3、默认值约束3、 引用完整性外键约束4、 自定义完整性1、存储过程 2、触发器1.5.2 主表和从表主表中没有的记录,从表不允许插入从表中有的记录,主表中不允许删除删除主表前,先删子表1.5.3 外键(foreign key)外键:从表中的公共字段-- 创建表的时候添加外键 drop table if exists stuinfo; create table stuinfo( id tinyint primary key, name varchar(20) )engine=innodb; drop table if exists stuscore; create table stuscore( sid tinyint primary key, score tinyint unsigned, foreign key(sid) references stuinfo(id) -- 创建外键 )engine=innodb; -- 通过修改表的时候添加外键 语法:alter table 从表 add foreign key(公共字段) references 主表(公共字段) drop table if exists stuinfo; create table stuinfo( id tinyint primary key, name varchar(20) )engine=innodb; drop table if exists stuscore; create table stuscore( sid tinyint primary key, score tinyint unsigned )engine=innodb; alter table stuscore add foreign key (sid) references stuinfo(id)删除外键通过外键的名字删除外键-- 删除外键 mysql> alter table stuscore drop foreign key `stuscore_ibfk_1`; Query OK, 0 rows affected (0.00 sec) Records: 0 Duplicates: 0 Warnings: 0小结:1、只有innodb才能支持外键 2、公共字段的名字可以不一样,但是数据类型要一样1.5.4 三种外键操作1、 严格限制(参见主表和从表)2、 置空操作(set null):如果主表记录删除,或关联字段更新,则从表外键字段被设置为null。3、 级联操作(cascade):如果主表记录删除,则从表记录也被删除。主表更新,从表外键字段也更新。语法:foreign key (外键字段) references 主表名 (关联字段) [主表记录删除时的动作] [主表记录更新时的动作]。一般说删除时置空,更新时级联。drop table if exists stuinfo; create table stuinfo( id tinyint primary key comment '学号,主键', name varchar(20) comment '姓名' )engine=innodb; drop table if exists stuscore; create table stuscore( id int auto_increment primary key comment '主键', sid tinyint comment '学号,外键', score tinyint unsigned comment '成绩', foreign key(sid) references stuinfo(id) on delete set null on update cascade )engine=innodb;小结:置空、级联操作中外键不能是从表的主键1.6 补充phpstudy中MySQL默认不是严格模式,将MySQL设置成严格模式打开my.ini,在sql-mode的值中,添加STRICT_TRANS_TABLESsql-mode="NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES"测试单词medium:中等的 small:小 tiny:微小 big:大
2022年10月12日
157 阅读
0 评论
0 点赞
2022-10-12
MySQL数据库(一)
1.1 目标掌握数据库的作用;能够通俗的解释什么是关系型数据库;能够至少说出三种关系型数据库;掌握MySQL客户端登录和登出MySQL服务器;理解数据库具体数据的存储逻辑;掌握创建、查看和删除数据库;了解MySQL数据库创建与删除指令对应的文件效果掌握数据表的增删改查操作;掌握数据的增删改查操作;1.2 数据库介绍1.2.1 作用数据库是用来存放数据的仓库数据库中存放的是表,表中存放的是数据。1.2.2 数据库的发展史萌芽阶段:文件系统最初始的数据库是用磁盘来存储数据的。文件就是最早的数据库。第一代数据库:层次模型优点:这是导航结构优点:结构清晰,分类查询方便缺点:有可能造成数据无效第一代数据库:网状模型网状模型解决了层次模型的数据不一致的问题,但没有解决导航问题。导航结构在查询中有时候效率低下,比如查询整个公司的四月的营业额。第二阶段:关系模型特点:1、每个表都是独立的2、通过关系字段将两个表连接起来3、关系:两个表的公共字段4、关系型数据库中多表联合查询效率低下。多学一招:为了解决关系型数据库多表查询效率的问题,项目中使用了NoSQL(非关系型数据库,Redis、mongodb等等),在数据库中按照键值对来存储,它是关系型数据库的补充。1.2.3 SQLStructured Query Language(结构化查询语言),是用来操作关系型数据库的一门语言。这是一个关系型数据库的通用操作语言,也成为标准SQL,也叫SQL-92。脚下留心:数据库的生产厂商为了占有市场份额,都会在标准SQL的基础上扩展一些自己的东西以吸引用户。1.2.4 常用的关系型数据库关系型数据库开发公司使用语言access微软公司SQLSQL Server微软公司T-SQLOracle甲骨文公司PL/SQLMySQL被甲骨文公司收购MySQL思考:已知标准SQL可以在所有的关系型数据库上运行,在Oracle上编写的PL/SQL能否在MySQL上运行?答:不可以,只能运行标准SQL1.3 连接服务器数据库是CS模式的软件,所以要连接数据库必须要有客户端软件。MySQL数据库默认端口号是33061.3.1 window界面连接服务器1、Navicat2、MySQL-Front1.3.2 通过web窗体连接主要有浏览器就可以访问数据库1.3.3 命令行连接host -h 主机 port -P 端口号 (大写) user -u 用户名 password -p 密码 (小写)例题-- 连接数据库 F:\wamp\PHPTutorial\MySQL\bin>mysql -h127.0.0.1 -P3306 -uroot -proot -- 明文 -- 如果连接本地数据库 -h可以省略 如果服务器端口是3306,-P端口号也可以省略 F:\wamp\PHPTutorial\MySQL\bin>mysql -uroot -proot -- 明文 -- 密文 F:\wamp\PHPTutorial\MySQL\bin>mysql -uroot -p Enter password: ****1.3.4 退出登录mysql> exit -- 方法一 mysql> quit -- 方法二 mysql> \q -- 方法三1.4 数据库基本概念1.4.1 数据库、表相关数据库:数据库中存放的是表,一个数据库中可以存放多个表表:表是用来存放数据的。关系:两个表的公共字段行:也称记录,也称实体列:也称字段,也称属性脚下留心:就表结构而言,表分为行和列;就表数据而言,表分为记录和字段;就面向对象而言,一个记录就是一个实体,一个字段就是一个属性。1.4.2 数据相关1、数据冗余:相同的数据存储在不同的地方冗余只能减少,不能杜绝。 减少冗余的方法是分表2、数据完整性:正确性+准确性=数据完整性正确性:数据类型正确 准确性:数据范围要准确思考:学生的年龄是整型,输入1000岁,正确性和准确性如何?答:正确的,但不准确。失去了数据完整性。1.4.3 数据库执行过程1.5 数据库的操作1.5.1 创建数据库语法:create database [if not exists] 数据名 [选项]例题-- 创建数据库 mysql> create database stu; Query OK, 1 row affected (0.06 sec) -- 创建数据库时,如果数据库已经存在就要报错 mysql> create database stu; # ERROR 1007 (HY000): Can't create database 'stu'; database exists -- 在创建数据库时候,判断数据库是否存在,不存在就创建 mysql> create database if not exists stu; Query OK, 1 row affected, 1 warning (0.00 sec) -- 特殊字符、关键字做数据库名,使用反引号将数据库名括起来 mysql> create database `create`; Query OK, 1 row affected (0.04 sec) mysql> create database `%$`; Query OK, 1 row affected (0.05 sec) -- 创建数据库时指定存储的字符编码 mysql> create database emp charset=gbk; Query OK, 1 row affected (0.00 sec) # 如果不指定编码,数据库默认使用安装数据库时指定的编码MySQL数据库的目录数据库保存的路径在安装MySQL的时候就配置好。 也可以在my.ini配置文件中更改数据库的保存地址。(datadir="F:/wamp/PHPTutorial/MySQL/data/") 一个数据库就对应一个文件夹,在文件夹中有一个db.opt文件。在此文件中设置数据库的字符集和校对集**小结:1、如果创建的数据库已存在,就会报错。解决方法:创建数据库的时候判断一下数据库是否存在,如果不存在再创建2、如果数据库名是关键字和特殊字符要报错。解决:在特殊字符、关键字行加上反引号3、创建数据库的时候可以指定字符编码脚下留心:创建数据库如果不指定字符编码,默认和MySQL服务器的字符编码是一致的。1.5.2 显示所有数据库语法:show databases例题mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | test | +--------------------+ 4 rows in set (0.00 sec)注意:数据库安装后,只带上面四个数据库1.5.3 删除数据库语法:drop database [if exists] 数据库名例题mysql> drop database `create`; Query OK, 0 rows affected (0.00 sec) mysql> drop database `%$`; Query OK, 0 rows affected (0.00 sec) -- 判断数据库是否存在,如果存在就删除 mysql> drop database if exists stu; Query OK, 0 rows affected (0.00 sec)小结:1、如果删除的数据库不存在,会报错解决:删除之前判断一下,如果存在就删除1.5.4 显示创建数据库的语句语法:show create database 数据库名例题:mysql> show create database emp; +----------+-------------------------------------------------------------+ | Database | Create Database | +----------+-------------------------------------------------------------+ | emp | CREATE DATABASE `emp` /*!40100 DEFAULT CHARACTER SET gbk */ | +----------+-------------------------------------------------------------+ 1 row in set (0.00 sec)1.5.5 修改数据库只能修改数据库选项,数据库的选项只有字符编码语法:alter database 数据库名 charset=字符编码例题:mysql> alter database emp charset=utf8; Query OK, 1 row affected (0.00 sec)小结:1、修改数据库只能修改数据库的字符编码2、在MySQL中utf字符编码之间没有横杆 utf81.5.6 选择数据库语法:use 数据库名例题mysql> use emp; Database changed1.6 表的操作mysql> create database data; Query OK, 1 row affected (0.00 sec) mysql> use data; Database changed1.6.1 创建表语法:create table [if not exists] `表名`( `字段名` 数据类型 [null|not null] [default] [auto_increment] [primary key] [comment], `字段名 数据类型 … )[engine=存储引擎] [charset=字符编码] null|not null 是否为空 default: 默认值 auto_increment 自动增长,默认从1开始,每次递增1 primary key 主键,主键的值不能重复,不能为空,每个表必须只能有一个主键 comment: 备注 engine 引擎决定了数据的存储和查找 myisam、innodb 脚下留心:表名和字段名如果用了关键字,要用反引号引起来。例题: -- 设置客户端和服务器通讯的编码 mysql> set names gbk; Query OK, 0 rows affected (0.00 sec) -- 创建简单的表 mysql> create table stu1( -> id int auto_increment primary key, -> name varchar(20) not null -> )engine=innodb charset=gbk; Query OK, 0 rows affected (0.11 sec) -- 创建复杂的表 mysql> create table stu2( -> id int auto_increment primary key comment '主键', -> name varchar(20) not null comment '姓名', -> `add` varchar(50) not null default '地址不详' comment '地址', -> score int comment '成绩,可以为空' -> )engine=myisam; Query OK, 0 rows affected (0.06 sec)小结:1、如果不指定引擎,默认是innodb2、如果不指定字符编码,默认和数据库编码一致3、varchar(20) 表示长度是20个字符数据表的文件一个数据库对应一个文件夹 一个表对应一个或多个文件 引擎是myisam,一个表对应三个文件 .frm :存储的是表结构 .myd :存储的是表数据 .myi :存储的表数据的索引 引擎是innodb,一个表对应一个表结构文件,innodb的都有表的数据都保存在ibdata1文件中,如果数据量很大,会自动的创建ibdata2,ibdata3...innodb和myisam的区别引擎 myisam1、查询速度快2、容易产生碎片3、不能约束数据innodb1、以前没有myisam查询速度快,现在已经提速了2、不产生碎片3、可以约束数据脚下留心:推荐使用innodb。1.6.2 显示所有表语法show tables;例题:mysql> show tables; Empty set (0.00 sec)1.6.3 显示创建表的语句语法show create table; -- 结果横着排列 show create table \G -- 将结果竖着排列例题1.6.4 查看表结构语法desc[ribe] 表名例题-- 方法一 mysql> describe stu2; +-------+-------------+------+-----+----------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+----------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(20) | NO | | NULL | | | add | varchar(50) | NO | | 地址不详 | | | score | int(11) | YES | | NULL | | +-------+-------------+------+-----+----------+----------------+ 4 rows in set (0.05 sec) -- 方法二 mysql> desc stu2; +-------+-------------+------+-----+----------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+----------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(20) | NO | | NULL | | | add | varchar(50) | NO | | 地址不详 | | | score | int(11) | YES | | NULL | | +-------+-------------+------+-----+----------+----------------+ 4 rows in set (0.00 sec)1.6.5 复制表语法一:create table 新表 select 字段 from 旧表特点:不能复制父表的键,能够复制父表的数据语法二:create table 新表 like 旧表特点:只能复制表结构,不能复制表数据小结:*表示所有字段1.6.6 删除表语法:drop table [if exists] 表1,表2,… 例题:-- 删除表 mysql> drop table stu4; Query OK, 0 rows affected (0.06 sec) -- 如果表存在就删除 mysql> drop table if exists stu4; Query OK, 0 rows affected, 1 warning (0.00 sec) -- 一次删除多个表 mysql> drop table stu2,stu3; Query OK, 0 rows affected (0.03 sec)1.6.7 修改表语法:alter table 表名 创建初始表mysql> create table stu( -> id int, -> name varchar(20) -> ); Query OK, 0 rows affected (0.00 sec)1、添加字段:alter table 表名add [column] 字段名 数据类型 [位置]mysql> alter table stu add `add` varchar(20); -- 默认添加字段放在最后 Query OK, 0 rows affected (0.05 sec) mysql> alter table stu add sex char(1) after name; -- 在name之后添加sex字段 Query OK, 0 rows affected (0.00 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> alter table stu add age int first; -- age放在最前面 Query OK, 0 rows affected (0.00 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> desc stu; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | age | int(11) | YES | | NULL | | | id | int(11) | YES | | NULL | | | name | varchar(20) | YES | | NULL | | | sex | char(1) | YES | | NULL | | | add | varchar(20) | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ 5 rows in set (0.00 sec)2、删除字段:alter table 表 drop [column] 字段名mysql> alter table stu drop age; -- 删除age字段 Query OK, 0 rows affected (0.00 sec) Records: 0 Duplicates: 0 Warnings: 03、修改字段(改名):alter table 表 change [column] 原字段名 新字段名 数据类型 …-- 将name字段更改为stuname varchar(10) mysql> alter table stu change name stuname varchar(10); Query OK, 0 rows affected (0.02 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> desc stu; +---------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +---------+-------------+------+-----+---------+-------+ | id | int(11) | YES | | NULL | | | stuname | varchar(10) | YES | | NULL | | | sex | char(1) | YES | | NULL | | | add | varchar(20) | YES | | NULL | | +---------+-------------+------+-----+---------+-------+ 4 rows in set (0.00 sec)4、修改字段(不改名):alter table 表 modify 字段名 字段属性…-- 将sex数据类型更改为varchar(20) mysql> alter table stu modify sex varchar(20); Query OK, 0 rows affected (0.00 sec) Records: 0 Duplicates: 0 Warnings: 0 -- 将add字段更改为varchar(20) 默认值是‘地址不详’ mysql> alter table stu modify `add` varchar(20) default '地址不详'; Query OK, 0 rows affected (0.00 sec) Records: 0 Duplicates: 0 Warnings: 05、修改引擎:alter table 表名 engine=引擎名mysql> alter table stu engine=myisam; Query OK, 0 rows affected (0.01 sec) Records: 0 Duplicates: 0 Warnings: 06、修改表名:alter table 表名 rename to 新表名-- 将stu表名改成student mysql> alter table stu rename to student; Query OK, 0 rows affected (0.00 sec)7、将表移动到其他数据库-- 将当前数据库中的student表移动到php74数据库中改名为stu mysql> alter table student rename to php74.stu; Query OK, 0 rows affected (0.00 sec)1.7 数据操作1.7.1 插入数据语法:insert into 表名 (字段名, 字段名,…) values (值1, 值1,…)1、插入所有字段-- 插入所有字段 mysql> insert into stu (id,stuname,sex,`add`) values (1,'tom','男','北京'); Query OK, 1 row affected (0.00 sec) -- 插入部分字段 mysql> insert into stu(id,stuname) values (2,'berry'); -- 插入的字段和表的字段可以顺序不一致。但是插入字段名和插入的值一定要一一对应 mysql> insert into stu(sex,`add`,id,stuname) values ('女','上海',3,'ketty'); Query OK, 1 row affected (0.00 sec) -- 插入字段名可以省略 mysql> insert into stu values(4,'rose','女','重庆'); Query OK, 1 row affected (0.00 sec)小结:1、插入字段名的顺序和数据表中字段名的顺序可以不一致 2、插入值的个数、顺序必须和插入字段名的个数、顺序要一致。 3、如果插入的值的顺序和个数与表字段的顺序个数一致,插入字段可以省略。2、插入默认值和空值mysql> insert into stu values (5,'jake',null,default); Query OK, 1 row affected (0.05 sec)小结:default关键字用来插入默认值,null用来插入空值.3、插入多条数据mysql> insert into stu values (6,'李白','男','四川'),(7,'杜甫','男','湖北'); Query OK, 2 rows affected (0.00 sec) Records: 2 Duplicates: 0 Warnings: 01.7.2 更新数据语法:update 表名 set 字段=值 [where 条件]-- 将berry性别改为女 mysql> update stu set sex='女' where stuname='berry'; Query OK, 1 row affected (0.06 sec) -- 将编号是1号的学生性别改成女,地址改为上海。 mysql> update stu set sex='女',`add`='上海' where id=1; Query OK, 1 row affected (0.00 sec)1.7.3 删除数据语法:delete from 表名 [where 条件]-- 删除1号学生 mysql> delete from stu where id=1; -- 删除名字是berry的学生 mysql> delete from stu where stuname='berry'; Query OK, 1 row affected (0.00 sec) -- 删除所有数据 mysql> delete from stu; Query OK, 5 rows affected (0.00 sec)多学一招:delete from 表和truncate table 表区别?1、delete from 表:遍历表记录,一条一条的删除 2、truncate table:将原表销毁,再创建一个同结构的新表。就清空表而言,这种方法效率高。1.7.4 查询数据语法:select 列名 from 表名例题-- 查询id字段的值 mysql> select id from stu; -- 查询id,stuname字段的值 mysql> select id,stuname from stu;、 -- 查询所有字段的值 mysql> select * from stu;1.7.5 数据传输时使用字符集发现:在插入数据的时候,如果有中文会报错(或者中文无法插入)分析:1、查看客户端发送的编码2、查看服务器接受,返回的编码更改接受客户端指令的编码mysql> set character_set_client=gbk; Query OK, 0 rows affected (0.05 sec)原因:返回编码是utf8,客户端是gbk;测试:成功可以通过set names一次性设置小结:1、设置什么编码取决于客户端的编码2、通过set names 设置编码1.8 补充知识每次执行指令要进入相应的目录中,麻烦,可以通过环境变量简化操作。1.8.1 环境变量配置我的电脑右键——属性——高级将mysql指令目录地址添加到环境变量的Path值中这时候就可以在任意目录下使用mysql指令原理:1、输入指令后,首先在当前目录下查找,如果当前目录下找不到,就到环境变量的Path中查找2、Path中有很多目录,从前往后查找1.8.2 校对集1、概念:在某种字符集下,字符之间的比较关系,比如a和B的大小关系,如果区分大小写a>B,如果不区分大小写则a<B。比如赵钱孙李大小关系,不同的标准关系不一样2、校对集依赖与字符集,不同的字符集的的比较规则不一样,如果字符集更改,校对集也重新定义。3、不同的校对集对同一字符序列比较的结果是不一致的。4、 可以在定义字符集的同时定义校对集、 语法: collate = 校对集例题:定义两个表,相同字符集不同校对集mysql> create table stu1( -> name char(1) -> )charset=utf8 collate=utf8_general_ci; Query OK, 0 rows affected (0.05 sec) mysql> create table stu2( -> name char(1) -> )charset=utf8 collate=utf8_bin; Query OK, 0 rows affected (0.05 sec) mysql> insert into stu1 values ('a'),('B'); Query OK, 2 rows affected (0.00 sec) Records: 2 Duplicates: 0 Warnings: 0 mysql> insert into stu2 values ('a'),('B'); Query OK, 2 rows affected (0.00 sec) Records: 2 Duplicates: 0 Warnings: 0测试:两个表的数据都是有小到大排序mysql> select * from stu1 order by name; -- 不区分大小写 +------+ | name | +------+ | a | | B | +------+ 2 rows in set (0.08 sec) mysql> select * from stu2 order by name; -- 区分大小写 +------+ | name | +------+ | B | | a | +------+ 2 rows in set (0.00 sec) 小结校对集规则:_bin:按二进制编码比较,区别大小写_ci:不区分大小写
2022年10月12日
208 阅读
0 评论
0 点赞
2022-10-12
PHP Smarty模板技术
1.1 目标掌握Smarty模板技术的实际运用;掌握Smarty模板技术的基础配置;掌握常用的smarty内置函数应用;掌握模板变量的使用以及常见的保留变量的使用;了解smarty配置文件的使用规范;掌握Smarty中内置函数:if分支、foreach和section循环的使用掌握Smarty在类中引入实现子类便捷使用的方式1.4 Smarty简介1.4.1 Smarty的引入1、为了分工合作,模板页面中最好不要出现PHP的代码。2、需要将表现和内容相分离1.2.2 Smarty介绍1.5 自定义Smarty1.3.1 演化一:(smarty生成混编文件)在模板中不能出现PHP定界符,标准写法如下:1、html代码<body> {$title} </body>2、PHP代码<?php $title='锄禾'; require './1-demo.html';运行结果不能解析的原因是:PHP不能识别 { 和 }解决:将大括号替换成PHP的定界符代码实现<?php $title='锄禾'; $str=file_get_contents('./index.html'); $str=str_replace('{','<?php echo ',$str); //替换左大括号 $str=str_replace('}',';?>',$str); //替换右大括号 file_put_contents('./index.html.php', $str); //写入混编文件 require './index.html.php'; //包含混编文件运行1.3.2 演化二:(smarty封装)由于每个页面都要替换定界符,所以需要将替换定界符的代码封装起来由于封装在类中,所有访问的方法需要通过面向对象的方式来访问1、创建Smarty.class.php<?php class Smarty{ private $tpl_var=array(); //赋值 public function assign($k,$v){ $this->tpl_var[$k]=$v; } /* *作用:编译模板 *@param $tpl string 模板的路径 */ public function compile($tpl){ $com_file=$tpl.'.php'; //混编文件地址 $str=file_get_contents($tpl); $str=str_replace('{$','<?php echo $this->tpl_var[\'',$str); //替换左大括号 $str=str_replace('}','\'];?>',$str); //替换右大括号 file_put_contents($com_file, $str); //写入混编文件 require $com_file; //包含混编文件 } }2、在index.php<?php require './Smarty.class.php'; $smarty=new Smarty(); $smarty->assign('title','锄禾'); $smarty->compile('./index.html');小结:1、需要将外部的变量赋值到对象的内部2、要通过面向对象的方式访问1.3.3 演化三:(有条件的生成混编文件)混编文件存在并且是最新的就直接包含,否则就重新生成模板文件修改时间<混编文件修改时间 => 混编文件是最新的Smarty类中的代码编译代码如下<?php class Smarty{ private $tpl_var=array(); //赋值 public function assign($k,$v){ $this->tpl_var[$k]=$v; } /* *作用:编译模板 *@param $tpl string 模板的路径 */ public function compile($tpl){ $com_file=$tpl.'.php'; //混编文件地址 //文件存在,并且模板文件修改时间<混编文件修改时间 if(file_exists($com_file) && filemtime($tpl)<filemtime($com_file)) require $com_file; else{ $str=file_get_contents($tpl); $str=str_replace('{$','<?php echo $this->tpl_var[\'',$str); //替换左大括号 $str=str_replace('}','\'];?>',$str); //替换右大括号 file_put_contents($com_file, $str); //写入混编文件 require $com_file; //包含混编文件 } } }小结:生成混编文件的条件1、混编不存在2、模板修改了, 模板文件修改时间>混编文件修改时间,说明模板修改过了。1.3.4 演化四:文件分类存放模板文件:view混编文件:viewcSmarty文件:smarty.class.phpSmarty.class.php代码如下:<?php class Smarty{ public $template_dir='./templates/'; //默认模板目录 public $templatec_dir='./templates_c/'; //默认混编目录 private $tpl_var=array(); //赋值 public function assign($k,$v){ $this->tpl_var[$k]=$v; } /* *作用:编译模板 *@param $tpl string 模板的名字 */ public function compile($tpl){ $tpl_file=$this->template_dir.$tpl; //拼接模板地址 $com_file=$this->templatec_dir.$tpl.'.php'; //混编文件地址 //文件存在,并且模板文件修改时间<混编文件修改时间 if(file_exists($com_file) && filemtime($tpl_file)<filemtime($com_file)) require $com_file; else{ $str=file_get_contents($tpl_file); $str=str_replace('{$','<?php echo $this->tpl_var[\'',$str); //替换左大括号 $str=str_replace('}','\'];?>',$str); //替换右大括号 file_put_contents($com_file, $str); //写入混编文件 require $com_file; //包含混编文件 } } }index.php代码如下<?php require './Smarty/Smarty.class.php'; $smarty=new Smarty(); $smarty->template_dir='./view/'; //更改模板目录 $smarty->templatec_dir='./viewc/'; //更改混编目录 $smarty->assign('title','锄禾'); $smarty->compile('index.html');1.3.5 演化五:封装编译方法编译的方法是smarty的核心方法,核心方法一般是不可以直接调用,需要进行二次封装smarty.class.php<?php class Smarty{ ... public function display($tpl){ require $this->compile($tpl); } /* *作用:编译模板 *@param $tpl string 模板的名字 */ private function compile($tpl){ .. //文件存在,并且模板文件修改时间<混编文件修改时间 if(file_exists($com_file) && filemtime($tpl_file)<filemtime($com_file)) return $com_file; //返回混编地址 else{ $str=file_get_contents($tpl_file); $str=str_replace('{$','<?php echo $this->tpl_var[\'',$str); //替换左大括号 $str=str_replace('}','\'];?>',$str); //替换右大括号 file_put_contents($com_file, $str); //写入混编文件 return $com_file; //返回混编地址 } } }index.php<?php ... $smarty->assign('title','锄禾'); $smarty->display('index.html'); //传递文件名1.6 官方Smarty介绍1.6.1 smarty目录结构到www.smarty.net网站下载最新的smarty版本解压libs目录结构需要掌握的smarty的属性和方法public $left_delimiter = "{"; //左界定 public $right_delimiter = "}"; //右界定 protected $template_dir = array('./templates/'); //默认模板目录 protected $compile_dir = './templates_c/'; //默认混编目录 protected $config_dir = array('./configs/'); //默认配置目录 protected $cache_dir = './cache/'; //默认缓存目录 public function setTemplateDir(){} //设置模板文件夹 public function setConfigDir(){} //设置配置文件夹 public function setCompileDir(){} //设置混编文件夹 public function setCacheDir(){} //设置缓存文件夹练习:以下关于Smarty配置描述正确的是(ABCD) A: 使用left_delimiter属性可以修改Smarty左定界符; B: 使用right_delimiter属性可以修改Smarty右定界符; C: 使用setTemplateDir()方法可以重新指定默认模板工作目录; D: 使用setCompileDir()方法可以重新指定默认编译文件工作目录。 1.6.2 smarty简单的操作1、将libs目录拷贝到站点下,改名为smarty2、创建模板目录templates3、创建混编目录templates_c4、在站点下创建1-demo.php<?php require './Smarty/Smarty.class.php'; $smarty=new Smarty(); $smarty->assign('title','锄禾'); $smarty->left_delimiter='{{'; //更改左界定 $smarty->right_delimiter='}}'; //更改右界定 $smarty->setTemplateDir('./view/'); //设置模板目录 $smarty->setCompileDir('./viewc/'); //设置混编目录 $smarty->display('1-demo.html');在templates下创建demo1.html<body> {{$title}} </body>1.6.3 注释语法:{ }注意:smarty注释在源码中看不见。思考:已知smarty的定界符是{ 和 },那么它的注释是什么?答:{ }1.2 变量smarty中变量有3中,普通变量、配置变量、保留变量1、普通变量普通变量就是我们自己定义的变量方法一:在PHP中定义$smarty->assign('name','tom');方法二:可以在模板定义语法:{assign var='变量名' value='值'} 例如:{assign var='sex' value='男'}简化写法:{$sex='男'}例题:php代码<?php require './Smarty/smarty.class.php'; $smarty=new Smarty(); $smarty->assign('name','tom'); //给变量赋值 $smarty->display('1-demo.html');HTML代码<body> 姓名:{$name} <br> {assign var='age' value=20} 年龄:{$age}<br> {$add='北京'} 地址:{$add} </body>运行结果2、保留变量Smarty中有一个特殊的保留变量(内置变量),类似于PHP中的所有的超全局变量、常量、时间等信息表达式描述{$smarty.get.name}获取get提交的name的值{$smarty.post.name}获取post提交的name的值{$smarty.request.name}获取get和post提交的name的值{$smarty.cookies.name}获取cookie中的name的值{$smarty.session.name}获取session中的name的值{$smarty.const.name}获取常量name{$smarty.server.DOCUMENT_ROOT}获取服务器的虚拟目录地址{$smarty.config.name}获取配置文件中的值{$smarty.now}时间戳{$smarty.ldelim}获取左界定{$smarty.rdelim}获取右界定例题PHP代码<?php require './Smarty/smarty.class.php'; $smarty=new Smarty(); define('name', '常量name'); setcookie('name','cookie的值'); $_SESSION['name']='session的值'; $smarty->display('1-demo.html');HTML代码<body> get提交:{$smarty.get.name}<br> post提交:{$smarty.post.name}<br> request提交:{$smarty.request.name}<br> 常量:{$smarty.const.name}<br> cookie的值:{$smarty.cookies.name}<br> session:{$smarty.session.name}<br> 时间戳:{$smarty.now}<br> 版本号:{$smarty.version}<br> 根目录:{$smarty.server.DOCUMENT_ROOT}<br> 左界定:{$smarty.ldelim}<br> 右界定:{$smarty.rdelim} </body>运行结果3、配置变量从配置文件中获取变量值,配置文件默认的文件夹是configs1、在站点下创建配置文件夹configs2、在configs目录下创建smarty.conf文件color='#FF0000'; size='15px';3、PHP页面<?php require './Smarty/smarty.class.php'; $smarty=new Smarty(); $smarty->display('1-demo.html');4、HTML页面{config_load file='smarty.conf'} <!--引入配置文件--> <style> body{ color:{#color#}; font-size: {$smarty.config.size} } </style>小结:1、要使用配置文件中的值,首先必须引入配置文件,通过{config_load}标签引入2、获取配置文件中的值的方法有两种 第一:{#变量名#} 第二:{$smarty.config.变量名}多学一招:配置文件中的节在配置文件中,‘[ ]’表示配置文件的段落例题:配置文件color=#FF0000 size=30px [spring] # 配置文件中的段落 color=#009900; size=20px; [winter] color=#000000; size=5px;注意:1、全局的一定要写在节的前面2、配置文件中[]表示节3、配置文件中的注释是 #HTML页面{config_load file='smarty.conf' section='winter'} -- 通过section引入配置文件中的段落 <style> body{ color:{#color#}; font-size: {$smarty.config.size} } </style>1.3 运算符smary中的运算符是PHP是一样的。除此以外,smarty还支持如下的运算符。运算符描述eqequal 相等neqnot equal 不等于gtgreater than 大于ltless than 小于lteless than or equal 小于等于gtegreat than or equal 大于等于is even是偶数is odd是奇数is not even不是偶数is not odd不是奇数not非mod求模取余div by被整除is [not] div by能否被某数整除,例如:{if $smarty.get.age is div by 3}...{/if}is [not] even by商的结果是否为偶数is [not] odd by商的结果是否为奇数1.4 判断语法:{if 条件} {elseif 条件} {else} {/if}例题:php代码<?php require './Smarty/smarty.class.php'; $smarty=new Smarty(); $smarty->display('1-demo.html');html代码<body> {if is_numeric($smarty.get.score)} {#判断是否是数字#} {if $smarty.get.score gte 90} A {elseif $smarty.get.score gte 80} B {else} C {/if} {else} 不是数字 {/if} <hr> {if $smarty.get.score is even} 是偶数 {elseif $smarty.get.score is odd} 是奇数 {/if} </body>运行结果小结:在判断中是可以使用PHP的函数的1.5 数组smarty中访问数组的方式有两种数组[下标] 数组.下标PHP代码<?php require './Smarty/smarty.class.php'; $smarty=new Smarty(); $stu=array('tom','berry'); //索引数组 $emp=array('name'=>'rose','sex'=>'女'); //关联数组 $goods=array( array('name'=>'手机','price'=>22), array('name'=>'钢笔','price'=>10) ); $smarty->assign('stu',$stu); $smarty->assign('emp',$emp); $smarty->assign('goods',$goods); $smarty->display('2-demo.html');HTML代码<body> 学生:{$stu[0]}-{$stu.1} <br> 雇员:{$emp['name']}-{$emp.sex}<br> 商品: <ul> <li>{$goods[0]['name']}</li> <li>{$goods[0].price}</li> <li>{$goods.1['name']}</li> <li>{$goods.1.price}</li> </ul> </body>运行结果1.6 循环smarty中支持的循环有:{for}、{while}、{foreach}、{section}。对于开发来说用的最多就是{foreach}循环1.6.1 for语法:{for 初始值 to 结束值 [step 步长]} {/for} 默认步长是1例题<body> {for $i=1 to 5} {$i}:锄禾日当午<br> {/for} <hr> {for $i=1 to 5 step 2} {$i}:锄禾日当午<br> {/for} </body>运行结果1.6.2 while语法{while 条件} {/while}例题(输出5句):<body> {$i=1} {while $i<=5} {$i++}:锄禾日当午<br> {/while} </body>1.6.3 foreach既能遍历关联数组也能遍历索引数组语法:{foreach 数组 as $k=>$v} {foreachelse} 没有数组输出 {/foreach}foreach的属性@index:从0开始的索引 @iteration:从1开始的编号 @first:是否是第一个元素 @last:是否是最后一个元素PHP代码<?php require './Smarty/smarty.class.php'; $smarty=new Smarty(); $smarty->assign('stu',array('first'=>'tom','second'=>'berry','third'=>'ketty','forth'=>'rose')); $smarty->display('3-demo.html');html代码<table border='1' bordercolor='#000' width='780'> <tr> <th>是否是第一个元素</th> <th>索引</th> <th>编号</th> <th>键</th> <th>值</th> <th>是否是最后一个元素</th> </tr> {foreach $stu as $k=>$v} <tr> <td>{$v@first}</td> <td>{$v@index}</td> <td>{$v@iteration}</td> <td>{$k}</td> <td>{$v}</td> <td>{$v@last}</td> </tr> {foreachelse} 没有输出 {/foreach} </table>运行结果1.6.4 sectionsection不支持关联数组,只能遍历索引数组语法:{section name=自定义名字 loop=数组} {/section}例题:php<?php require './Smarty/smarty.class.php'; $smarty=new Smarty(); $smarty->assign('stu',array('tom','berry')); $smarty->display('4-demo.html');html代码<table border='1' bordercolor='#000' width='780'> <tr> <th>是否是第一个元素</th> <th>索引</th> <th>编号</th> <th>值</th> <th>是否是最后一个元素</th> </tr> {section name=s loop=$stu} <tr> <td>{$smarty.section.s.first}</td> <td>{$smarty.section.s.index}</td> <td>{$smarty.section.s.iteration}</td> <td>{$stu[s]}</td> <td>{$smarty.section.s.last}</td> </tr> {sectionelse} 没有输出 {/section} </table>1.7 函数函数有两种,自定义函数和内置函数smarty的内置函数就是封装的PHP的关键字1.8 变量修饰器1.8.1 变量修饰器变量修饰器的本质就是PHP函数,用来转换数据php代码<?php require './Smarty/smarty.class.php'; $smarty=new Smarty(); $smarty->display('5-demo.html');html代码<body> 转成大写:{'abc'|upper} <br> 转成小写:{'ABC'|lower} <br> 默认值:{$add|default:'地址不详'}<br> 去除标签:{'<b>你好吗</b>'|strip_tags}<br> 实体转换:{'<b>你好吗</b>'|escape}<br> 日期:{$smarty.now|date_format:'%Y-%m-%d %H:%M:%S'} 多个管道连续使用:{'<b>boy</b>'|strip_tags|upper}<br> </body>运行结果注意:1、将PHP的关键字或函数封装成标签称为函数,将PHP关键字封装成smarty关键字称为修饰器。内部的本质都是、PHP函数或PHP关键字。2、|称为管道运算符,将前面的参数传递后后面的修饰器使用1.8.2 自定义变量修饰器变量修饰器存放在plugins目录中规则:文件的命名规则:modifier.变量修饰器名称.php文件内方法命名规则:smarty_modifier_变量修饰器名称(形参...){}例题1、在plugins目录中创建modifier.cal.php页面<?php function smarty_modifier_cal($num1,$num2,$num3){ return $num1+$num2+$num3; }2、在模板中调用{10|cal:20:30} 10作为第一个参数传递 参数之间用冒号分隔1.9 避免Smarty解析smarty的定界符和css、js中的大括号产生冲突的时候,css、js中的大括号不要被smarty解析方法一:更换定界符方法二:左大括号后面添加空白字符方法三:{literal} {/literal}smarty不解析{literal} {/literal}中的内容<style> {literal} body{color: #FF0000;} {/literal} </style>1.10 缓存缓存:页面缓存、空间缓存、数据缓存。smarty中的缓存就是页面缓存smarty的缓存是页面缓存。1.10. 1 开启缓存$smarty->caching=true|1; //开启缓存1.10.2 缓存的更新方法一:删除缓存,系统会重新生成新的缓存文件方法二:更新了模板文件,配置文件,缓存自动更新方法三:过了缓存的生命周期,默认是3600秒方法四:强制更新PHP代码<?php require './Smarty/smarty.class.php'; $smarty=new Smarty(); $smarty->caching=true; //开启缓存 if(date('H')>=9) $smarty->force_cache=true; //强制更新缓存 $smarty->display('6-demo.html');1.10.3 缓存的生命周期$smarty->cache_lifetime=-1 | 0 | N -1:永远不过期 0:立即过期 N:有效期是N秒,默认是3600秒PHP代码$smarty->cache_lifetime=3; //缓存的生命周期1.10.4 局部不缓存局部不缓存有两种方法1、变量不缓存 {$变量名 nocache} 2、整个块不缓存 {nocache} {/nocache}代码不缓存:{$smarty.now nocache} <br> 不缓存:{nocache} {$smarty.now}<br> {/nocache}1.10.5 缓存分页通过$smarty->display(模板,识别id)。通过识别id来缓存分页、集合PHP页面<?php require './Smarty/smarty.class.php'; $smarty=new Smarty(); $smarty->caching=1; $smarty->display('7-demo.html',$_GET['pageno']);html页面<body> 这是第{$smarty.get.pageno}页 </body>运行结果1.10.6 缓存集合每个组合都会产生缓存PHP代码<?php require './Smarty/smarty.class.php'; $smarty=new Smarty(); $smarty->caching=1; $color=$_GET['color']; $size=$_GET['size']; $smarty->display('7-demo.html',"$color|$size");HTML代码<body> 颜色:{$smarty.get.color}<br> 大小:{$smarty.get.size} </body>运行结果1.10.7 清除缓存$smarty->clearCache(模板,[识别id]) $smarty->clearAllCache(); //清除所有缓存代码<?php require './Smarty/smarty.class.php'; $smarty=new Smarty(); //$smarty->clearCache('7-demo.html',1); //$smarty->clearCache('7-demo.html','red|10'); //$smarty->clearCache('7-demo.html'); $smarty->clearAllCache(); //清除所有缓存1.11 将smarty集成到项目中1、将smarty拷贝到Lib目录下2、实现smarty类的自动加载 private static function initAutoLoad(){ spl_autoload_register(function($class_name){ //Smarty类存储不规则,所以将类名和地址做一个映射 $map=array( 'Smarty' => LIB_PATH.'Smarty'.DS.'Smarty.class.php' ); ... elseif(isset($map[$class_name])) $path=$map[$class_name]; else //控制器 $path=__URL__.$class_name.'.class.php'; if(file_exists($path) && is_file($path)) require $path; }); }3、创建混编目录,并且定义混编目录地址private static function initRoutes(){ ... define('__VIEW__',VIEW_PATH.$p.DS); //当前视图的目录地址 define('__VIEWC__', APP_PATH.'Viewc'.DS.$p.DS); //混编目录 }4、由于前后台都要启动模板,所以应该在基础控制器中实例化smarty<?php //基础控制器 namespace Core; class Controller{ protected $smarty; use \Traits\Jump; public function __construct() { $this->initSession(); $this->initSmarty(); } //初始化session private function initSession(){ new \Lib\Session(); } //初始化Smarty private function initSmarty(){ $this->smarty=new \Smarty(); $this->smarty->setTemplateDir(__VIEW__); //设置模板目录 $this->smarty->setCompileDir(__VIEWC__); //设置混编目录 } }5、在控制器中使用smartyclass ProductsController extends BaseController{ //获取商品列表 public function listAction() { //实例化模型 $model=new \Model\ProductsModel(); $list=$model->select(); //加载视图 //require __VIEW__.'products_list.html'; $this->smarty->assign('list',$list); $this->smarty->display('products_list.html'); }6、在模板中更改如下:{foreach $list as $rows} <tr> <td>{$rows['proID']}</td> <td>{$rows['proname']}</td> <td>{$rows['proprice']}</td> <td><a href="index.php?p=Admin&c=Products&a=edit&proid={$rows['proID']}">修改</a></td> <td><a href="javascript:void(0)" onclick="if(confirm('确定要删除吗')){ location.href='index.php?p=Admin&c=Products&a=del&proid={$rows['proID']}'}">删除</a></td> </tr> {/foreach}
2022年10月12日
213 阅读
0 评论
1 点赞
2022-10-12
PHP 类封装文件上传
1.1 目标更好的理解类的封装特性;理解代码根据业务和功能的分类管理思想;理解公共控制器的作用,掌握公共控制器的封装;掌握PHP面向对象中继承的核心应用;1.2 文件上传1.2.1 封装文件上传类1、在Lib目录下创建Upload.class.php<?php namespace Lib; class Upload{ private $path; //上传的路径 private $size; //上传的大小 private $type; //允许上传的类型 private $error; //保存错误信息 public function __construct($path,$size,$type) { $this->path=$path; $this->size=$size; $this->type=$type; } //返回错误信息 public function getError(){ return $this->error; } /* * 文件上传 * @param $files array $_FILES[] * @return bool|string 成功返回文件路径,失败返回false */ public function uploadOne($files){ if($this->checkError($files)){ //没有错误就上传 $foldername=date('Y-m-d'); //文件夹名称 $folderpath= $this->path.$foldername; //文件夹路径 if(!is_dir($folderpath)) mkdir($folderpath); $filename=uniqid('',true).strrchr($files['name'],'.');//文件名 $filepath="$folderpath/$filename"; //文件路径 if(move_uploaded_file($files['tmp_name'],$filepath)) return "{$foldername}/{$filename}"; else{ $this->error='上传失败<br>'; return false; } } return false; } //验证上传是否有误 private function checkError($files){ //1、验证错误号 if($files['error']!=0){ switch($files['error']) { case 1: $this->error='文件大小超过了php.ini中允许的最大值,最大值是:'.ini_get('upload_max_filesize'); return false; case 2: $this->error='文件大小超过了表单允许的最大值'; return false; case 3: $this->error='只有部分文件上传'; return false; case 4: $this->error='没有文件上传'; return false; case 6: $this->error='找不到临时文件'; return false; case 7: $this->error='文件写入失败'; return false; default: $this->error= '未知错误'; return false; } } //2、验证格式 $info=finfo_open(FILEINFO_MIME_TYPE); $mime=finfo_file($info,$files['tmp_name']); if(!in_array($mime, $this->type)){ $this->error='只能上传'.implode(',', $this->type).'格式'; return false; } //3、验证大小 if($files['size']> $this->size){ $this->error='文件大小不能超过'.number_format($this->size/1024,1).'K'; return false; } //4、验证是否是http上传 if(!is_uploaded_file($files['tmp_name'])){ $this->error='文件不是HTTP POST上传的<br>'; return false; } return true; } }1.2.2 封装缩略图类在Lib目录下创建Image.class.php<?php namespace Lib; class Image{ /* * 制作缩略图 * @param $src_path 源图的路径 */ public function thumb($src_path,$prefix='small_',$w=200,$h=200){ $dst_img=imagecreatetruecolor($w,$h); //目标图 $src_img=imagecreatefromjpeg($src_path); //源图 $src_w=imagesx($src_img); $src_h=imagesy($src_img); imagecopyresampled($dst_img,$src_img,0,0,0,0,$w,$h,$src_w,$src_h); $filename=basename($src_path); //文件名 $foldername=substr(dirname($src_path),-10); //目录名 $save_path= dirname($src_path).'/'.$prefix.$filename; imagejpeg($dst_img,$save_path); return "{$foldername}/{$prefix}{$filename}"; } }1.2.3 实现文件上传1、register.html <form action="" method="post" enctype="multipart/form-data"> ...2、更改注册控制器public function registerAction(){ //第二步:执行注册逻辑 if(!empty($_POST)){ //文件上传 $path=$GLOBALS['config']['app']['path']; $size=$GLOBALS['config']['app']['size']; $type=$GLOBALS['config']['app']['type']; $upload=new \Lib\Upload($path, $size, $type); if($filepath=$upload->uploadOne($_FILES['face'])){ //生成缩略图 $image=new \Lib\Image(); $data['user_face']=$image->thumb($path.$filepath,'s1_'); }else{ $this->error('index.php?p=Admin&c=Login&a=register', $upload->getError()); } //文件上传结束 ...3、配置文件 'app' =>array( 'path' => './Public/Uploads/', 'size' => 1234567, 'type' => ['image/png','image/jpeg','image/gif'],1.3 登录模块1.3.1 记住密码登录成功后,如果需要记录用户名和密码,则将用户名和密码记录在cookie中打开登录页面的时候,获取cookie的值在视图页面(login.html)页面显示cookie的信息<input type="text" class="input" name="username" placeholder="登录账号" value="<?=$name?>" /> ... <input type="password" class="input" name="password" placeholder="登录密码" value="<?=$pwd?>" />运行结果1.3.2 安全退出退出:退出的时候不销毁令牌安全退出:退出的时候销毁了令牌top.html<a class="button button-little bg-yellow" href="index.php?p=Admin&c=Login&a=logout" target="_top">安全退出</a> _top:表示在最顶端的窗口中打开控制器(LoginController)public function logoutAction(){ session_destroy(); header('location:index.php?p=Admin&c=Login&a=login'); }
2022年10月12日
223 阅读
0 评论
0 点赞
1
...
14
15
16
17