第一天 HTML
第一节 HTML简介
-
文件名后缀为.html或.htm
第二节 HTML基本标签
2.1 结构标签
<html><html>:根标签 <head></head>:头标签 <title></title>:页面的标题 <body></body>:主体标签:网页内容
2.2 排版标签
1.注释标签:<!--注释--> 2.换行标签:<br/> 3.段落标签:<p>文本文字</p> 特点:段与段之间有行高 属性:align对齐方式 (left:左对齐 center:居中 right:右对齐) 4.水平线标签:<hr/> 属性: width:水平线的长度(两种:第一种:像素表示;第二种,百分比表示) size: 水平线的粗细 (像素表示,例如:10px) color:水平线的颜色 align:水平线的对齐方式(left:左对齐 center:居中 right:右对齐)
2.3 标题标签
<h1></h1>—-<h6></h6> 随着数字增大文字逐渐变小,字体是加粗的,内置字号,默认占据一行;
2.4 容器标签
<div></div>:块级标签,独占一行,换行 <span></span>:行级标签,所有内容都在同一行 作用: <div></div>:主要是结合css页面分块布局 <span></span>:进行友好提示信息
2.5 列表标签
无序列表标签: <ul></ul> 属性:type :三个值,分别为 circle(空心圆) ,disc(默认,实心圆),square(黑色方块) 列表项:<li></li> 示例如下: <ul type="square">无序列表 <li>苹果</li> <li>香蕉</li> <li>橘子</li> </ul> 有序列表标签:<ol></ol> 属性:type:1、A、a、I、i(数字、字母、罗马数字) 列表项: <li></li> 示例如下: <ol type="I">有序列表 <li>苹果</li> <li>香蕉</li> <li>橘子</li> </ol>
-
定义列表
dl (defination list) 定义列表
dt (defination title) 定义标题
dd (defination description) 定义描述
代码示例
定义列表 <dl> <dt>苹果</dt> <dd>苹果是一种水果,富含维生素C,美容养颜,吃了长寿....</dd> </dl>
2.6 图片标签
<img/> 独立标签 属性: src:图片地址: 相对路径 (同一个网站) 绝对路径 (不同网站) width:宽度 height:高度 border:边框 align:对齐方式,代表图片与相邻的文本的相当位置(有三个属性值:top middle bottom) alt:图片的文字说明 title:图片的悬停显示 hspace 和 vspace 设定图片边沿上下左右空白,以免文字或其它图片过于贴近
2.7 链接标签
<a>文本或图片</a> 属性: href:跳转页面的地址(跳转到外网需要添加协议) target:_self(自己) _blank(新页面,之前页面存在) _parent _top 默认_self _search相等于给页面起一个名字,如果再次打开时,如果页面存在,则不再打开新的页面。可以是任意名字。 name:名称,锚点(回到锚点: 顶部,底部,中间),在访问锚点的书写格式:#name的值
2.8 表格标签
-
table、tr、td、 th
-
colspan 属性,用法先扣再填
-
rowspan属性
2.9 文本格式化标签
<b> 定义粗体文本。 <big> 定义大号字。 <em> 定义着重文字。 <i> 定义斜体字。 <small> 定义小号字。 <strong> 定义加重语气。 <sub> 定义下标字。 <sup> 定义上标字。 <ins> 定义插入字。 <del> 定义删除字。
第三节 HTML表单标签
3.1form标签
常用属性:action:表示动作,值为服务器的地址,把表单的数据提交到该地址上处理 method:请求方式:get 和post enctype:表示是表单提交的类型 默认值:application/x-www-form-urlencoded 普通表单 multipart/form-data 多部分表单(一般用于文件上传) text/plain 普通文本 get: 1.数据存在地址栏中,请求参数都在地址后拼接 path?name=张三&password=123456 2.不安全 3.效率高 4.get请求大小有限制,不同浏览器有不同,但是大约是2KB使用情况:一般情况用于查询数据。 post: 1.地址栏没有数据:请求参数单独处理。 2.安全可靠 3.效率低 4.post请求大小理论上无限。使用情况:一般用于插入修改等操作 put deleteheader
3.2 input标签
type: 以下为type可能要取的值: 1.1 text 文本框 输入内容 1.2 password 密码框 密文或者掩码 1.3 radio 表示是单选,name必须一致;value:提交给服务器的数据 表示同一组中只能选中一个( checked ="checked" 表示选中) 1.4 checkbox 表示多选 ,name必须一致, 表示同一组中可以选多个,返回值是个数组( checked ="checked" 表示选中) 1.5 file :表示上传控件 以上具有输入性质的必须要有name属性,初始开始写value表示是默认值(以后获取输入框的内容要根据name来取) 以下按钮不具有输入性质,不需要name属性,但是按钮上的文字提示使用value属性 1.6 submit 提交 1.7 reset 重置 1.9 image 图片提交按钮 1.10 button 普通按钮 1.11 hidden 表示隐藏域,该框的内容服务器需要,但是不想让用户知道(不想清楚的显示在界面上) 1.12 email 表示邮箱格式的数据 name属性:表单元素名字,只有name属性才能提交给服务器。 value属性:提交给服务器的数据 placeholder:提示信息 高级属性: disabled:禁用 readonly:只读
3.3 select元素
<select name="city"> <!--select标签添加该属性multiple="multiple"表示多选 、size表示显示的个数--> <!--option表示下拉列表项--> <option value="北京">北京</option> <!--selected="selected"表示选中该项--> <option value="上海" selected="selected">上海</option> <option value="广州">广州</option> <option value="杭州">杭州</option> </select>
3.4 textarea 元素
<textarea cols="100" rows="5"> 表示5行100列的区域可以输入内容,该元素没有value属性
3.5 示例综合代码--注册
<form action="" method="get"> <table align="center"> <caption> <h1>注册</h1></caption> <tr> <td align="right">用户名:</td> <td><input type="text" name="username" value="bluesky" /></td> </tr> <tr> <td align="right">密码:</td> <td><input type="password" name="password" /></td> </tr> <tr> <td align="right">确认密码:</td> <td><input type="password" name="confirmpwd" /></td> </tr> <tr> <td align="right">性别:</td> <td> <input type="radio" name="sex" value="男" />男 <input type="radio" name="sex" value="女" checked="checked" />女 </td> </tr> <tr> <td align="right">爱好:</td> <td> <input type="checkbox" name="hobby" value="篮球" checked="checked" />篮球 <input type="checkbox" name="hobby" value="足球 " />足球 <input type="checkbox" name="hobby" value="乒乓球 " />乒乓球 <input type="checkbox" name="hobby" value="羽毛球 " />羽毛球 </td> </tr> </tr> <tr> <td align="right">上传头像:</td> <td> <input type="file" name="upload" /> </td> </tr> </tr> <tr> <td align="right">居住地:</td> <td> <select name="city"> <option value="北京">北京</option> <option value="上海" selected="selected">上海</option> <option value="广州">广州</option> <option value="杭州">杭州</option> </select> </td> </tr> </tr> <tr> <td align="right">个人介绍:</td> <td> <textarea cols="100" rows="5"> </textarea> </td> </tr> </tr> <tr> <td></td> <td align="center"> <input type="submit" value="注册" /> <input type="reset" value="重置" /> </td> </tr> </table> </form>
第五节 HTML框架标签
5.1 frameset
示例代码
-
top.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> </head> <body bgcolor="red"> <h1>HTML的框架标签</h1> </body> </html>
-
left.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> </head> <body bgcolor="#FFA600"> <a href="http://www.qfedu.com">千锋官网</a><br/> <a href="http://www.qfedu.com">JAVA官网</a><br/> <a href="http://www.qfedu.com">JAVA在线</a><br/> </body> </html>
-
right.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body bgcolor="#00FFFF"> <h1>正文内容</h1> </body> </html>
-
content.html
<!--1.框架标签不能和body同时出现 2.frameset: border去除框架标签的框 ,示例:border="0" border="10px" bordercolor="yellow" 3.frame框大小不变:两种情况: 第一种:border ="0" 第二种: noresize="noresize" 不改变大小 备注:scrolling是否显示滚动条 yes 显示 no 不显示 auto 如果内容高度超过屏幕高度直接显示滚动, 4. frame 是框,内容使用src来填充, 定位显示到指定位置: 使用name属性 例如: 点击left.html的标签跳转内容显示在right.html 1.给right.html的frame添加name属性,方便定位。 2.在left.html中使用target目标定位,根据name名查找 --> <frameset rows="200,*" border="10px" bordercolor="yellow"> <frame src="top.html" scrolling="yes" noresize="noresize" /> <frameset cols="200,*"> <frame src="left.html" scrolling="yes" noresize="noresize" /> <frame src="right.html" name="content" scrolling="yes" /> </frameset> </frameset>
第六节 HTML的其它标签和特殊字符
6.1其他标签
<!--该网页的关键字--> <meta name="keywords" content="keyword1,keyword2,keyword3"> <!--该网页的描述--> <meta name="description" content="this is my page"> <!--该网页的编码--> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> html4.01 <!--页面自动跳转,2秒后跳转到百度--> <meta http-equiv="refresh" content="2;URL=https://www.baidu.com"> <!--该网页的编码--> <meta charset="UTF-8"> html5 <!-- href:引入css文件的地址--> <link rel="stylesheet" type="text/css" href="./styles.css"> <!--src:js的文件地址--> <script type="text/javascript" src=""></script>
6.2特殊字符
< 小于号 > 大于号 & 与字符 " 引号 ® 己注册 © 版权 ™ 商标 空格  制表符
小结
基本标签:
(1)结构标签 html head title body
(2)排版p br hr
(3)标题 h1-h6
(4)容器 div span
(5)列表 ul ol dl
(6) 表格 table
(7) 图片 img
(8)超链接 a
表单内容
form
action 表单提交的服务器地址
method 提交方式
enctype 编码类型
表单元素
input
type: text password radio checkbox button submit reset image file hidden email
select
textarea
框架标签
frameset
rows
cols
frame
其他标签
meta
特殊字符
第二天 CSS层叠样式表
第一节 CSS简介
-
概念
CSS :层叠样式表(英文全称:Cascading Style Sheets)是一种用来表现HTML(标准通用标记语言的一个应用)或XML(标准通用标记语言的一个子集)等文件样式的计算机语言。CSS不仅可以静态地修饰网页,还可以配合各种脚本语言动态地对网页各元素进行格式化。 多个样式可以层层覆盖叠加,如果不同的css样式对同一个html标签进行修饰,样式有冲突的,应用优先级高的,不冲突的样式规则共同作用。
-
特点
1 丰富的样式定义 CSS提供了丰富的文档样式外观,以及设置文本和背景属性的能力;允许为任何元素创建边框,以及元素边框与其他元素间的距离,以及元素边框与元素内容间的距离;允许随意改变文本的大小写方式、修饰方式以及其他页面效果。
2 易于使用和修改 CSS可以将样式定义在HTML元素的style属性中,也可以将其定义在HTML文档的header部分,也可以将样式声明在一个专门的CSS文件中,以供HTML页面引用。总之,CSS样式表可以将所有的样式声明统一存放,进行统一管理。 另外,可以将相同样式的元素进行归类,使用同一个样式进行定义,也可以将某个样式应用到所有同名的HTML标签中,也可以将一个CSS样式指定到某个页面元素中。如果要修改样式,我们只需要在样式列表中找到相应的样式声明进行修改。
3 多页面应用 CSS样式表可以单独存放在一个CSS文件中,这样我们就可以在多个页面中使用同一个CSS样式表。CSS样式表理论上不属于任何页面文件,在任何页面文件中都可以将其引用。这样就可以实现多个页面风格的统一。
4 层叠 简单的说,层叠就是对一个元素多次设置同一个样式,这将使用最后一次设置的属性值。例如对一个站点中的多个页面使用了同一套CSS样式表,而某些页面中的某些元素想使用其他样式,就可以针对这些样式单独定义一个样式表应用到页面中。这些后来定义的样式将对前面的样式设置进行重写,在浏览器中看到的将是最后面设置的样式效果。
5 页面压缩 在使用HTML定义页面效果的网站中,往往需要大量或重复的表格和font元素形成各种规格的文字样式,这样做的后果就是会产生大量的HTML标签,从而使页面文件的大小增加。而将样式的声明单独放到CSS样式表中,可以大大的减小页面的体积,这样在加载页面时使用的时间也会大大的减少。另外,CSS样式表的复用更大程序的缩减了页面的体积,减少下载的时间
第二节 CSS使用方式
-
内联方式
把CSS样式嵌入到html标签当中,类似属性的用法,示例如下:
<div style="color:blue;font-size:50px">This is my HTML page. </div>
好处:可以单独设置某个元素样式,缺点:不利于样式重用
-
内部方式
在head标签中使用style标签引入css,示例如下: <style type=“text/css”> //告诉浏览器使用css解析器去解析 div {color:red; font-size:50px} </style> 好处:可以控制页面中多个元素样式,缺点:只能一个页面使用
-
外部方式
将css样式抽成一个单独文件,谁用谁就引用,好处:多个页面可以同时使用。 示例如下: 单独文件div.css: 内容示例:div{color:green;font-size:50px} 引用语句写在head标签内部, 链接式: <link rel="stylesheet" type="text/css" href=“div.css"></link> rel:代表当前页面与href所指定文档的关系 type:文件类型,告诉浏览器使用css解析器去解析 href:css文件地址 导入式: <style type="text/css"> @import url("div.css") </style> 该内容放在head标签中 备注:link和@import区别: 1.link所有浏览器都支持,@import某些版本低的IE不支持 2.@import是等待html加载完成才加载,link解析到这个语句,就加载 3.@import不支持js动态修改
-
优先级 内联样式>内部样式>外部样式,就近原则
第三节 CSS选择器
3.1 基本选择器
-
标签选择器
-
id选择器
-
class选择器
3.2 属性选择器
格式为:html标签[属性='属性值']{css属性:css属性值;} 或者html标签[属性]{css属性:css属性值;}, 具体示例如下: body内容: <form name="login" action="#" method="get"> <font size="3">用户名:<font> <input type=“text" name="username" value="zhangsan" /> </br> 密码: <input type="password" name="password" value="123456" /> </br> <input type="submit" value="登录"></input> </form> head中书写: <style type="text/css"> input[type='text'] { background-color: pink } input[type='password'] { background-color: yellow } font[size] { color: green } a[href] { color: blue; } </style>
3.3 伪元素选择器
语法: 静止状态 a:link{css属性} 悬浮状态 a:hover{css属性} 触发状态 a:active{css属性} 完成状态 a:visited{css属性} 具体示例如下: <a href="https://hao.360.cn/">点我吧</a> <style type="text/css"> <!--静止状态 --> a:link {color: red;} <!--悬浮状态 --> a:hover {color: green;} <!--触发状态 --> a:active {color: yellow;} <!--完成状态 --> a:visited {color: blue;} </style>
3.4 层级选择器
后代选择器
div p{...} 表示div中的p标签,所有的p,后代
div span{....} 表示div中的span标签,包括所有的span,后代
子代选择器
div>span{....} 表示 div中有一个span, span是子代
相邻兄弟 +
通用兄弟 ~
<div id="div1"> <div class="div11"> <span>span1-1</span> </div> <div class="div12"> <span>span1-2</span> </div> </div> <div class="div2"> <div id="div22"> <span>span2-1</span> </div> <div id="div23"> <span>span2-2</span> </div> </div> <style type="text/css"> #div1 .div11{color:red;} #div1 .div12{color:purple;} .div2 #div22{color:green;} .div2 #div23{color:blue;} </style>
3.5 其他选择器
-
全局选择器
-
群组选择器
第四节 CSS属性
-
文字属性
font-weight 属性设置文本的粗细。关键字 100 ~ 900 为字体指定了 9 级加粗度。 100 对应最细的字体变形,900 对应最粗的字体变形。 数字 400 等价于 normal,而 700 等价于 bold。
斜体(italic)是对每个字母的结构有一些小改动,来反映变化的外观。 倾斜(oblique)文本则是正常竖直文本的一个倾斜版本。
简写: font: italic bold 30px "幼圆","黑体"; /style weight size family swsf/
-
文本属性
text-indent:缩进元素中文本的首行,取值类型如下: text-indent:5em;表示此段落第一行缩进5个字符的宽度 text-indent:20%:表示此段落第一行缩进父容器宽度的百分之二十
-
背景属性
/简写 没有顺序/ background: red center no-repeat url(img/003.jpg);
-
列表属性
list-style-type:decimal;改变列表的标志类型 list-style-image: url("images/dog.gif");用图像表示标志 list-style-position: inside;确定标志出现在列表项内容之外还是内容内部 简写 list-style: decimal url(img/001.png) inside; 去掉样式: list-style:none; list-style-type:none;
-
尺寸显示轮廓属性
width:设置元素的宽度 height:设置元素的高度 显示属性(display) display: none 不显示 block:块级显示 inline:行级显示 inline-block:行级块 轮廓(outline) 绘制于元素周围的一条线,位于边框边缘的外围,可起到突出元素的作用。常用属性: outline-style:solid(实线)/dotted(虚线)/dashed(虚线,虚线的每段较长)/double(框为空心);设置轮廓的样outline-color:red;设置轮廓的颜色 outline-width:10px设置轮廓的宽度
-
浮动属性
浮动:简单理解---飘起来了
clear 属性
规定元素的哪一侧不允许其他浮动元素。
-
定位属性
postion: static(默认) | relative| absolute| fixed
第五节 CSS盒子模型
5.1 边框属性
border-style:边框样式,值有以下情况: solid:实线 double:空心线 dashed:虚线组成的边框 dotted:圆点组成的边框 border-color:边框颜色 border-width:边框宽度 简写 border: 1px solid red;
5.2 外边距属性
margin:外间距,边框和边框外层的元素的距离 margin:四个方向的距离(top right bottom left)
5.3 内边距属性
padding:内间距,元素内容和边框之间的距离((top right bottom left))
-
div水平居中显示
margin: 0 auto; /*0 上下 0 左右 auto*/
-
div垂直居中显示
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> #box{ height: 300px; background-color:#FFC0CB; /*弹性盒子*/ display: flex; /*垂直对齐*/ align-items: center; /*水平对齐*/ justify-content: center; } #div1,#div2{ width: 100px; height: 100px; } #div1{ background-color: #6495ED; } #div2{ background-color: #7FFFD4; } </style> </head> <body> <div id="box"> <div id="div1">第一个div</div> <div id="div2">第二个div</div> </div> </body> </html> 注意,设为 Flex 布局以后,子元素的float、clear和vertical-align属性将失效。
第六节 CSS3扩展属性
6.1 border-radius
圆角属性
6.2 box-shadow
用于向方框添加阴影
6.3 background-size
属性规定背景图片的尺寸
6.4 background-image
为指定元素使用多个背景图像
6.5 text-shadow
可向文本应用阴影
第三天 JS基础使用
第一节JS概述
-
简介
JavaScript(LiveScript)一种解释性脚本语言,是一种动态类型、弱类型、基于原型继承的语言,内置支持类型。它的解释器被称为JavaScript引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在HTML(标准通用标记语言下的一个应用)网页上使用,用来给HTML网页增加动态功能。
第二节 JS基本语法
2.1 数据类型
-
基本(原始)类型
number、string、boolean、undefined、null五种
-
引用(对象)类型
Number String Boolean Object Array
2.2 JavaScript的三种使用方式
-
第一种方式:在<script>标签中,script可以放在网页中任何位置。
<script type="text/javascript"> var num=10; var d=new Date(); document.write(num); </script>
-
第二种方式:使用外部JavaScript文件,把js代码放入单独的文件中 ,这个文件的扩展名.js
<script type="text/javascript" src="js/myjs.js"></script>
-
第三种方式: 放在标签中的事件属性中,常见事件 ,onclick
<input type="button" value="你点我啊" οnclick="alert('你点我干嘛')" />
2.3 JS运算符
-
== 自动转型比较数值
-
===直接比较地址
第三节 JS函数和事件
3.1 函数定义
function functionName(parameters){ //执行的代码 }
3.2 匿名函数
/*匿名函数*/ var method1=function(){ document.write("这是一个匿名函数"); } method1(); /*匿名函数(自执行匿名函数)*/ (function(s){ document.write("这是一个自执行匿名函数"+s); })("hahaha");
3.3 闭包
闭包就是能够读取其他函数内部局部变量的函数; 闭包可以理解成“定义在一个函数内部的函数“。
闭包三个条件:
1 闭包是一个内部函数
2 闭包能够读取其他(外部)函数的局部变量
3 闭包和局部变量在同一个作用域。
使用形式:1 闭包作为函数的返回值;2闭包作为函数的参数。
案例:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>闭包 closure</title> <script type="text/javascript"> /*定义一个函数*/ function a(){ var a=10; document.write(a); document.write("<br/>"); } // a(); // a(); // a(); function b(){ var num=10;//没有释放 /*函数包含函数*/ function c(){ num++; document.write(num); document.write("<br />") } return c; } var f=b();//f是一个函数:闭包 f(); f(); f(); </script> </head> <body> </body> </html>
好处:1 使局部变量常驻内存,2 避免污染全局变量 3 .提高封装性保护局部变量
3.4 系统函数
-
提示框 alert();
-
确认框 confirm();
-
输入框 prompt();
-
字符串转换整数 parseInt();
-
字符串转成小数 parseFloat();
-
判断数字是不是不是一个数字 isNaN();
3.5 事件
事件 | 描述 |
---|---|
onchange | HTML 元素内容改变(离开光标触发) |
onclick | 用户点击 HTML 元素 |
onmouseover | 光标移动到HTML元素 |
onmouseout | 光标离开HTML元素 |
onkeydown | 用户按下键盘按键 |
onload | 浏览器已完成页面的加载 |
3.6 字符串、正则表达式
-
字符串常用函数演示
var str="hello,我爱java";//原始类型 var str2=new String("hello");//引用类型对象类型 var str3=String("hello");//原始类型 document.write(str==str2); document.write("<br/>"); document.write(str===str2); document.write("<br/>"); document.write(typeof(str2)); document.write("<br/>"); //document.write(str instanceof String); document.write("长度:"+str.length); document.write("<br/>"); document.write("指定位置的字符:"+str.charAt(0)); document.write("<br/>"); document.write("indexOf:"+str.indexOf("java")); document.write("<br/>"); var ss=str.split(","); document.write(ss.length); document.write("<br/>"); var s1=str.substr(6,6); document.write(s1); var s2=str.substring(6,12); document.write(s2);
-
RegExp 对象
语法:
var patt=new RegExp(pattern,modifiers);
或者更简单的方式:
var patt=/pattern/modifiers;
修饰符
修饰符 描述 i 执行对大小写不敏感的匹配。 g 执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)。 m 执行多行匹配。 元字符
元字符 描述 . 查找单个字符,除了换行和行结束符。 \w 查找单词字符。[a-zA-Z0-9_] \W 查找非单词字符。 \d 查找数字。[0-9] \D 查找非数字字符。 \s 查找空白字符。 \S 查找非空白字符。 \b 匹配单词边界。 量词
量词 描述 n+ 匹配任何包含至少一个 n 的字符串。例如,/a+/ 匹配 "candy" 中的 "a","caaaaaaandy" 中所有的 "a" n* 匹配任何包含零个或多个 n 的字符串。例如,/bo*/ 匹配 "A ghost booooed" 中的 "boooo","A bird warbled" 中的 "b",但是不匹配 "A goat grunted"。 n? 匹配任何包含零个或一个 n 的字符串。例如,/e?le?/ 匹配 "angel" 中的 "el","angle" 中的 "le"。 n{X} 匹配包含 X 个 n 的序列的字符串。例如,/a{2}/ 不匹配 "candy," 中的 "a",但是匹配 "caandy," 中的两个 "a",且匹配 "caaandy." 中的前两个 "a"。 n{X,} X 是一个正整数。前面的模式 n 连续出现至少 X 次时匹配。例如,/a{2,}/ 不匹配 "candy" 中的 "a",但是匹配 "caandy" 和 "caaaaaaandy." 中所有的 "a"。 n{X,Y} X 和 Y 为正整数。前面的模式 n 连续出现至少 X 次,至多 Y 次时匹配。例如,/a{1,3}/ 不匹配 "cndy",匹配 "candy," 中的 "a","caandy," 中的两个 "a",匹配 "caaaaaaandy" 中的前面三个 "a"。注意,当匹配 "caaaaaaandy" 时,即使原始字符串拥有更多的 "a",匹配项也是 "aaa"。 n$ 匹配任何结尾为 n 的字符串。 ^n 匹配任何开头为 n 的字符串。 RegExp 对象方法
方法 描述 exec 检索字符串中指定的值。返回找到的值,并确定其位置。 test 检索字符串中指定的值。返回 true 或 false。 支持正则表达式的 String 对象的方法
方法 描述 match 找到一个或多个正则表达式的匹配。 replace 替换与正则表达式匹配的子串。 split 把字符串分割为字符串数组。
小结
(1)javascript是一门脚本语言,动态添加,弱类型语言。
(2)定义变量
var
(3)javascript包括基本(原始)类型,引用(对象)类型
原始类型:number boolean string undefined null
引用类型:Object (Person)、Array
(4)运算符
(5)选择(if(条件))、循环
(6)函数和事件
自定义函数
匿名函数
系统函数
事件: onchange onclick onmouseover onmouseout onkeydown onload
(7)字符串(记住)
(8)正则表达式
第四天 JS的DOM和BOM
第一节 DOM
1.1 概述
-
通过 HTML DOM,使用 JavaScript访问 HTML 文档的所有元素。
当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model)。
-
JS DOM能力
-
JavaScript 能够改变页面中的所有 HTML 元素。
-
JavaScript 能够改变页面中的所有 HTML 属性。
-
JavaScript 能够改变页面中的所有 CSS 样式。
-
JavaScript 能够对页面中的所有事件做出反应。
-
1.2 获取HTML元素
-
id找到HTML元素
var x=document.getElementById("intro");
-
标签名找到 HTML 元素
var x=document.getElementById("main"); var y=x.getElementsByTagName("p");
-
类名找到HTML 元素
var x=document.getElementsByClassName("intro");
1.3 修改HTML
-
改变HTML内容
<html> <body> <p id="p1">Hello World!</p> <script> document.getElementById("p1").innerHTML="abcd"; </script> </body> </html>
-
改变html属性
<!DOCTYPE html> <html> <body> <img id="image" src="1.gif"> <script> document.getElementById("image").src="2.jpg"; </script> </body> </html>
-
修改CSS样式
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <body> <p id="p1">Hello World!</p> <p id="p2">Hello World!</p> <script> document.getElementById("p2").style.color="blue"; document.getElementById("p2").style.fontFamily="Arial"; document.getElementById("p2").style.fontSize="larger"; </script> <p>以上段落通过脚本修改。</p> </body> </html>
-
元素操作
<div id="div1"> <p id="p1">这是一个段落。</p> <p id="p2">这是另一个段落。</p> </div> <script> var para=document.createElement("p"); var node=document.createTextNode("这是一个新段落。"); para.appendChild(node); var element=document.getElementById("div1"); element.appendChild(para); </script>
-
删除已有的 HTML 元素
<div id="div1"> <p id="p1">这是一个段落。</p> <p id="p2">这是另一个段落。</p> </div> <script> var parent=document.getElementById("div1"); var child=document.getElementById("p1"); parent.removeChild(child); </script>
-
DOM事件
<!DOCTYPE html> <html> <body> <h1 id="id1">myH1</h1> <button type="button" οnclick="document.getElementById('id1').style.color='red'"> button</button> </body> </html>
-
杂烩
<script> document.getElementById("myBtn").οnclick=function(){ document.getElementById("myhead2").style.color='blue'; }; </script>
<body οnlοad="alert('页面加载完毕')">
<input type="text" id="fname" οnchange="upperCase()">
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> </head> <body> <div οnmοuseοver="mOver(this)" οnmοuseοut="mOut(this)" style="background-color:#D94A38;width:120px;height:20px;padding:40px;">Mouse Over Me</div> <script> function mOver(obj){ obj.innerHTML="Thank You" } function mOut(obj){ obj.innerHTML="Mouse Over Me" } </script> </body> </html>
-
1.4 EventListener
-
addEventListener() 方法
document.getElementById("myBtn").addEventListener("click", displayDate);
-
addEventListener() 方法可以更简单的控制事件(冒泡与捕获)。
第一个参数是事件的类型 (如 "click" 或 "mousedown"). 把on去掉
第二个参数是事件触发后调用的函数。
第三个参数是个布尔值用于描述事件是冒泡还是捕获。该参数是可选的。
默认值为 false, 即冒泡传递,当值为 true 时, 事件使用捕获传递。
注意:不要使用 "on" 前缀。 例如,使用 "click" ,而不是使用 "onclick"。
-
element.addEventListener("click", myFunction); function myFunction() { alert ("Hello World!"); }
-
addEventListener() 方法允许向同个元素添加多个事件,且不会覆盖已存在的事件:
element.addEventListener("click", myFunction); element.addEventListener("click", mySecondFunction);
-
removeEventListener() 方法移除由 addEventListener() 方法添加的事件句柄:
element.removeEventListener("mousemove", myFunction);
-
第二节 JavaScript的BOM
2.1 window
-
三种方法能够确定浏览器窗口的尺寸。
var w=window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth; var h=window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight;
-
可用宽度,可用高度
document.write("可用宽度: " + screen.availWidth); document.write("可用高度: " + screen.availHeight);
-
2.2 Location
window.location 对象用于获得当前页面的地址 (URL),并把浏览器重定向到新的页面。
window.location 对象在编写时可不使用 window 这个前缀。 一些例子:
一些实例:
-
location.href 属性返回当前页面的 URL。
-
location.hostname 返回 web 主机的域名
-
location.pathname 返回当前页面的路径和文件名
-
location.port 返回 web 主机的端口 (80 或 443)
-
location.protocol 返回所使用的 web 协议(http:// 或 https://)
-
示例代码:
document.write(location.href); document.write(location.pathname);
location.assign() 方法加载新的文档
<html> <head> <script> function newDoc() { window.location.assign("http://www.baidu.com/") } </script> </head> <body> <input type="button" value="Load new document" οnclick="newDoc()"> </body> </html>
2.3 History
history.back() - 与在浏览器点击后退按钮相同
<html> <head> <script> function goBack() { window.history.back() } </script> </head> <body> <input type="button" value="Back" οnclick="goBack()"> </body> </html>
history.forward() - 与在浏览器中点击按钮向前相同
<html> <head> <script> function goForward() { window.history.forward() } </script> </head> <body> <input type="button" value="Forward" οnclick="goForward()"> </body> </html>
2.4Navigatory
已弃用
<div id="example"></div> <script> txt = "<p>浏览器代号: " + navigator.appCodeName + "</p>"; txt+= "<p>浏览器名称: " + navigator.appName + "</p>"; txt+= "<p>浏览器版本: " + navigator.appVersion + "</p>"; txt+= "<p>启用Cookies: " + navigator.cookieEnabled + "</p>"; txt+= "<p>硬件平台: " + navigator.platform + "</p>"; txt+= "<p>用户代理: " + navigator.userAgent + "</p>"; txt+= "<p>用户代理语言: " + navigator.systemLanguage + "</p>"; document.getElementById("example").innerHTML=txt; </script>
第三节 JavaScript计时
3.1 Date对象
var d=new Date(); document.write(d); document.write("<br/>") document.write("年份:"+(d.getYear()+1900)); document.write("<br/>") document.write("年份:"+d.getFullYear()); document.write("<br/>"); document.write("月份:"+(d.getMonth()+1)) document.write("<br/>"); document.write("日期:"+d.getDate()); document.write("<br/>"); document.write("小时:"+d.getHours()); document.write("<br/>"); document.write("分钟:"+d.getMinutes()); document.write("<br/>"); document.write("秒:"+d.getSeconds());
3.2 JavaScript计时函数
setInterval()周期执行函数
每三秒弹出 "hello" :
setInterval(function(){alert("Hello")},3000);
setInterval() 方法设置每秒钟执行一次代码,就是手表一样。
var myVar=setInterval(function(){myTimer()},1000); function myTimer() { var d=new Date(); var t=d.toLocaleTimeString(); document.getElementById("demo").innerHTML=t; }
clearInterval() 方法用于停止 setInterval() 方法执行的函数代码。
代码:
<p id="demo"></p> <button οnclick="myStopFunction()">Stop time</button> <script> var myVar=setInterval(function(){myTimer()},1000); function myTimer() { var d=new Date(); var t=d.toLocaleTimeString(); document.getElementById("demo").innerHTML=t; } function myStopFunction() { clearInterval(myVar); } </script>
setTimeout()延迟执行函数
异步执行
等待3秒,然后弹出 "Hello":
setTimeout(function(){alert("Hello")},3000);
clearTimeout() 方法用于停止执行setTimeout()方法的函数代码。
var myVar; function myFunction() { myVar=setTimeout(function(){alert("Hello")},3000); } function myStopFunction() { clearTimeout(myVar); }
使用setTimeout实现周期执行
<script type="text/javascript"> var num=0; var id=0; function show(){ document.write(id+"好好学习<br/>"); num++; if(num!=10){ id=setTimeout(show,1000); } } id=setTimeout(show,1000); </script>
小结
DOM
(1)获取网页元素
getElementById();
getElementsByTagName();
getElementsByClassName();
(2)获取或设置内容
innerHTML
innerText
(3)获取或修改属性
dom对象.src="";
dom对象.width=""
dom对象.setAttribute("属性名","属性值");
(4)修改css
dom对象.style.fontSize="";
(5)创建或删除元素
document.createElement();
appendChild();
insertBefore();
dom对象.remove();
dom对象.parentNode.removeChild(dom对象);
(6)DOM事件
html添加事件属性
EventListenner方式添加
事件的冒泡和捕获
(7)BOM
window:全局对象
innerWidth
innerHeight
open();
close();
screen 屏幕对象
location:地址
history:历史记录
navigator:导航对象
(8)时间
Date
setInterval(); 周期执行函数
setTimeOut(); 延迟执行函数
其他
Math
eval
第五天 SQL基础操作
第一节 数据库简介
1.1 SQL语句分类
-
DDL(Data Definition Language):数据定义语言,用来定义数据库对象:库、表、列等。
-
DML(Data Manipulation Language):数据操作语言,用来定义数据库记录(数据)。
-
DCL(Data Control Language):数据控制语言,用来定义访问权限和安全级别。
-
DQL(Data Query Language):数据查询语言,用来查询记录(数据)。
-
1.2 DDL操作数据库
-
系统默认数据库:
-
information_schema:
information_schema数据库是MySQL自带的,它提供了访问数据库元数据的方式。什么是元数据呢?元数据是关于数据的数据,如数据库名或表名,列的数据类型,或访问权限等。
-
mysql:
mysql:这个是mysql的核心数据库,主要负责存储数据库的用户、权限设置、关键字等mysql自己需要使用的控制和管理信息,不可以删除。
-
performance_schema:
性能优化的数据库
-
test:
这个是安装时候创建的一个测试数据库,和它的名字一样,是一个完全的空数据库,没有任何表,可以删除。
-
-
创建数据库
CREATE DATABASE [IF NOT EXISTS] db_name
-
查看
SHOW DATABASES;
-
查看前面创建的mydb2数据库的定义信息
ShOW CREATE DATABASE mydb2;
-
把mydb2的字符集修改为utf8
ALTER DATABASE mydb2 character SET utf8;
-
删除
DROP DATABASE [IF EXISTS] db_name
-
查看当前使用的数据库
SQL> Select database(); #没有选择数据 null
-
切换数据库
USE mydb2;
-
退出MySQL
quit;或exit;
-
1.3 DDL操作表
-
创建新表
CREATE TABLE [IF NOT EXISTS] 表名(
字段1 字段类型(长度) 约束,
字段2 字段类型(长度) 约束,
...
字段n 字段类型(长度) 约束
) [charset=utf8];
SQL> CREATE TABLE IF NOT EXISTS student ( id INT NOT NULL, name VARCHAR(50), age INT, address VARCHAR(100) ) CHARSET=utf8; 或 SQL> CREATE TABLE IF NOT EXISTS `student` ( `id` INT NOT NULL, `name` VARCHAR(50), `age` INT, `address` VARCHAR(100) ) CHARSET=utf8;
注意:数据库名、表名、字段名可以使用反勾号` 括住,也可以不括。如果SQL关键字一般要括住。
常用数据类型:
-
int:整型(4个字节)
-
double:浮点型(8个字节),近似值例如double(5,2)表示最多5位,其中必须有2位小数,即最大值为999.99
-
decimal:精确数值数据,最大位数可以是65例如decimal(5,2)能够存储具有五位数和两位小数的任何值,因此可以存储范围为-999.99至999.99。
-
char:固定长度字符串类型; char(10) 'aaa ' 固定10个字符,不足补空格, 长度0-255缺点:
浪费空间,优点:查询速度快
-
varchar:可变长度字符串类型; varchar(10) 'aaa' 最多存储10个字符
缺点:查询速度慢,优点:节省空间
-
text:大文本字符串类型;有字符编码,存储比较大的文本数据。
-
blob:Binary Large Object二进制大对象数据;可以存储图片、音频、视频
-
date:日期类型,格式为:yyyy-MM-dd;
-
time:时间类型,格式为:hh:mm:ss
-
timestamp:时间戳类型 yyyy-MM-dd hh:mm:ss 会自动赋值
-
datetime:日期时间类型 yyyy-MM-dd hh:mm:ss
常用约束:
-
主键约束:primary key (保证数据唯一性),不能重复,不能为null
-
唯一约束:unique [key],不能重复,可以为null
-
非空约束:not null
-
默认约束:default
-
外键约束:foreign key
-
自动增长:auto_increment
-
-
删除现有表
DROP TABLE table_name;
-
查看当前数据库中的所有表
SHOW TABLES;
-
查看表的字段信息
DESC student;
-
在上面学生表的基础上增加一个image列。
ALTER TABLE student ADD image blob;
-
修改address列,使其长度为60。
ALTER TABLE student MODIFY address varchar(60);
-
删除image列,一次只能删一列。
ALTER TABLE student DROP image;
-
表名改为user。
RENAME TABLE student TO user;
-
查看表的创建细节
SHOW CREATE TABLE user;
-
修改表的字符集为gbk
ALTER TABLE user CHARACTER SET gbk;
-
列名name修改为username
ALTER TABLE user CHANGE name username varchar(100);
-
1.4 DML操作
DML是对表中的数据进行增、删、改的操作。
主要包括:INSERT 、UPDATE、 DELETE
小知识:
在mysql中,字符串类型和日期类型都要用单引号括起来。
空值:null。
-
插入操作:INSERT:
INSERT INTO 表名(列名1,列名2 ...)VALUES(列值1,列值2...);
INSERT INTO student(id,name,age,address) values (1,'zhangsan',20,'北京海淀');
INSERT INTO student(id,name,age,address) values (4,'曹操',27,'北京海淀'),(5,'周瑜',28,'北京朝阳'),(6,'赵云',30,'北京大兴');
小知识:
查看数据库编码的具体信息
Show variables like ‘character%’;
临时更改客户端和服务器结果集的编码
Set character_set_client=gbk;
Set character_set_results=gbk;
或者
SET NAMES ‘gbk’; // client connection results
-
修改操作:UPDATE
语法:UPDATE 表名 SET 列名1=列值1,列名2=列值2 ... WHERE 列名=值
-
删除操作:DELETE
DELETE FROM 表名 【WHERE 列名=值】
-
第二节 DQL数据查询(重点)
查询返回的结果集是一张虚拟表
语法: SELECT 列名 FROM 表名 【WHERE --> GROUP BY-->HAVING--> ORDER BY-->LIMIT】
有顺序
SELECT selection_list /要查询的列名称/
FROM table_list /要查询的表名称/
WHERE condition /行条件/
GROUP BY grouping_columns /对结果分组/
HAVING condition /分组后的行条件/
ORDER BY sorting_columns /对结果排序/
LIMIT offset_start, row_count /结果限定/
2.1 简单查询
-
查询所有列 *表示所有列
SELECT * FROM stu;
-
查询指定列
SELECT sid, sname, age FROM stu;
-
比较运算符**
l =、!=、<>、<、<=、>、>=;
l BETWEEN…AND; 含头含尾
l IN(set);
l IS NULL;
关系运算符
l AND;
l OR;
l NOT;
算术运算符:
+ - * / %
-
模糊查询
_ 任意一个字符
%:任意0~n个字符
'张%' ---》张三丰 张三 张无忌
'李_' --->李四 李逵 李刚
SELECT * FROM stu WHERE sname LIKE '___';
模糊查询必须使用LIKE关键字。其中 “”匹配任意一个字母,5个“”表示5个任意字母。
-
字段控制查询
去除重复记录
SELECT DISTINCT sal FROM emp; SELECT DISTINCT sal,comm FROM emp; --两个都重复才排重
用了把NULL转换成数值0的函数IFNULL:
SELECT *,sal+IFNULL(comm,0) FROMemp;
给列名添加别名
SELECT *, sal+IFNULL(comm,0) AS total FROM emp;
给列起别名时,是可以省略AS关键字的:
SELECT *,sal+IFNULL(comm,0) total FROM emp;
-
排序
查询所有学生记录,按年龄升序排序
SELECT * FROM stu ORDER BY age ASC; SELECT * FROM stu ORDER BY age;# 默认升序
查询所有学生记录,按年龄降序排序
SELECT * FROM stu ORDER BY age DESC;
查询所有雇员,按月薪降序排序,如果月薪相同时,按编号升序排序
SELECT * FROM emp ORDER BY sal DESC,empno ASC;
-
聚合函数
聚合函数是用来做纵向运算的函数:
l COUNT():统计指定列不为NULL的记录行数;
l MAX():计算指定列的最大值,如果指定列是字符串类型,那么使用字符串排序运算;
l MIN():计算指定列的最小值,如果指定列是字符串类型,那么使用字符串排序运算;
l SUM():计算指定列的数值和,如果指定列类型不是数值类型,那么计算结果为0;
l AVG():计算指定列的平均值,如果指定列类型不是数值类型,那么计算结果为0;
示例
-- 查询emp表中记录数 SELECT COUNT(*) AS ‘cnt’ FROM emp; --查询emp表中有佣金的人数: SELECT COUNT(*) FROM emp WHERE sal > 2500; --查询emp表中月薪大于2500的人数 SELECT COUNT(*) AS cnt FROM emp WHERE sal+IFNULL(comm,0) >2500; --统计月薪与佣金之和大于2500元的人数: SELECT COUNT(*) AS cnt FROM emp WHERE sal+IFNULL(comm,0) > 2500; --查询有佣金的人数,以及有领导的人数: SELECT COUNT(comm), COUNT(mgr)FROM emp; --查询所有雇员月薪和: SELECT SUM(sal) FROM emp; --查询所有雇员月薪和,以及所有雇员佣金和: SELECT SUM(sal), SUM(comm) FROMemp; --查询所有雇员月薪+佣金和: SELECT SUM(sal+IFNULL(comm,0))FROM emp; -- 统计所有员工平均工资: SELECT AVG(sal) FROM emp; --查询最高工资和最低工资: SELECT MAX(sal), MIN(sal) FROM emp;
-
分组查询
--查询每个部门的部门编号和每个部门的工资和: SELECT deptno, SUM(sal) FROM emp GROUP BY deptno; --查询每个部门的部门编号以及每个部门的人数: SELECT deptno,COUNT(*) FROM emp GROUP BY deptno; --查询每个部门的部门编号以及每个部门工资大于1500的人数: SELECT deptno,COUNT(*) FROM emp WHERE sal>1500 GROUP BY deptno;
-
HAVING子句
--查询工资总和大于9000的部门编号以及工资和 SELECT deptno, SUM(sal) FROM emp GROUP BY deptno HAVING SUM(sal) > 9000;
注:having与where的区别:
1.having是在分组后对数据进行过滤,where是在分组前对数据进行过滤
2.having后面可以使用分组函数(统计函数)
where后面不可以使用分组函数。
where是对分组前记录的条件,如果某行记录没有满足WHERE子句的条件,那么这行记录不会参加分组;而 having是对分组后数据的约束。
-
LIMIT限制
--查询前5行记录,起始行从0开始 SELECT * FROM emp LIMIT 0, 5; --查询10行记录,起始行从3开始 SELECT* FROM emp LIMIT 3, 10; --分页查询可以5,5即从第6条数据向后走5行
-
小结
1 数据库:存储数据的仓库。
2 数据库管理系统: MySQL Oracle SQL Server DB2
3 MySQL安装、卸载
4 SQL语句:
DDL 数据定义语言 创建库,创建表
DML数据操纵语言 添加 删除 更新 insert delete udpate
DQL 数据查询语言 select
DCL 数据控制语言, 用户的创建 权限分配。
5 DQL
简单查询
条件查询 where 运算符 = != <> > >= < <= in between and and or not + - * / %
模糊查询 通配符 _表示一个字符 %表示任意多个字符
字段控制 distinct 去重 合并 别名
排序 order by
聚合函数 count sum max min avg
分组查询 group by having
limit 限制查询
第六天 MySQL约束和多表查询
第一节 数据完整性
作用:保证用户输入的数据保存到数据库中是正确的。
确保数据的完整性 = 在创建表时给表中添加约束
-
实体完整性约束
约束类型:
主键约束(primary key)
唯一约束(unique)
自动增长列(auto_increment)
-
主键约束(primary key)数据不能重复。不可以为null
第一种添加方式:
CREATE TABLE student( id int primary key, name varchar(50) ); CREATE TABLE student( id int, name varchar(50), primary key(id) );
第二种添加方式:此种方式优势在于,可以创建联合主键
CREATE TABLE student( classid int, stuid int, name varchar(50), primary key(classid,stuid) );
第三种添加方式:(不推荐)
CREATE TABLE student( id int, name varchar(50) ); ALTER TABLE student ADD PRIMARY KEY (id);
-
唯一约束(unique)
特点:数据不能重复。可以为null
CREATE TABLE student( Id int primary key, Name varchar(50) unique );
-
自动增长列(auto_increment)
CREATE TABLE student( Id int primary key auto_increment, Name varchar(50) ) auto_increment=100; INSERT INTO student(name) values(‘tom’);
-
域完整性约束
域完整性约束的作用:限制此单元格的数据正确,不对其它单元格起作用,域代表当前单元格
域完整性约束:数据类型、非空约束(not null)、默认值约束(default)
check约束(mysql不支持)check(sex='男'or sex='女')
check约束可以用enum代替
数值类型
类型 大小 范围(有符号) 范围(无符号) 用途 TINYINT 1 字节 (-128,127) (0,255) 小整数值 SMALLINT 2 字节 (-32 768,32 767) (0,65 535) 大整数值 MEDIUMINT 3 字节 (-8 388 608,8 388 607) (0,16 777 215) 大整数值 INT或INTEGER 4 字节 (-2 147 483 648,2 147 483 647) (0,4 294 967 295) 大整数值 BIGINT 8 字节 (-9 233 372 036 854 775 808,9 223 372 036 854 775 807) (0,18 446 744 073 709 551 615) 极大整数值 FLOAT 4 字节 查看帮助文档 查看帮助文档 单精度浮点数值 DOUBLE 8 字节 查看帮助文档 查看帮助文档 双精度浮点数值 DOUBLE(M,D) 8个字节,M表示长度,D表示小数位数 同上,受M和D的约束 DUBLE(5,2) -999.99-999.99 同上,受M和D的约束 双精度浮点数值 DECIMAL(M,D) 对DECIMAL(M,D) ,如果M>D,为M+2否则为D+2 依赖于M和D的值,M最大值为65 依赖于M和D的值,M最大值为65 小数值 日期类型:
每个时间类型有一个有效值范围和一个"零"值,当指定不合法的MySQL不能表示的值时使用"零"值。
-
类型 大小(字节) 范围 格式 用途 DATE 3 1000-01-01/9999-12-31 YYYY-MM-DD 日期值 TIME 3 '-838:59:59'/'838:59:59' HH:MM:SS 时间值或持续时间 YEAR 1 1901/2155 YYYY 年份值 DATETIME 8 1000-01-01 00:00:00/9999-12-31 23:59:59 YYYY-MM-DD HH:MM:SS 混合日期和时间值 TIMESTAMP 4 1970-01-01 00:00:00/2038 结束时间是第 2147483647 秒,北京时间 2038-1-19 11:14:07,格林尼治时间 2038年1月19日 凌晨 03:14:07 YYYYMMDD HHMMSS 混合日期和时间值,时间戳 字符串类型:
类型 大小 用途 CHAR 0-255字符 定长字符串 char(10) 10个字符 VARCHAR 0-65535 字节 变长字符串 varchar(10) 10个字符 TINYBLOB 0-255字节 不超过 255 个字符的二进制字符串 TINYTEXT 0-255字节 短文本字符串 BLOB(binary large object) 0-65 535字节 二进制形式的长文本数据 TEXT 0-65 535字节 长文本数据 MEDIUMBLOB 0-16 777 215字节 二进制形式的中等长度文本数据 MEDIUMTEXT 0-16 777 215字节 中等长度文本数据 LONGBLOB 0-4 294 967 295字节 二进制形式的极大文本数据 LONGTEXT 0-4 294 967 295字节 极大文本数据 CHAR和VARCHAR类型类似,但它们保存和检索的方式不同。它们的最大长度和是否尾部空格被保留等方面也不同。在存储或检索过程中不进行大小写转换。
INARY和VARBINARY类类似于CHAR和VARCHAR,不同的是它们包含二进制字符串而不要非二进制字符串。也就是说,它们包含字节字符串而不是字符字符串。这说明它们没有字符集,并且排序和比较基于列值字节的数值值。
BLOB是一个二进制大对象,可以容纳可变数量的数据。有4种BLOB类型:TINYBLOB、BLOB、MEDIUMBLOB和LONGBLOB。它们只是可容纳值的最大长度不同。
有4种TEXT类型:TINYTEXT、TEXT、MEDIUMTEXT和LONGTEXT。
-
非空约束
not null
-
默认值约束
default
CREATE TABLE student( Id int primary key, Name varchar(50) not null, Sex varchar(10) default '男' ); insert intostudent1 values(1,'tom','女'); insert intostudent1 values(2,'jerry',default);
-
引用完整性约束
外键约束:FOREIGN KEY
第一种添加外键方式。推荐
#学生表(主表) CREATE TABLE student( sid int primary key, name varchar(50) not null, sex varchar(10) default '男' ); #成绩表(从表) create table score( id int, score int, sid int , CONSTRAINT fk_score_sid foreign key(sid) references student(sid) ); -- 外键列的数据类型一定要与主键的类型一致
第二种添加外键方式。
ALTER TABLE score ADD CONSTRAINT fk_stu_score FOREIGN KEY(sid) REFERENCES student(sid);
-
第二节 多表查询
多表的关系
-
多表的关系
一对多关系
多对多关系(可以通过建立新表转换成一对多关系)
一对一关系
-
多表查询
--去除重复记录 SELECT * FROM t1 UNION SELECT * FROM t2; --不去除重复记录 SELECT * FROM t1 UNION ALL SELECT * FROM t2; # 注意:被合并的两个结果:列数必须相同,列类型可以不同。 # 连接查询 # 交叉连接(笛卡儿积),有很多重复数据 SELECT * FROM emp,dept; # 14*4=56 传统写法 SELECT * FROM emp CROSS JOIN dept; # 标准写法 # 内连接 两个表的位置可以交换(外键为空置拿不出数据) SELECT * FROM emp CROSS JOIN dept WHERE emp.deptno = dept.deptno; # 交叉连接基础上做一个判断 传统写法 SELECT * FROM emp CROSS JOIN dept ON emp.deptno = dept.deptno; # 标准写法 SELECT * FROM emp INNER JOIN dept ON emp.deptno = dept.deptno; # 外连接 连个表的位置不能交换,有主次之分 # 左外连接(左表为主表,右表为从表) SELECT * FROM emp LEFT OUTER JOIN dept ON emp.deptno = dept.deptno; SELECT * FROM emp LEFT JOIN dept ON emp.deptno = dept.deptno; # OUTER可以省略 SELECT * FROM emp LEFT JOIN dept ON emp.deptno = dept.deptno WHERE dept.deptno IS NULL; # 右外连接(右表为主表,左表为从表) SELECT * FROM emp RIGHT JOIN dept ON emp.deptno = dept.deptno WHERE emp.deptno IS NULL; # OUTER可以省略 # 子查询 SELECT sal FROM emp WHERE ename='jones'; SELECT * FROM emp WHERE sal > 2975; SELECT * FROM emp WHERE sal > (SELECT sal FROM emp WHERE ename='jones'); SELECT deptno FROM emp WHERE ename='scott'; SELECT * FROM emp WHERE deptno=(SELECT deptno FROM emp WHERE ename='scott'); SELECT MAX(sal) FROM emp WHERE deptno=30; SELECT * FROM emp WHERE sal > (SELECT MAX(sal) FROM emp WHERE deptno=30); SELECT * FROM emp WHERE sal > ALL (SELECT sal FROM emp WHERE deptno=30); # 大于所有的,即最高的 SELECT * FROM emp WHERE sal > ANY (SELECT sal FROM emp WHERE deptno=30); # 大于所有的,即最低的 SELECT * FROM (SELECT ename,job,sal FROM emp) AS temp; # 结果多行多列 # `localhost` 只能本地账户登陆, '%'所有账户都能登陆, '10.9.21.188'只能这个地址能登陆账户 # 创建用户 CREATE USER `zhangsan1`@`localhost` IDENTIFIED BY '123'; # 授权 GRANT SELECT,UPDATE,DELETE,INSERT ON test01.* TO `zhangsan1`@`localhost`; # 撤销权限 REVOKE ALL ON test01.* FROM `zhangsan1`@`localhost`; # 删除用户 DROP USER `zhangsan1`@`localhost`;
第三节 视图、存储过程、变量、函数
3.1 视图
概念
视图就是一条SELECT语句执行后返回的结果集。所以我们在创建视图的时候,主要的工作就落在创建这条SQL查询语句上。
视图特点
视图是对若干张基本表的引用,一张虚表,查询语句执行的结果,不存储具体的数据(基本表数据发生了改变,视图也会跟着改变)视图一般不执行增删改操作。
好处
方便操作,特别是查询操作,减少复杂的SQL语句,增强可读性; 更加安全,数据库授权命令不能限定到特定行和特定列,但是通过合理创建视图,可以把权限限定到行列级别;
示例
-- ---------------------------- -- View structure for `view_user_course` -- ---------------------------- DROP VIEW IF EXISTS `view_user_course`; CREATE VIEW `view_user_course` AS (SELECT `uc`.`id` AS `id`, `u`.`name` AS `username`, `c`.`name` AS `coursename` FROM `user` `u` LEFT JOIN `user_course` `uc` ON `u`.`id` = `uc`.`userid` LEFT JOIN `course` `c` ON `uc`.`courseid` = `c`.`id`) ; SELECT vuc.username, vuc.coursename FROM view_user_course vuc WHERE vuc.username = '小张'
3.2 存储过程
简介
存储过程(Stored Procedure)是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给定参数(如果该存储过程带有参数)来调用执行它。 存储过程是可编程的函数,在数据库中创建并保存,可以由SQL语句和控制结构组成。当想要在不同的应用程序或平台上执行相同的函数,或者封装特定功能时,存储过程是非常有用的。数据库中的存储过程可以看做是对编程中面向对象方法的模拟,它允许控制数据的访问方式。
优点
(1).增强SQL语言的功能和灵活性. 存储过程可以用控制语句编写,有很强的灵活性,可以完成复杂的判断和较复杂的运算。 (2).标准组件式编程. 存储过程被创建后,可以在程序中被多次调用,而不必重新编写该存储过程的SQL语句。而且数据库专业人员可以随时对存储过程进行修改,对应用程序源代码毫无影响。 (3).较快的执行速度. 如果某一操作包含大量的Transaction-SQL代码或分别被多次执行,那么存储过程要比批处理的执行速度快很多。因为存储过程是预编译的。在首次运行一个存储过程时查询,优化器对其进行分析优化,并且给出最终被存储在系统表中的执行计划。而批处理的Transaction-SQL语句在每次运行时都要进行编译和优化,速度相对要慢一些。 (4).减少网络流量. 针对同一个数据库对象的操作(如查询、修改),如果这一操作所涉及的Transaction-SQL语句被组织进存储过程,那么当在客户计算机上调用该存储过程时,网络中传送的只是该调用语句,从而大大减少网络流量并降低了网络负载。 (5).作为一种安全机制来充分利用. 通过对执行某一存储过程的权限进行限制,能够实现对相应的数据的访问权限的限制,避免了非授权用户对数据的访问,保证了数据的安全。
创建存储过程
CREATE PROCEDURE 过程名([[IN|OUT|INOUT] 参数名 数据类型[,[IN|OUT|INOUT] 参数名 数据类型…]]) [特性 ...] 过程体
举例
DELIMITER // CREATE PROCEDURE myproc(OUT s int) BEGIN SELECT COUNT(*) INTO s FROM students; END // DELIMITER ; --"DELIMITER ;"的意为把分隔符还原为;
参数
IN:参数的值必须在调用存储过程时指定,在存储过程中修改该参数的值不能被返回,为默认值 OUT:该值可在存储过程内部被改变,并可返回 INOUT:调用时指定,并且可被改变和返回
存储过程的删除
DROP PROCEDURE [过程1[,过程2…]]
示例
--例子1 输入参数 DELIMITER // CREATE PROCEDURE in_param(IN p_in int) BEGIN SELECT p_in; SET p_in=2; SELECT p_in; END; // DELIMITER ; #调用 CALL in_param(10); --例子2 输出参数 DELIMITER // CREATE PROCEDURE out_param(OUT p_out int) BEGIN SELECT p_out; SET p_out=2; SELECT p_out; END; // DELIMITER ; #调用 SET @p_out=1; CALL out_param(@p_out); SELECT @p_out; --例子3 输入输出参数 DELIMITER // CREATE PROCEDURE inout_param(INOUT p_inout int) BEGIN SELECT p_inout; SET p_inout=2; SELECT p_inout; END; // DELIMITER ; #调用 SET @p_inout=1; CALL inout_param(@p_inout) ; SELECT @p_inout; --案例4 转账存储过程 DELIMITER // CREATE PROCEDURE transMoney(IN fromid INT, IN toid INT, IN m DECIMAL) BEGIN UPDATE account SET money=money-m WHERE id=fromid; UPDATE account SET money=money+m WHERE id=toid; END; // DELIMITER ; #调用 CALL transMoney(1,2,1000); --案例5 使用存储添加学生 DELIMITER // CREATE PROCEDURE addStudent(IN _id INT, IN `_name` VARCHAR(10), IN _age INT,_address VARCHAR(100)) BEGIN INSERT INTO student(id,NAME,age,address) VALUES(_id,_name,_age,_address); END; // DELIMITER ; #调用 CALL addStudent(6,'张无忌',20,'南京');
3.3 MySQL中的变量
-
局部变量
DECLARE var_name [, var_name]... data_type [ DEFAULT value ]; --示例1 DELIMITER // CREATE PROCEDURE addNum(IN a INT, IN b INT) BEGIN DECLARE c INT DEFAULT 0; SET c=a+b; #赋值,必须要有SET SELECT c AS C; END; // DELIMITER ; #调用 CALL addNum(10,20); --示例2 DELIMITER // CREATE PROCEDURE queryemp() BEGIN DECLARE v_name VARCHAR(100); DECLARE v_salary DECIMAL(8,2); SELECT `name`, `salary` INTO v_name, v_salary FROM employee WHERE id=1; SELECT v_name,v_salary; END; // DELIMITER ; #调用 CALL queryemp();
-
用户变量
在客户端链接到数据库实例整个过程中用户变量都是有效的。
示例
set @name = ''; select @name:=password from user limit 0,1;
-
会话变量
服务器为每个连接的客户端维护一系列会话变量。在客户端连接数据库实例时,使用相应全局变量的当前值对客户端的会话变量进行初始化。设置会话变量不需要特殊权限,但客户端只能更改自己的会话变量,而不能更改其它客户端的会话变量。会话变量的作用域与用户变量一样,仅限于当前连接。当当前连接断开后,其设置的所有会话变量均失效。
查看所有的会话变量 SHOW [SESSION] VARIABLES; 查看一个会话变量也有如下三种方式: select @@var_name; select @@session.var_name; show session variables like "%var%";
-
全局变量
全局变量影响服务器整体操作。当服务器启动时,它将所有全局变量初始化为默认值。这些默认值可以在选项文件中或在命令行中指定的选项进行更改。要想更改全局变量,必须具有SUPER权限
查看所有的全局变量 show global variables; 要想查看一个全局变量,有如下两种方式: select @@global.var_name; show global variables like “%var%”;
-
3.4 函数
存储没有返回值,使用输出参数返回数据,可以有多个,函数有返回值,只能返回一个。
MySQL 有很多内置的函数
-
字符串函数
CHARSET(str) //返回字串字符集 CONCAT (string2 [,... ]) //连接字串 INSTR (string ,substring ) //返回substring首次在string中出现的位置,不存在返回0 LCASE (string2 ) //转换成小写 LEFT (string2 ,length ) //从string2中的左边起取length个字符 LENGTH (string ) //string长度,字节的长度 LOAD_FILE (file_name ) //从文件读取内容 LOCATE (substring , string [,start_position ] ) 同INSTR,但可指定开始位置 LPAD (string ,length ,pad ) //重复用pad加在string开头,直到字串长度为length LTRIM (string ) //去除前端空格 REPEAT (string2 ,count ) //重复count次 REPLACE (str ,search_str ,replace_str ) //在str中用replace_str替换search_str RPAD (string ,length ,pad) //在str后用pad补充,直到长度为length RTRIM (string ) //去除后端空格 STRCMP (string1 ,string2) //逐字符比较两字串大小, SUBSTRING (str , position [,length ]) //从str的position开始,取length个字符, TRIM([[BOTH|LEADING|TRAILING] [padding] FROM]string2) //去除指定位置的指定字符 UCASE (string2 ) //转换成大写 RIGHT(string2,length) //取string2最后length个字符 SPACE(count) //生成count个空格 注:mysql中处理字符串时,默认第一个字符下标为1,即参数position必须大于等于1
数学类函数
ABS (number2 ) //绝对值 BIN (decimal_number) //十进制转二进制 CEILING (number2 ) //向上取整 CONV(number2,from_base,to_base) //进制转换 FLOOR (number2 ) //向下取整 FORMAT (number,decimal_places ) //保留小数位数 POWER (number ,power ) //求指数 RAND([seed]) //随机数 ROUND (number [,decimals ]) //四舍五入,decimals为小数位数] 注:返回类型并非均为整数
日期时间类
ADDTIME (date2 ,time_interval) //将time_interval天加到date2 秒 ADDDATE('2019-04-15',2); #2天 CURRENT_DATE ( ) //当前日期 CURRENT_TIME ( ) //当前时间 CURRENT_TIMESTAMP ( ) //当前时间戳 DATE (datetime ) //返回datetime的日期部分 DATE_ADD (date2 , INTERVAL d_value d_type ) //在date2中加上日期或时间 DATE_FORMAT (datetime ,FormatCodes ) //使用formatcodes格式显示datetime DATE_SUB (date2 , INTERVAL d_value d_type ) //在date2上减去一个时间 DATEDIFF (date1 ,date2 ) //两个日期差 DAY (date ) //返回日期的天 DAYNAME (date ) //英文星期 DAYOFWEEK (date ) //星期(1-7) ,1为星期天 DAYOFYEAR (date ) //一年中的第几天 EXTRACT (interval_name FROM date ) //从date中提取日期的指定部分 MAKEDATE (year ,day ) //给出年及年中的第几天,生成日期串 MAKETIME (hour ,minute ,second ) //生成时间串 MONTHNAME (date ) //英文月份名 NOW ( ) //当前时间 SEC_TO_TIME (seconds ) //秒数转成时间 STR_TO_DATE (string ,format ) //字串转成时间,以format格式显示 TIMEDIFF (datetime1 ,datetime2 ) //两个时间差 TIME_TO_SEC(time) //时间转秒数 WEEK (date_time [,start_of_week ]) //第几周 YEAR (datetime ) //年份 DAYOFMONTH(datetime) //月的第几天 HOUR(datetime) //小时
-
3.1 使用步骤
-
导入JDBC驱动包:**需要下载包含数据库编程所需的JDBC的jar包。
-
注册JDBC驱动程序:要求您初始化驱动程序,以便您可以打开与数据库的通信通道。
-
创建连接:需要使用DriverManager.getConnection()方法创建一个Connection对象,该对象表示与数据库的物理连接。
-
执行查询:需要使用类型为Statement的对象来构建和提交SQL语句到数据库。
-
从结果集中提取数据:需要使用相应的ResultSet.getXXX()方法从结果集中检索数据。
-
释放资源:需要明确地关闭所有数据库资源,而不依赖于JVM的垃圾收集。
-
3.2 注册驱动
-
第一种方式(推荐写法):Class.forName()
try { Class.forName("com.mysql.jdbc.Driver"); } catch(ClassNotFoundException ex) { System.out.println("Error: unable to load driver class!"); System.exit(1); }
-
第二种方式:是使用静态DriverManager.registerDriver()方法。
try { Driver myDriver = new com.mysql.jdbc.Driver(); DriverManager.registerDriver( myDriver ); } catch(ClassNotFoundException ex) { System.out.println("Error: unable to load driver class!"); System.exit(1); } * 1>驱动程序注册两次 * 2>java程序依赖mysql驱动包
-
3.3 获取连接
DriverManager.getConnection()方法
RDBMS JDBC驱动程序名称 连接字符串格式 MySQL的 com.mysql.jdbc.Driver jdbc:mysql://hostname:3306 / databaseName ORACLE oracle.jdbc.driver.OracleDriver jdbc:oracle:thin:@ hostname:port Number:databaseName DB2 COM.ibm.db2.jdbc.net.DB2Driver jdbc:db2:hostname:port Number / databaseName SYBASE com.sybase.jdbc.SybDriver jdbc:sybase:Tds: hostname:port Number / databaseName 创建数据库连接对象
String URL = "jdbc:mysql://localhost:3306/emp"; String USER = "root"; String PASS = "root" Connection conn = DriverManager.getConnection(URL, USER, PASS);
第四节 JDBC执行SQL语句
-
Statement
-
boolean execute(String SQL)**:如果可以检索到ResultSet对象,则返回一个布尔值true; 否则返回false。使用此方法执行SQL DDL语句或需要使用真正的动态SQL时。
-
int executeUpdate(String SQL):返回受SQL语句执行影响的行数。使用此方法执行预期会影响多个行的SQL语句,例如INSERT,UPDATE或DELETE语句。
-
ResultSet executeQuery(String SQL):返回一个ResultSet对象。当您希望获得结果集时,请使用此方法,就像使用SELECT语句一样。
-
-
ResultSet
SELECT语句是从数据库中选择行并在结果集中查看行的标准方法。该java.sql.ResultSet中的接口表示结果集数据库查询。
ResultSet对象维护指向结果集中当前行的游标。术语“结果集”是指包含在ResultSet对象中的行和列数据。
如果没有指定任何ResultSet类型,您将自动获得一个TYPE_FORWARD_ONLY。
类型 描述 ResultSet.TYPE_FORWARD_ONLY 光标只能在结果集中向前移动。 ResultSet.TYPE_SCROLL_INSENSITIVE 光标可以向前和向后滚动,结果集对创建结果集后发生的数据库的其他更改不敏感。 ResultSet.TYPE_SCROLL_SENSITIVE。 光标可以向前和向后滚动,结果集对创建结果集之后发生的其他数据库所做的更改敏感。 --演示案例1:查询数据 public class JdbcDemo2 { public static void main(String[] args) { Connection connection=null; Statement stat=null; ResultSet rs=null; //2注册驱动 try { Class.forName("com.mysql.jdbc.Driver"); //3获取连接 connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/school", "root", "root"); //4创建命令(语句)对象 stat=connection.createStatement(); //执行命令查询 rs=stat.executeQuery("select ename,empno from emp"); //5处理结果 while(rs.next()){ // int empno=rs.getInt(1); // String empname=rs.getString(2); int empno=rs.getInt("empno"); String empname=rs.getString("ename"); System.out.println(empno+"...."+empname); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { if(rs!=null){ try { rs.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(stat!=null){ try { stat.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(connection!=null){ try { connection.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } } --演示案例2:添加数据 public class JdbcDemo3 { public static void main(String[] args) { Connection connection=null; Statement stat=null; //2 注册驱动 try { Class.forName("com.mysql.jdbc.Driver"); //3打开连接 connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/school", "root", "root"); //4创建命令并执行 stat=connection.createStatement(); int result=stat.executeUpdate("insert into dept(deptno,dname,loc) values(80,'市场部','天津')"); if(result>0){ System.out.println("添加成功"); }else{ System.out.println("添加失败"); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { if(stat!=null){ try { stat.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(connection!=null){ try { connection.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } } --演示案例3:更新数据 public class JdbcDemo4 { public static void main(String[] args) { Connection connection=null; Statement stat=null; //2 注册驱动 try { Class.forName("com.mysql.jdbc.Driver"); //3打开连接 connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/school", "root", "root"); //4创建命令并执行 stat=connection.createStatement(); int result=stat.executeUpdate("update dept set loc='内蒙' where deptno=80"); if(result>0){ System.out.println("更新成功"); }else{ System.out.println("更新失败"); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { if(stat!=null){ try { stat.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(connection!=null){ try { connection.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } } --演示案例4:删除 public class JdbcDemo5 { public static void main(String[] args) { Connection connection=null; Statement stat=null; //2 注册驱动 try { Class.forName("com.mysql.jdbc.Driver"); //3打开连接 connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/school", "root", "root"); //4创建命令并执行 stat=connection.createStatement(); int result=stat.executeUpdate("delete from dept where deptno=80"); if(result>0){ System.out.println("删除成功"); }else{ System.out.println("删除失败"); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { if(stat!=null){ try { stat.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(connection!=null){ try { connection.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } } --演示案例5:实现用户登录 数据库myschool 表 :user create table user( • id int primary key auto_increment, • username varchar(18) not null, • password varchar(16) not null, # 密文 123456 • phone varchar(11) ); insert into user (username,password,phone) values('zhangsan','123456','13898765678'); insert into user (username,password,phone) values('lisi','6666','17898879988'); package com.qf.day03; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Scanner; import javax.management.remote.rmi.RMIJRMPServerImpl; /* * 实现用户登录 */ public class JdbcDemo1 { public static void main(String[] args) { Scanner input=new Scanner(System.in); System.out.println("请输入用户名"); String username=input.nextLine(); System.out.println("请输入密码"); String pass=input.nextLine(); //连接对象 Connection connection=null; //命令对象 Statement stat=null; //结果集 ResultSet rs=null; //1 注册驱动 try { Class.forName("com.mysql.jdbc.Driver"); //2获取连接 connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/school", "root", "root"); //3创建命令 stat=connection.createStatement(); //4执行命命令 select * from user where username='zhangsan' and password='123456'; rs=stat.executeQuery("select * from user where username='"+username+"' and password='"+pass+"'"); if(rs.next()){ //有数据 System.out.println("登录成功"); }else{ System.out.println("账号或密码错误"); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { if(rs!=null){ try { rs.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(stat!=null){ try { stat.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(connection!=null){ try { connection.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }
-
SQL注入
就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意的)SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。比如先前的很多影视网站泄露VIP会员密码大多就是通过WEB表单递交查询字符暴出的,这类表单特别容易受到SQL注入式攻击。
-
PreparedStatement
作用:1预编译,效率高 2 安全,避免SQL注入
PreparedStatement pstmt = null; try { String SQL = "Update Employees SET age = ? WHERE id = ?"; pstmt = conn.prepareStatement(SQL); . . . } catch (SQLException e) { . . . } finally { . . . }
练习
package com.qf.day03; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Scanner; /** * 使用PreparedStatement实现emp表的数据添加 * @author wgy * */ public class Demo6 { public static void main(String[] args) throws Exception{ Scanner input=new Scanner(System.in); System.out.println("请输入员工编号"); int empno=input.nextInt(); System.out.println("请输入员工姓名"); String ename=input.next(); System.out.println("请输入工作"); String job=input.next(); System.out.println("请输入经理的编号"); int mgr=input.nextInt(); System.out.println("请输入入职日期"); String date=input.next(); SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd"); Date hiredate=sdf.parse(date); System.out.println("请输入工资"); double salary=input.nextDouble(); System.out.println("请输入奖金"); double comm=input.nextDouble(); System.out.println("请输入部门"); int deptno=input.nextInt(); //1注册驱动 Class.forName("com.mysql.jdbc.Driver"); //2获取连接 String url="jdbc:mysql:///school"; Connection conn=DriverManager.getConnection(url, "root", "root"); //3创建命令 PreparedStatement pstat=conn.prepareStatement("insert into emp(empno,ename,job,mgr,hiredate,sal,comm,deptno) values(?,?,?,?,?,?,?,?);"); //4参数赋值 pstat.setObject(1, empno); pstat.setObject(2, ename); pstat.setObject(3, job); pstat.setObject(4, mgr); pstat.setObject(5, hiredate); pstat.setObject(6, salary); pstat.setObject(7, comm); pstat.setObject(8, deptno); //5执行 int count=pstat.executeUpdate(); if(count>0) { System.out.println("添加成功"); }else { System.out.println("添加失败"); } //6释放资源 pstat.close(); conn.close(); } }
-
抽取数据库工具类
package com.qf.utils; /** * 1 注册驱动 * 2 获取连接 * 3 释放资源 * 4 执行SQL 增删改 * @author wgy * */ import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class DbUtils { //驱动名称 static String driver="com.mysql.jdbc.Driver"; //url连接字符串 static String url="jdbc:mysql://localhost:3306/school"; //用户名 static String user="root"; //密码 static String password="root"; static { try { Class.forName(driver); } catch (ClassNotFoundException e) { System.out.println("注册驱动失败"); } } /** * 获取连接 * @return */ public static Connection getConnection() { try { return DriverManager.getConnection(url, user, password); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } /** * 释放资源 * @param rs * @param stat * @param conn */ public static void closeAll(ResultSet rs,Statement stat,Connection conn) { try { if(rs!=null) { rs.close(); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } try { if(stat!=null) { stat.close(); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } try { if(conn!=null) { conn.close(); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 执行命令 * @param sql insert int emp() values(?,?,?,?) * @param params */ public static int executeUpdate(String sql,Object... params) { try { Connection conn = getConnection(); PreparedStatement pstat = conn.prepareStatement(sql); if(params!=null) { for(int i=0;i<params.length;i++) { pstat.setObject(i+1, params[i]); } } int count=pstat.executeUpdate(); closeAll(null, pstat, conn); return count; } catch (Exception e) { e.printStackTrace(); } return 0; } }
-
小结
1 单元测试
2 jdbc介绍 :
Java Database Connectity java数据库连接技术
定义一套连接数据的规范和标准。
3 jdbc包含两个部分
JDBC API
JDBC 驱动程序
4 JDBC的使用步骤
1 导入jar包
2 注册驱动
3 获取连接
4 创建命令
5 执行命令,处理结果
6 释放资源
5 JDBC的api
Driver 驱动
DriverManager 驱动管理类
Connection 负责连接数据库
Statement 负责执行命令
ResultSet 封装结果集
PreparedStatment 预编译命令
5 数据库工具类
DbUtils.java
1 注册驱动
2 获取连接
3 释放资源
4 执行命令 (增删改 DDL)
5 执行查询(反射)
第八天 JDBC高级操作和事务
第一节 JDBC批处理
Statement批处理
-
1 注册驱动获取连接
-
2 使用createStatement()方法创建Statement对象。
-
3 使用setAutoCommit()将auto-commit设置为false 。(可选)
-
4 使用addBatch()方法在创建的语句对象上添加您喜欢的SQL语句到批处理中。
-
5 在创建的语句对象上使用executeBatch()方法执行所有SQL语句。
-
6 使用commit()方法提交所有更改。(可选)
-
7 释放资源
-
// Create statement object Statement stmt = conn.createStatement(); // Set auto-commit to false conn.setAutoCommit(false); // Create SQL statement String SQL = "INSERT INTO Employees (id, first, last, age) " + "VALUES(200,'Zia', 'Ali', 30)"; // Add above SQL statement in the batch. stmt.addBatch(SQL); // Create one more SQL statement String SQL = "INSERT INTO Employees (id, first, last, age) " + "VALUES(201,'Raj', 'Kumar', 35)"; // Add above SQL statement in the batch. stmt.addBatch(SQL); // Create one more SQL statement String SQL = "UPDATE Employees SET age = 35 " + "WHERE id = 100"; // Add above SQL statement in the batch. stmt.addBatch(SQL); // Create an int[] to hold returned values int[] count = stmt.executeBatch(); //Explicitly commit statements to apply changes conn.commit();
PrepareStatement批处理
-
使用占位符创建SQL语句。
-
使用prepareStatement() 方法创建PrepareStatement对象。
-
使用setAutoCommit()将auto-commit设置为false 。(可选)
-
使用addBatch()方法在创建的语句对象上添加您喜欢的SQL语句到批处理中。
-
在创建的语句对象上使用executeBatch()方法执行所有SQL语句。
-
最后,使用commit()方法提交所有更改。(可选)
-
// Create SQL statement String SQL = "INSERT INTO Employees (id, first, last, age) " + "VALUES(?, ?, ?, ?)"; // Create PrepareStatement object PreparedStatemen pstmt = conn.prepareStatement(SQL); //Set auto-commit to false conn.setAutoCommit(false); // Set the variables pstmt.setInt( 1, 400 ); pstmt.setString( 2, "Pappu" ); pstmt.setString( 3, "Singh" ); pstmt.setInt( 4, 33 ); // Add it to the batch pstmt.addBatch(); // Set the variables pstmt.setInt( 1, 401 ); pstmt.setString( 2, "Pawan" ); pstmt.setString( 3, "Singh" ); pstmt.setInt( 4, 31 ); // Add it to the batch pstmt.addBatch(); //add more batches //Create an int[] to hold returned values int[] count = stmt.executeBatch(); //Explicitly commit statements to apply changes conn.commit();
Statment批处理和PrepareStatment批处理区别: (1)Statment批处理可以添加不同Sql语句,而PrepareStatment只能添加一种sql语句 (2)PrepareStatment效率比Statment高,而且更安全。
第二节 JDBC操作二进制
-
setAsciiStream():**此方法用于提供大的ASCII值。
-
setCharacterStream():此方法用于提供大型UNICODE值。
-
setBinaryStream():此方法用于提供较大的二进制值。
-
XML文件的内容
<?xml version="1.0" encoding="UTF-8"?> <Employee> <id>100</id> <first>张</first> <last>无极</last> <Salary>10000</Salary> <Dob>18-08-1978</Dob> </Employee>
// Import required packages import java.sql.*; import java.io.*; import java.util.*; public class JDBCExample { // JDBC driver name and database URL static final String JDBC_DRIVER = "com.mysql.jdbc.Driver"; static final String DB_URL = "jdbc:mysql://localhost:3306/EMP"; // Database credentials static final String USER = "username"; static final String PASS = "password"; public static void main(String[] args) { Connection conn = null; PreparedStatement pstmt = null; Statement stmt = null; ResultSet rs = null; try{ // Register JDBC driver Class.forName("com.mysql.jdbc.Driver"); // Open a connection System.out.println("Connecting to database..."); conn = DriverManager.getConnection(DB_URL,USER,PASS); //Create a Statement object and build table stmt = conn.createStatement(); createXMLTable(stmt); //Open a FileInputStream File f = new File("XML_Data.xml"); long fileLength = f.length(); FileInputStream fis = new FileInputStream(f); //Create PreparedStatement and stream data String SQL = "INSERT INTO XML_Data VALUES (?,?)"; pstmt = conn.prepareStatement(SQL); pstmt.setInt(1,100); pstmt.setAsciiStream(2,fis,(int)fileLength); pstmt.execute(); //Close input stream fis.close(); // Do a query to get the row SQL = "SELECT Data FROM XML_Data WHERE id=100"; rs = stmt.executeQuery (SQL); // Get the first row if (rs.next ()){ //Retrieve data from input stream InputStream xmlInputStream = rs.getAsciiStream (1); int c; ByteArrayOutputStream bos = new ByteArrayOutputStream(); while (( c = xmlInputStream.read ()) != -1) bos.write(c); //Print results System.out.println(bos.toString()); } // Clean-up environment rs.close(); stmt.close(); pstmt.close(); conn.close(); }catch(SQLException se){ //Handle errors for JDBC se.printStackTrace(); }catch(Exception e){ //Handle errors for Class.forName e.printStackTrace(); }finally{ //finally block used to close resources try{ if(stmt!=null) stmt.close(); }catch(SQLException se2){ }// nothing we can do try{ if(pstmt!=null) pstmt.close(); }catch(SQLException se2){ }// nothing we can do try{ if(conn!=null) conn.close(); }catch(SQLException se){ se.printStackTrace(); }//end finally try }//end try System.out.println("Goodbye!"); }//end main public static void createXMLTable(Statement stmt) throws SQLException{ System.out.println("Creating XML_Data table..." ); //Create SQL Statement String streamingDataSql = "CREATE TABLE XML_Data " + "(id INTEGER, Data TEXT)"; //Drop table first if it exists. try{ stmt.executeUpdate("DROP TABLE IF EXISTS XML_Data"); //Build table. stmt.executeUpdate(streamingDataSql); }catch(SQLException se){ }// do nothing }//end createXMLTable }//end JDBCExample
package com.qf.day04; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.lang.ProcessBuilder.Redirect; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; /** * 把图片放入数据库 * @author wgy * */ public class Demo4 { public static void main(String[] args) throws Exception{ //write(); read(); } public static void write() throws Exception{ Class.forName("com.mysql.jdbc.Driver"); String url="jdbc:mysql://localhost:3306/school"; Connection conn=DriverManager.getConnection(url, "root", "root"); PreparedStatement pstat=conn.prepareStatement("insert into bigdata2(id,img) values(?,?)"); FileInputStream fis=new FileInputStream("d:\\图片\\003.jpg"); pstat.setInt(1, 1); pstat.setBinaryStream(2, fis); int count=pstat.executeUpdate(); System.out.println(count); pstat.close(); conn.close(); } public static void read() throws Exception{ Class.forName("com.mysql.jdbc.Driver"); String url="jdbc:mysql://localhost:3306/school"; Connection conn=DriverManager.getConnection(url, "root", "root"); PreparedStatement pstat=conn.prepareStatement("select * from bigdata2 where id=1"); ResultSet rs=pstat.executeQuery(); if(rs.next()) { int id=rs.getInt("id"); System.out.println(id); //处理图片 InputStream is=rs.getBinaryStream("img"); FileOutputStream fos=new FileOutputStream("d:\\haha.jpg"); byte[] buf=new byte[1024]; int len=0; while((len=is.read(buf))!=-1) { fos.write(buf,0,len); } fos.close(); is.close(); } rs.close(); pstat.close(); conn.close(); System.out.println("读取完成"); } }
小结
1 数据完整性 :数据的正确性。
实体完整性:
主键约束:不能重复,不能为为null
唯一约束: 不能重复 ,可以为null
自动增长: auto_increment, 默认从1 开始每次增长1
域完整性:
数据类型:
int
double
double(5,2)
decimal(5,2);
char 0-255
varchar 长度不固定
text
blob
date
datetime
timestamp
非空约束 not null
默认约束 default
引用完整性
外键约束
2 多表查询
2.1 表关系
一对多
一对一
多对多
2.2 查询
合并结果集
union 去掉重复
union all 包含重复
连接查询
直接连接(交叉连接)
内连接
传统写法
select *from emp ,dept where emp.deptno=dept.deptno;
标准写法
select *from emp inner join dept on emp.deptno=dept.deptno;
外连接
左外连接
select *from emp left outer join dept on emp.deptno=dept.deptno;
右外连接
select *from emp right outer join dept on emp.deptno=dept.deptno;
子查询:
where 子查询
from 子查询
子查询结果:
1 单行单列
2 多行单列
3 多行多列
2.3 导出导入
2.4 创建用户
create user zhangsan identified by '123';
授权
grant all on school.* to zhangsan
撤销权限
revoke all on scholl.* from zhangsan
第七天 JDBC概述和CRUD
第一节 单元测试
注意点:
测试类加后缀Test,测试方法加前缀test
第二节 JDBC的简介
JDBC核心组件
DriverManager: 此类管理数据库驱动程序列表。使用通信协议将来自java应用程序的连接请求与适当的数据库驱动程序匹配。
Driver:此接口处理与数据库服务器的通信,我们很少会直接与Driver对象进行交互。而是使用DriverManager对象来管理这种类型的对象。
Connection:该接口具有用于连接数据库的所有方法。连接对象表示通信上下文,数据库的所有通信仅通过连接对象。
Statement:使用从此接口创建的对象将SQL语句提交到数据库。除了执行存储过程之外,一些派生接口还接受参数。
ResultSet:在使用Statement对象执行SQL查询后,这些对象保存从数据库检索的数据。它作为一个迭代器,允许我们移动其数据。
SQLException:此类处理数据库应用程序中发生的任何异常。
第三节 JDBC初始
3.1 使用步骤
-
导入JDBC驱动包:**需要下载包含数据库编程所需的JDBC的jar包。
-
注册JDBC驱动程序:要求您初始化驱动程序,以便您可以打开与数据库的通信通道。
-
创建连接:需要使用DriverManager.getConnection()方法创建一个Connection对象,该对象表示与数据库的物理连接。
-
执行查询:需要使用类型为Statement的对象来构建和提交SQL语句到数据库。
-
从结果集中提取数据:需要使用相应的ResultSet.getXXX()方法从结果集中检索数据。
-
释放资源:需要明确地关闭所有数据库资源,而不依赖于JVM的垃圾收集。
3.2 注册驱动
-
第一种方式(推荐写法):Class.forName()
try { Class.forName("com.mysql.jdbc.Driver"); } catch(ClassNotFoundException ex) { System.out.println("Error: unable to load driver class!"); System.exit(1); }
-
第二种方式:是使用静态DriverManager.registerDriver()方法。
try { Driver myDriver = new com.mysql.jdbc.Driver(); DriverManager.registerDriver( myDriver ); } catch(ClassNotFoundException ex) { System.out.println("Error: unable to load driver class!"); System.exit(1); } * 1>驱动程序注册两次 * 2>java程序依赖mysql驱动包
3.3 获取连接
DriverManager.getConnection()方法
RDBMS | JDBC驱动程序名称 | 连接字符串格式 |
---|---|---|
MySQL的 | com.mysql.jdbc.Driver | jdbc:mysql://hostname:3306 / databaseName |
ORACLE | oracle.jdbc.driver.OracleDriver | jdbc:oracle:thin:@ hostname:port Number:databaseName |
DB2 | COM.ibm.db2.jdbc.net.DB2Driver | jdbc:db2:hostname:port Number / databaseName |
SYBASE | com.sybase.jdbc.SybDriver | jdbc:sybase:Tds: hostname:port Number / databaseName |
创建数据库连接对象
String URL = "jdbc:mysql://localhost:3306/emp"; String USER = "root"; String PASS = "root" Connection conn = DriverManager.getConnection(URL, USER, PASS);
第四节 JDBC执行SQL语句
-
Statement
-
boolean execute(String SQL)**:如果可以检索到ResultSet对象,则返回一个布尔值true; 否则返回false。使用此方法执行SQL DDL语句或需要使用真正的动态SQL时。
-
int executeUpdate(String SQL):返回受SQL语句执行影响的行数。使用此方法执行预期会影响多个行的SQL语句,例如INSERT,UPDATE或DELETE语句。
-
ResultSet executeQuery(String SQL):返回一个ResultSet对象。当您希望获得结果集时,请使用此方法,就像使用SELECT语句一样。
-
-
ResultSet
SELECT语句是从数据库中选择行并在结果集中查看行的标准方法。该java.sql.ResultSet中的接口表示结果集数据库查询。
ResultSet对象维护指向结果集中当前行的游标。术语“结果集”是指包含在ResultSet对象中的行和列数据。
如果没有指定任何ResultSet类型,您将自动获得一个TYPE_FORWARD_ONLY。
类型 描述 ResultSet.TYPE_FORWARD_ONLY 光标只能在结果集中向前移动。 ResultSet.TYPE_SCROLL_INSENSITIVE 光标可以向前和向后滚动,结果集对创建结果集后发生的数据库的其他更改不敏感。 ResultSet.TYPE_SCROLL_SENSITIVE。 光标可以向前和向后滚动,结果集对创建结果集之后发生的其他数据库所做的更改敏感。 --演示案例1:查询数据 public class JdbcDemo2 { public static void main(String[] args) { Connection connection=null; Statement stat=null; ResultSet rs=null; //2注册驱动 try { Class.forName("com.mysql.jdbc.Driver"); //3获取连接 connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/school", "root", "root"); //4创建命令(语句)对象 stat=connection.createStatement(); //执行命令查询 rs=stat.executeQuery("select ename,empno from emp"); //5处理结果 while(rs.next()){ // int empno=rs.getInt(1); // String empname=rs.getString(2); int empno=rs.getInt("empno"); String empname=rs.getString("ename"); System.out.println(empno+"...."+empname); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { if(rs!=null){ try { rs.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(stat!=null){ try { stat.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(connection!=null){ try { connection.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } } --演示案例2:添加数据 public class JdbcDemo3 { public static void main(String[] args) { Connection connection=null; Statement stat=null; //2 注册驱动 try { Class.forName("com.mysql.jdbc.Driver"); //3打开连接 connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/school", "root", "root"); //4创建命令并执行 stat=connection.createStatement(); int result=stat.executeUpdate("insert into dept(deptno,dname,loc) values(80,'市场部','天津')"); if(result>0){ System.out.println("添加成功"); }else{ System.out.println("添加失败"); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { if(stat!=null){ try { stat.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(connection!=null){ try { connection.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } } --演示案例3:更新数据 public class JdbcDemo4 { public static void main(String[] args) { Connection connection=null; Statement stat=null; //2 注册驱动 try { Class.forName("com.mysql.jdbc.Driver"); //3打开连接 connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/school", "root", "root"); //4创建命令并执行 stat=connection.createStatement(); int result=stat.executeUpdate("update dept set loc='内蒙' where deptno=80"); if(result>0){ System.out.println("更新成功"); }else{ System.out.println("更新失败"); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { if(stat!=null){ try { stat.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(connection!=null){ try { connection.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } } --演示案例4:删除 public class JdbcDemo5 { public static void main(String[] args) { Connection connection=null; Statement stat=null; //2 注册驱动 try { Class.forName("com.mysql.jdbc.Driver"); //3打开连接 connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/school", "root", "root"); //4创建命令并执行 stat=connection.createStatement(); int result=stat.executeUpdate("delete from dept where deptno=80"); if(result>0){ System.out.println("删除成功"); }else{ System.out.println("删除失败"); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { if(stat!=null){ try { stat.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(connection!=null){ try { connection.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } } --演示案例5:实现用户登录 数据库myschool 表 :user create table user( • id int primary key auto_increment, • username varchar(18) not null, • password varchar(16) not null, # 密文 123456 • phone varchar(11) ); insert into user (username,password,phone) values('zhangsan','123456','13898765678'); insert into user (username,password,phone) values('lisi','6666','17898879988'); package com.qf.day03; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Scanner; import javax.management.remote.rmi.RMIJRMPServerImpl; /* * 实现用户登录 */ public class JdbcDemo1 { public static void main(String[] args) { Scanner input=new Scanner(System.in); System.out.println("请输入用户名"); String username=input.nextLine(); System.out.println("请输入密码"); String pass=input.nextLine(); //连接对象 Connection connection=null; //命令对象 Statement stat=null; //结果集 ResultSet rs=null; //1 注册驱动 try { Class.forName("com.mysql.jdbc.Driver"); //2获取连接 connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/school", "root", "root"); //3创建命令 stat=connection.createStatement(); //4执行命命令 select * from user where username='zhangsan' and password='123456'; rs=stat.executeQuery("select * from user where username='"+username+"' and password='"+pass+"'"); if(rs.next()){ //有数据 System.out.println("登录成功"); }else{ System.out.println("账号或密码错误"); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { if(rs!=null){ try { rs.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(stat!=null){ try { stat.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(connection!=null){ try { connection.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }
-
SQL注入
就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意的)SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。比如先前的很多影视网站泄露VIP会员密码大多就是通过WEB表单递交查询字符暴出的,这类表单特别容易受到SQL注入式攻击。
-
PreparedStatement
作用:1预编译,效率高 2 安全,避免SQL注入
PreparedStatement pstmt = null; try { String SQL = "Update Employees SET age = ? WHERE id = ?"; pstmt = conn.prepareStatement(SQL); . . . } catch (SQLException e) { . . . } finally { . . . }
练习
package com.qf.day03; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Scanner; /** * 使用PreparedStatement实现emp表的数据添加 * @author wgy * */ public class Demo6 { public static void main(String[] args) throws Exception{ Scanner input=new Scanner(System.in); System.out.println("请输入员工编号"); int empno=input.nextInt(); System.out.println("请输入员工姓名"); String ename=input.next(); System.out.println("请输入工作"); String job=input.next(); System.out.println("请输入经理的编号"); int mgr=input.nextInt(); System.out.println("请输入入职日期"); String date=input.next(); SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd"); Date hiredate=sdf.parse(date); System.out.println("请输入工资"); double salary=input.nextDouble(); System.out.println("请输入奖金"); double comm=input.nextDouble(); System.out.println("请输入部门"); int deptno=input.nextInt(); //1注册驱动 Class.forName("com.mysql.jdbc.Driver"); //2获取连接 String url="jdbc:mysql:///school"; Connection conn=DriverManager.getConnection(url, "root", "root"); //3创建命令 PreparedStatement pstat=conn.prepareStatement("insert into emp(empno,ename,job,mgr,hiredate,sal,comm,deptno) values(?,?,?,?,?,?,?,?);"); //4参数赋值 pstat.setObject(1, empno); pstat.setObject(2, ename); pstat.setObject(3, job); pstat.setObject(4, mgr); pstat.setObject(5, hiredate); pstat.setObject(6, salary); pstat.setObject(7, comm); pstat.setObject(8, deptno); //5执行 int count=pstat.executeUpdate(); if(count>0) { System.out.println("添加成功"); }else { System.out.println("添加失败"); } //6释放资源 pstat.close(); conn.close(); } }
-
抽取数据库工具类
package com.qf.utils; /** * 1 注册驱动 * 2 获取连接 * 3 释放资源 * 4 执行SQL 增删改 * @author wgy * */ import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class DbUtils { //驱动名称 static String driver="com.mysql.jdbc.Driver"; //url连接字符串 static String url="jdbc:mysql://localhost:3306/school"; //用户名 static String user="root"; //密码 static String password="root"; static { try { Class.forName(driver); } catch (ClassNotFoundException e) { System.out.println("注册驱动失败"); } } /** * 获取连接 * @return */ public static Connection getConnection() { try { return DriverManager.getConnection(url, user, password); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } /** * 释放资源 * @param rs * @param stat * @param conn */ public static void closeAll(ResultSet rs,Statement stat,Connection conn) { try { if(rs!=null) { rs.close(); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } try { if(stat!=null) { stat.close(); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } try { if(conn!=null) { conn.close(); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 执行命令 * @param sql insert int emp() values(?,?,?,?) * @param params */ public static int executeUpdate(String sql,Object... params) { try { Connection conn = getConnection(); PreparedStatement pstat = conn.prepareStatement(sql); if(params!=null) { for(int i=0;i<params.length;i++) { pstat.setObject(i+1, params[i]); } } int count=pstat.executeUpdate(); closeAll(null, pstat, conn); return count; } catch (Exception e) { e.printStackTrace(); } return 0; } }
小结
1 单元测试
2 jdbc介绍 :
Java Database Connectity java数据库连接技术
定义一套连接数据的规范和标准。
3 jdbc包含两个部分
JDBC API
JDBC 驱动程序
4 JDBC的使用步骤
1 导入jar包
2 注册驱动
3 获取连接
4 创建命令
5 执行命令,处理结果
6 释放资源
5 JDBC的api
Driver 驱动
DriverManager 驱动管理类
Connection 负责连接数据库
Statement 负责执行命令
ResultSet 封装结果集
PreparedStatment 预编译命令
5 数据库工具类
DbUtils.java
1 注册驱动
2 获取连接
3 释放资源
4 执行命令 (增删改 DDL)
5 执行查询(反射)
第八天 JDBC高级操作和事务
第一节 JDBC批处理
Statement批处理
-
1 注册驱动获取连接
-
2 使用createStatement()方法创建Statement对象。
-
3 使用setAutoCommit()将auto-commit设置为false 。(可选)
-
4 使用addBatch()方法在创建的语句对象上添加您喜欢的SQL语句到批处理中。
-
5 在创建的语句对象上使用executeBatch()方法执行所有SQL语句。
-
6 使用commit()方法提交所有更改。(可选)
-
7 释放资源
// Create statement object Statement stmt = conn.createStatement(); // Set auto-commit to false conn.setAutoCommit(false); // Create SQL statement String SQL = "INSERT INTO Employees (id, first, last, age) " + "VALUES(200,'Zia', 'Ali', 30)"; // Add above SQL statement in the batch. stmt.addBatch(SQL); // Create one more SQL statement String SQL = "INSERT INTO Employees (id, first, last, age) " + "VALUES(201,'Raj', 'Kumar', 35)"; // Add above SQL statement in the batch. stmt.addBatch(SQL); // Create one more SQL statement String SQL = "UPDATE Employees SET age = 35 " + "WHERE id = 100"; // Add above SQL statement in the batch. stmt.addBatch(SQL); // Create an int[] to hold returned values int[] count = stmt.executeBatch(); //Explicitly commit statements to apply changes conn.commit();
PrepareStatement批处理
-
使用占位符创建SQL语句。
-
使用prepareStatement() 方法创建PrepareStatement对象。
-
使用setAutoCommit()将auto-commit设置为false 。(可选)
-
使用addBatch()方法在创建的语句对象上添加您喜欢的SQL语句到批处理中。
-
在创建的语句对象上使用executeBatch()方法执行所有SQL语句。
-
最后,使用commit()方法提交所有更改。(可选)
// Create SQL statement String SQL = "INSERT INTO Employees (id, first, last, age) " + "VALUES(?, ?, ?, ?)"; // Create PrepareStatement object PreparedStatemen pstmt = conn.prepareStatement(SQL); //Set auto-commit to false conn.setAutoCommit(false); // Set the variables pstmt.setInt( 1, 400 ); pstmt.setString( 2, "Pappu" ); pstmt.setString( 3, "Singh" ); pstmt.setInt( 4, 33 ); // Add it to the batch pstmt.addBatch(); // Set the variables pstmt.setInt( 1, 401 ); pstmt.setString( 2, "Pawan" ); pstmt.setString( 3, "Singh" ); pstmt.setInt( 4, 31 ); // Add it to the batch pstmt.addBatch(); //add more batches //Create an int[] to hold returned values int[] count = stmt.executeBatch(); //Explicitly commit statements to apply changes conn.commit();
Statment批处理和PrepareStatment批处理区别: (1)Statment批处理可以添加不同Sql语句,而PrepareStatment只能添加一种sql语句 (2)PrepareStatment效率比Statment高,而且更安全。
第二节 JDBC操作二进制
-
setAsciiStream():**此方法用于提供大的ASCII值。
-
setCharacterStream():此方法用于提供大型UNICODE值。
-
setBinaryStream():此方法用于提供较大的二进制值。
XML文件的内容
<?xml version="1.0" encoding="UTF-8"?> <Employee> <id>100</id> <first>张</first> <last>无极</last> <Salary>10000</Salary> <Dob>18-08-1978</Dob> </Employee>
// Import required packages import java.sql.*; import java.io.*; import java.util.*; public class JDBCExample { // JDBC driver name and database URL static final String JDBC_DRIVER = "com.mysql.jdbc.Driver"; static final String DB_URL = "jdbc:mysql://localhost:3306/EMP"; // Database credentials static final String USER = "username"; static final String PASS = "password"; public static void main(String[] args) { Connection conn = null; PreparedStatement pstmt = null; Statement stmt = null; ResultSet rs = null; try{ // Register JDBC driver Class.forName("com.mysql.jdbc.Driver"); // Open a connection System.out.println("Connecting to database..."); conn = DriverManager.getConnection(DB_URL,USER,PASS); //Create a Statement object and build table stmt = conn.createStatement(); createXMLTable(stmt); //Open a FileInputStream File f = new File("XML_Data.xml"); long fileLength = f.length(); FileInputStream fis = new FileInputStream(f); //Create PreparedStatement and stream data String SQL = "INSERT INTO XML_Data VALUES (?,?)"; pstmt = conn.prepareStatement(SQL); pstmt.setInt(1,100); pstmt.setAsciiStream(2,fis,(int)fileLength); pstmt.execute(); //Close input stream fis.close(); // Do a query to get the row SQL = "SELECT Data FROM XML_Data WHERE id=100"; rs = stmt.executeQuery (SQL); // Get the first row if (rs.next ()){ //Retrieve data from input stream InputStream xmlInputStream = rs.getAsciiStream (1); int c; ByteArrayOutputStream bos = new ByteArrayOutputStream(); while (( c = xmlInputStream.read ()) != -1) bos.write(c); //Print results System.out.println(bos.toString()); } // Clean-up environment rs.close(); stmt.close(); pstmt.close(); conn.close(); }catch(SQLException se){ //Handle errors for JDBC se.printStackTrace(); }catch(Exception e){ //Handle errors for Class.forName e.printStackTrace(); }finally{ //finally block used to close resources try{ if(stmt!=null) stmt.close(); }catch(SQLException se2){ }// nothing we can do try{ if(pstmt!=null) pstmt.close(); }catch(SQLException se2){ }// nothing we can do try{ if(conn!=null) conn.close(); }catch(SQLException se){ se.printStackTrace(); }//end finally try }//end try System.out.println("Goodbye!"); }//end main public static void createXMLTable(Statement stmt) throws SQLException{ System.out.println("Creating XML_Data table..." ); //Create SQL Statement String streamingDataSql = "CREATE TABLE XML_Data " + "(id INTEGER, Data TEXT)"; //Drop table first if it exists. try{ stmt.executeUpdate("DROP TABLE IF EXISTS XML_Data"); //Build table. stmt.executeUpdate(streamingDataSql); }catch(SQLException se){ }// do nothing }//end createXMLTable }//end JDBCExample
package com.qf.day04; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.lang.ProcessBuilder.Redirect; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; /** * 把图片放入数据库 * @author wgy * */ public class Demo4 { public static void main(String[] args) throws Exception{ //write(); read(); } public static void write() throws Exception{ Class.forName("com.mysql.jdbc.Driver"); String url="jdbc:mysql://localhost:3306/school"; Connection conn=DriverManager.getConnection(url, "root", "root"); PreparedStatement pstat=conn.prepareStatement("insert into bigdata2(id,img) values(?,?)"); FileInputStream fis=new FileInputStream("d:\\图片\\003.jpg"); pstat.setInt(1, 1); pstat.setBinaryStream(2, fis); int count=pstat.executeUpdate(); System.out.println(count); pstat.close(); conn.close(); } public static void read() throws Exception{ Class.forName("com.mysql.jdbc.Driver"); String url="jdbc:mysql://localhost:3306/school"; Connection conn=DriverManager.getConnection(url, "root", "root"); PreparedStatement pstat=conn.prepareStatement("select * from bigdata2 where id=1"); ResultSet rs=pstat.executeQuery(); if(rs.next()) { int id=rs.getInt("id"); System.out.println(id); //处理图片 InputStream is=rs.getBinaryStream("img"); FileOutputStream fos=new FileOutputStream("d:\\haha.jpg"); byte[] buf=new byte[1024]; int len=0; while((len=is.read(buf))!=-1) { fos.write(buf,0,len); } fos.close(); is.close(); } rs.close(); pstat.close(); conn.close(); System.out.println("读取完成"); } }
第三节 数据库事务
-
概述
一组要么同时执行成功,要么同时失败的SQL语句。是数据库操作的一个不能分割执行单元。
事务开始于
-
连接到数据库上,并执行一条DML语句insert、update或delete
-
前一个事务结束后,又输入了另一条DML语句
事务结束于
-
执行commit或rollback语句。
-
执行一条DDL语句,例如create table语句,在这种情况下,会自动执行commit语句。
-
执行一条DDL语句,例如grant语句,在这种情况下,会自动执行commit。
-
断开与数据库的连接
-
执行了一条DML语句,该语句却失败了,在这种情况中,会为这个无效的DML语句执行rollback语句。
3.2 事务的四大特点
(ACID)
-
Atomicity(原子性)
表示一个事务内的所有操作是一个整体,要么全部成功,要么全部失败
-
Consistency(一致性)
表示一个事务内有一个操作失败时,所有的更改过的数据都必须回滚到修改前状态
-
Isolation(隔离性)
事务查看数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看中间状态的数据。
-
Durability(持久性)
持久性事务完成之后,它对于系统的影响是永久性的。
案例:
CREATE TABLE account( id INT PRIMARY KEY, NAME VARCHAR(20) NOT NULL, money DOUBLE(10,2) ) public static void main(String[] args) { Connection connection=null; PreparedStatement pstat1=null; PreparedStatement pstat2=null; //1注册驱动 try { Class.forName("com.mysql.jdbc.Driver"); //2获取连接 connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/school", "root", "root"); //3创建命令 //3.1开启事务 ,设置事务自动提交为false connection.setAutoCommit(false); pstat1=connection.prepareStatement("update account set money=money-1000 where name='张莎强'"); pstat1.executeUpdate(); //int c=10/0; pstat2=connection.prepareStatement("update account set money=money+1000 where name='小苍'"); pstat2.executeUpdate(); System.out.println("转账成功..."); //3.2提交事务 connection.commit(); } catch (Exception e) { System.out.println("出现异常"); try { connection.rollback();//出现问题,要回滚(撤销事务做过的修改) connection.commit();//可加也不不加 } catch (SQLException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } }finally { if(pstat1!=null){ try { pstat1.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(pstat2!=null){ try { pstat2.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(connection!=null){ try { connection.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
Mysql支持的事务语句
#开启事务 START TRANSACTION; # connection.setAutoCommit(false); UPDATE account SET money=money-1000 WHERE id=1; UPDATE account SET money=money+1000 WHERE id=2; #提交事务 COMMIT;#connection.commit(); #回滚 ROLLBACK; #connection.rollback();
-
-
事务隔离级别
Read Uncommitted(读取未提交内容)
在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)。
Read Committed(读取提交内容)
这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别出现不可重复读(Nonrepeatable Read)问题,因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。
Repeatable Read 可重读
这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读(Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻读” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。
Serializable 可串行化 这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。效率最低的。
这四种隔离级别采取不同的锁类型来实现,若读取的是同一个数据的话,就容易发生问题。
-
脏读(Dirty Read):某个事务已更新一份数据未提交前,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的。
#修改事务的隔离级别: SET [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SERIALIZABLE] #查看事务隔离级别 SELECT @@tx_isolation;
-
不可重复读(Non-repeatable read):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据。
# A方 买 本伟 SELECT @@tx_isolation; START TRANSACTION; UPDATE account SET money=money-2000 WHERE id=1; UPDATE account SET money=money+2000 WHERE id=2; COMMIT; ROLLBACK; START TRANSACTION; UPDATE account SET money=money+1000 WHERE id=2; COMMIT; # B方 卖 郑帅 #(修改隔离级别) SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; #查看隔离级别 SELECT @@tx_isolation; SELECT *FROM account; #发货 #修改隔离级别 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT *FROM account; #不可重复读 START TRANSACTION; SELECT SUM(money) FROM account; SELECT SUM(money) FROM account; SELECT SUM(money) FROM account; COMMIT; #再次修改隔离级别 SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; START TRANSACTION; SELECT SUM(money) FROM account; SELECT SUM(money) FROM account; SELECT SUM(money) FROM account; COMMIT;
幻读(Phantom Read):在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。但是InnoDB存储引擎通过多版本并发控制机制解决了该问题。
-
JDBC中事务应用
setAutoCommit()**方法。如果将boolean false传递给setAutoCommit(),则关闭自动提交。我们可以传递一个布尔值true来重新打开它。
-
事务的提交和回滚
conn.commit( ); conn.rollback( );
try{ //开启事务 conn.setAutoCommit(false); Statement stmt = conn.createStatement(); String SQL = "INSERT INTO Employees " + "VALUES (106, 20, 'Rita', 'Tez')"; stmt.executeUpdate(SQL); //有可能出现异常 String SQL = "INSERT IN Employees " + "VALUES (107, 22, 'Sita', 'Singh')"; stmt.executeUpdate(SQL); // 没有错误提交 conn.commit(); }catch(SQLException se){ //出现错误回滚 conn.rollback(); conn.commit(); }
-
Savepoint
-
setSavepoint(String savepointName):**定义新的保存点。它还返回一个Savepoint对象。
-
releaseSavepoint(Savepoint savepointName):删除保存点。请注意,它需要一个Savepoint对象作为参数。此对象通常是由setSavepoint()方法生成的保存点。
public static void main(String[] args) { Connection conn = null; Statement stmt = null; Savepoint savepoint1 = null; try { Class.forName("com.mysql.jdbc.Driver"); conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/school", "root", "root"); // Assume a valid connection object conn conn.setAutoCommit(false); stmt = conn.createStatement(); // set a Savepoint String SQL = "INSERT INTO Employees " + "VALUES (106, 20, 'Rita', 'Tez');"; stmt.executeUpdate(SQL); savepoint1 = conn.setSavepoint("Savepoint1"); // Submit a malformed SQL statement that breaks SQL = "INSERT IN Employees " + "VALUES (107, 22, 'Sita', 'Tez')"; stmt.executeUpdate(SQL); // If there is no error, commit the changes. conn.commit(); System.out.println("执行成功"); } catch (Exception se) { // If there is any error. try { se.printStackTrace(); conn.rollback(savepoint1); conn.commit(); System.out.println("回滚"); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
-
小结
1 批处理
Statement实现批处理
stat.addBatch(sql);// insert update delete
stat.executeBatch();
PreparetedStatement
pstat.addBatch();
pstat.executeBatch();
pstat.clearBatch();
2 jdbc操作大数据
大文本 tinytext text mediumtext longtext
setAsciiStream();
setCharacterStream();
setBinaryStream();
二进制tinyblob blob mediunblob longblob
setBinaryStream();
3 事务:一组要么同时执行成功,要么同时失败的SQL语句。是数据库操作的一个不能分割执行单元。
四个特性:
原子性 A: 不能分割
一致性 C:事务执行前后保持一致
隔离型 I: 事务与事务之间对数据的读取控制
持久性 D:事务提交或回滚之后,永久保存数据库。
4 修改隔离级别
#修改事务的隔离级别: SET [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SERIALIZABLE] #查看事务隔离级别 SELECT @@tx_isolation;
java代码更改隔离级别
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
5 保存点
SavePoint
第九天 数据库连接池和DBUtils使用
第一节 工具类封装,DAO模式和自定义连接池
-
DAO设计模式(Database Access Object 数据库访问对象)
-
DAO模式的组成部分
1 DAO接口(主要包 添加 修改 查询 删除方法)
2 DAO实现类
3 实体类 (domain、beans、entity、pojo、model)
PO (VO)(Persistent Object, Value Object)
VO (View Object)
DTO (Data Transfer Object)
--作用:用在数据访问代码和业务逻辑代码之间通过实体类来传输数据
--实体类特征:
◦属性一般使用private修饰
◦提供public修饰的getter/setter方法
◦实体类提供无参构造方法,根据业务提供有参构造
◦实现java.io.Serializable接口,支持序列化机制
4 数据库连接和关闭工具类
设计的包名 :
domain 存放实体类
utils 存放工具类
dao 存放接口
dao.impl 存放实现类
使用DAO设计模式实现emp表的查询、添加、删除、修改
-
自定义实现连接池
package Day20190827.Day9连接池和Dbutils.utils; import java.beans.PropertyDescriptor; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Method; import java.sql.*; import java.util.ArrayList; import java.util.List; import java.util.Properties; /** * @Auther: xbh * @Date: 2019/8/26 14:28 * @Description: * 四个功能 * 1、注册驱动(一次) * 2、获取连接 * 3、释放资源 * 4、执行sql语句(增删改) */ public class DbUtils { private static String driver; private static String url; private static String user; private static String password; //注册驱动(一次) static { // driver="com.mysql.jdbc.Driver"; // url="jdbc:mysql://localhost:3306/day20190824?useSSL=true&characterEncoding=utf8"; // user="root"; // password="123456"; //读取文件 Properties properties = new Properties(); FileInputStream fis = null; InputStream is = null; try { /*fis = new FileInputStream("src\\db.properties"); properties.load(fis); driver=properties.getProperty("driver");*/ //读取文件2,使用类加载器加载配置文件 is = DbUtils.class.getClassLoader().getResourceAsStream("db.properties"); properties.load(is); driver=properties.getProperty("driver"); url=properties.getProperty("url"); user=properties.getProperty("user"); password=properties.getProperty("password"); Class.forName(driver); } catch (ClassNotFoundException e) { e.printStackTrace(); System.out.println("注册驱动失败"); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if(fis!=null) { fis.close(); } if(is!=null){ is.close(); } } catch (IOException e) { e.printStackTrace(); } } } //获取连接 public static Connection getConnection(){ try { return DriverManager.getConnection(url, user, password); } catch (SQLException e) { e.printStackTrace(); } return null; } //释放资源 public static void closeAll(Connection conn, Statement stat, ResultSet rs){ if(rs!=null){ try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if(stat!=null){ try { stat.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn!=null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } //sql语句 public static int executeUpdate(String sql, Object...params){ Connection conn = getConnection(); PreparedStatement pstat = null; try { pstat = conn.prepareStatement(sql); //设置参数 if(params!=null){ for (int i = 0; i < params.length; i++) { pstat.setObject(i+1, params[i]); } } return pstat.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); }finally { closeAll(conn,pstat,null); } return -1; } //返回list集合的方法 public static <T> List<T> findList(String sql,Class<T> class1, Object...params){ List<T> list = new ArrayList<>(); //从数据库查询数据 Connection conn = null; PreparedStatement pstat = null; ResultSet rs = null; try{ //获取连接 conn = getConnection(); //获取执行 pstat = conn.prepareStatement(sql); //进行执行判断 if(params != null){ for (int i = 0; i < params.length; i++) { pstat.setObject(i+1, params[i]); } } //执行语句 rs = pstat.executeQuery(); //获得表头 ResultSetMetaData metaData = rs.getMetaData(); while (rs.next()){ //获得对象 T t = convertToObject(metaData, rs, class1); list.add(t); } } catch (Exception e) { e.printStackTrace(); } finally { closeAll(conn, pstat, rs); } return list; } //返回单个对象的方法 public static <T> T findSingle(String sql, Class<T> class1, Object...params){ T t = null; //从数据库查询数据 Connection conn = null; PreparedStatement pstat = null; ResultSet rs = null; try{ conn = getConnection(); pstat = conn.prepareStatement(sql); if(params != null){ for (int i = 0; i < params.length; i++) { pstat.setObject(i+1, params[i]); } } rs = pstat.executeQuery(); ResultSetMetaData metaData = rs.getMetaData(); if (rs.next()){ t = convertToObject(metaData, rs, class1); } } catch (Exception e) { e.printStackTrace(); } finally { closeAll(conn, pstat, rs); } return t; } public static <T> T convertToObject(ResultSetMetaData metaData, ResultSet rs, Class<T> class1){ try { //映射对象 T t = class1.newInstance(); for (int i = 0; i < metaData.getColumnCount(); i++) { //获得表头 String columnLabel = metaData.getColumnLabel(i + 1); //获得表头下的数据 Object value = rs.getObject(columnLabel);//empno ename try{ //内省解析属性描述符 PropertyDescriptor pd = new PropertyDescriptor(columnLabel, class1); if (pd != null) {//属性描述符不空 //获取set方法 Method writeMethod = pd.getWriteMethod();//setEmpno setEname //加入数据到对象 writeMethod.invoke(t, value); } }catch (Exception e){ continue; } } //返回对象 return t; } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } return null; } }
第二节DBCP连接池
-
配置文件
#连接设置 driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/day20190824?useSSL=true&characterEncoding=utf8 username=root password=123456 #<!-- 初始化连接 --> initialSize=10 #最大连接数量 maxTotal=50 #<!-- 最大空闲连接 --> maxIdle=20 #<!-- 最小空闲连接 --> minIdle=5 #<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 --> maxWaitMillis=5000
-
连接池
package Day20190827.Day9连接池和Dbutils.utils; import org.apache.commons.dbcp2.BasicDataSource; import org.apache.commons.dbcp2.BasicDataSourceFactory; import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.sql.*; import java.util.ArrayList; import java.util.List; import java.util.Properties; /** * @Auther: xbh * @Date: 2019/8/26 14:28 * @Description: * 四个功能 * 1、注册驱动(一次) * 2、获取连接 * 3、释放资源 * 4、执行sql语句(增删改) */ public class DbUtils_DBCP { private static String driver; private static String url; private static String user; private static String password; private static BasicDataSource dataSource = null; //注册驱动(一次) static { Properties properties = new Properties(); InputStream resourceAsStream = DbUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcp.properties"); try { properties.load(resourceAsStream); dataSource = BasicDataSourceFactory.createDataSource(properties); } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } /*dataSource = new BasicDataSource(); //设置四个基本属性 dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://localhost:3306/day20190824?useSSL=true&characterEncoding=utf8"); dataSource.setUsername("root"); dataSource.setPassword("123456"); //设置初始大小 dataSource.setInitialSize(10); //设置最大个数 dataSource.setMaxTotal(50); //设置最大空闲连接 dataSource.setMaxIdle(10); //设置最小空闲连接 dataSource.setMinIdle(5); //设置超时时间 dataSource.setMaxWaitMillis(5000);*/ } //获取连接 public static Connection getConnection(){ try { return dataSource.getConnection(); } catch (SQLException e) { e.printStackTrace(); } return null; } //释放资源 public static void closeAll(Connection conn, Statement stat, ResultSet rs){ if(rs!=null){ try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if(stat!=null){ try { stat.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn!=null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } //sql语句 public static int executeUpdate(String sql, Object...params){ Connection conn = getConnection(); PreparedStatement pstat = null; try { pstat = conn.prepareStatement(sql); //设置参数 if(params!=null){ for (int i = 0; i < params.length; i++) { pstat.setObject(i+1, params[i]); } } return pstat.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); }finally { closeAll(conn,pstat,null); } return -1; } //返回list集合的方法 public static <T> List<T> findList(String sql,Class<T> class1, Object...params){ List<T> list = new ArrayList<>(); //从数据库查询数据 Connection conn = null; PreparedStatement pstat = null; ResultSet rs = null; try{ //获取连接 conn = getConnection(); //获取执行 pstat = conn.prepareStatement(sql); //进行执行判断 if(params != null){ for (int i = 0; i < params.length; i++) { pstat.setObject(i+1, params[i]); } } //执行语句 rs = pstat.executeQuery(); //获得表头 ResultSetMetaData metaData = rs.getMetaData(); while (rs.next()){ //获得对象 T t = convertToObject(metaData, rs, class1); list.add(t); } } catch (Exception e) { e.printStackTrace(); } finally { closeAll(conn, pstat, rs); } return list; } //返回单个对象的方法 public static <T> T findSingle(String sql, Class<T> class1, Object...params){ T t = null; //从数据库查询数据 Connection conn = null; PreparedStatement pstat = null; ResultSet rs = null; try{ conn = getConnection(); pstat = conn.prepareStatement(sql); if(params != null){ for (int i = 0; i < params.length; i++) { pstat.setObject(i+1, params[i]); } } rs = pstat.executeQuery(); ResultSetMetaData metaData = rs.getMetaData(); if (rs.next()){ t = convertToObject(metaData, rs, class1); } } catch (Exception e) { e.printStackTrace(); } finally { closeAll(conn, pstat, rs); } return t; } public static <T> T convertToObject(ResultSetMetaData metaData, ResultSet rs, Class<T> class1){ try { //映射对象 T t = class1.newInstance(); for (int i = 0; i < metaData.getColumnCount(); i++) { //获得表头 String columnLabel = metaData.getColumnLabel(i + 1); //获得表头下的数据 Object value = rs.getObject(columnLabel);//empno ename try{ //内省解析属性描述符 PropertyDescriptor pd = new PropertyDescriptor(columnLabel, class1); if (pd != null) {//属性描述符不空 //获取set方法 Method writeMethod = pd.getWriteMethod();//setEmpno setEname //加入数据到对象 writeMethod.invoke(t, value); } }catch (Exception e){ continue; } } //返回对象 return t; } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } return null; } }
第三节 C3P0连接池
-
配置文件
c3p0.driverClass=com.mysql.jdbc.Driver c3p0.jdbcUrl=jdbc:mysql://localhost:3306/day20190824?useSSL=true&characterEncoding=utf8 c3p0.user=root c3p0.password=123456 c3p0.acquireIncrement=5 c3p0.initialPoolSize=20 c3p0.minPoolSize=10 c3p0.maxPoolSize=40
-
连接池
package Day20190827.Day9连接池和Dbutils.utils; import com.mchange.v2.c3p0.ComboPooledDataSource; import org.apache.commons.dbcp2.BasicDataSource; import org.apache.commons.dbcp2.BasicDataSourceFactory; import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.sql.*; import java.util.ArrayList; import java.util.List; import java.util.Properties; /** * @Auther: xbh * @Date: 2019/8/26 14:28 * @Description: * 四个功能 * 1、注册驱动(一次) * 2、获取连接 * 3、释放资源 * 4、执行sql语句(增删改) */ public class DbUtils_c3p0 { private static ComboPooledDataSource dataSource = null; //注册驱动(一次) static { try{ //自动加载,不用引用,但是配置文件不能改 dataSource = new ComboPooledDataSource(); }catch (Exception e){ e.printStackTrace(); } } //获取连接 public static Connection getConnection(){ try { return dataSource.getConnection(); } catch (SQLException e) { e.printStackTrace(); } return null; } //释放资源 public static void closeAll(Connection conn, Statement stat, ResultSet rs){ if(rs!=null){ try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if(stat!=null){ try { stat.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn!=null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } //sql语句 public static int executeUpdate(String sql, Object...params){ Connection conn = getConnection(); PreparedStatement pstat = null; try { pstat = conn.prepareStatement(sql); //设置参数 if(params!=null){ for (int i = 0; i < params.length; i++) { pstat.setObject(i+1, params[i]); } } return pstat.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); }finally { closeAll(conn,pstat,null); } return -1; } //返回list集合的方法 public static <T> List<T> findList(String sql,Class<T> class1, Object...params){ List<T> list = new ArrayList<>(); //从数据库查询数据 Connection conn = null; PreparedStatement pstat = null; ResultSet rs = null; try{ //获取连接 conn = getConnection(); //获取执行 pstat = conn.prepareStatement(sql); //进行执行判断 if(params != null){ for (int i = 0; i < params.length; i++) { pstat.setObject(i+1, params[i]); } } //执行语句 rs = pstat.executeQuery(); //获得表头 ResultSetMetaData metaData = rs.getMetaData(); while (rs.next()){ //获得对象 T t = convertToObject(metaData, rs, class1); list.add(t); } } catch (Exception e) { e.printStackTrace(); } finally { closeAll(conn, pstat, rs); } return list; } //返回单个对象的方法 public static <T> T findSingle(String sql, Class<T> class1, Object...params){ T t = null; //从数据库查询数据 Connection conn = null; PreparedStatement pstat = null; ResultSet rs = null; try{ conn = getConnection(); pstat = conn.prepareStatement(sql); if(params != null){ for (int i = 0; i < params.length; i++) { pstat.setObject(i+1, params[i]); } } rs = pstat.executeQuery(); ResultSetMetaData metaData = rs.getMetaData(); if (rs.next()){ t = convertToObject(metaData, rs, class1); } } catch (Exception e) { e.printStackTrace(); } finally { closeAll(conn, pstat, rs); } return t; } public static <T> T convertToObject(ResultSetMetaData metaData, ResultSet rs, Class<T> class1){ try { //映射对象 T t = class1.newInstance(); for (int i = 0; i < metaData.getColumnCount(); i++) { //获得表头 String columnLabel = metaData.getColumnLabel(i + 1); //获得表头下的数据 Object value = rs.getObject(columnLabel);//empno ename try{ //内省解析属性描述符 PropertyDescriptor pd = new PropertyDescriptor(columnLabel, class1); if (pd != null) {//属性描述符不空 //获取set方法 Method writeMethod = pd.getWriteMethod();//setEmpno setEname //加入数据到对象 writeMethod.invoke(t, value); } }catch (Exception e){ continue; } } //返回对象 return t; } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } return null; } }
第四节 Druid连接池
-
配置文件
#连接设置 driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/day20190824?useSSL=true&characterEncoding=utf8 username=root password=123456 #<!-- 初始化连接 --> initialSize=10 #最大连接数量 maxActive=50 #<!-- 最小空闲连接 --> minIdle=5 #<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 --> maxWait=5000
-
连接池
package Day20190827.Day9连接池和Dbutils.utils; import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.pool.DruidDataSourceFactory; import com.mchange.v2.c3p0.ComboPooledDataSource; import org.apache.commons.dbcp2.BasicDataSource; import org.apache.commons.dbcp2.BasicDataSourceFactory; import java.beans.IntrospectionException; import java.beans.PropertyDescriptor; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.sql.*; import java.util.ArrayList; import java.util.List; import java.util.Properties; /** * @Auther: xbh * @Date: 2019/8/26 14:28 * @Description: * 四个功能 * 1、注册驱动(一次) * 2、获取连接 * 3、释放资源 * 4、执行sql语句(增删改) */ public class DbUtils_Druid { private static DruidDataSource dataSource = null; //注册驱动(一次) static { Properties properties=new Properties(); try{ properties.load(DbUtils_Druid.class.getClassLoader().getResourceAsStream("druid.properties")); //自动加载,不用引用,但是配置文件不能改 dataSource = (DruidDataSource)DruidDataSourceFactory.createDataSource(properties); }catch (Exception e){ e.printStackTrace(); } } //获取连接 public static Connection getConnection(){ try { return dataSource.getConnection(); } catch (SQLException e) { e.printStackTrace(); } return null; } //释放资源 public static void closeAll(Connection conn, Statement stat, ResultSet rs){ if(rs!=null){ try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if(stat!=null){ try { stat.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn!=null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } //sql语句 public static int executeUpdate(String sql, Object...params){ Connection conn = getConnection(); PreparedStatement pstat = null; try { pstat = conn.prepareStatement(sql); //设置参数 if(params!=null){ for (int i = 0; i < params.length; i++) { pstat.setObject(i+1, params[i]); } } return pstat.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); }finally { closeAll(conn,pstat,null); } return -1; } //返回list集合的方法 public static <T> List<T> findList(String sql,Class<T> class1, Object...params){ List<T> list = new ArrayList<>(); //从数据库查询数据 Connection conn = null; PreparedStatement pstat = null; ResultSet rs = null; try{ //获取连接 conn = getConnection(); //获取执行 pstat = conn.prepareStatement(sql); //进行执行判断 if(params != null){ for (int i = 0; i < params.length; i++) { pstat.setObject(i+1, params[i]); } } //执行语句 rs = pstat.executeQuery(); //获得表头 ResultSetMetaData metaData = rs.getMetaData(); while (rs.next()){ //获得对象 T t = convertToObject(metaData, rs, class1); list.add(t); } } catch (Exception e) { e.printStackTrace(); } finally { closeAll(conn, pstat, rs); } return list; } //返回单个对象的方法 public static <T> T findSingle(String sql, Class<T> class1, Object...params){ T t = null; //从数据库查询数据 Connection conn = null; PreparedStatement pstat = null; ResultSet rs = null; try{ conn = getConnection(); pstat = conn.prepareStatement(sql); if(params != null){ for (int i = 0; i < params.length; i++) { pstat.setObject(i+1, params[i]); } } rs = pstat.executeQuery(); ResultSetMetaData metaData = rs.getMetaData(); if (rs.next()){ t = convertToObject(metaData, rs, class1); } } catch (Exception e) { e.printStackTrace(); } finally { closeAll(conn, pstat, rs); } return t; } public static <T> T convertToObject(ResultSetMetaData metaData, ResultSet rs, Class<T> class1){ try { //映射对象 T t = class1.newInstance(); for (int i = 0; i < metaData.getColumnCount(); i++) { //获得表头 String columnLabel = metaData.getColumnLabel(i + 1); //获得表头下的数据 Object value = rs.getObject(columnLabel);//empno ename try{ //内省解析属性描述符 PropertyDescriptor pd = new PropertyDescriptor(columnLabel, class1); if (pd != null) {//属性描述符不空 //获取set方法 Method writeMethod = pd.getWriteMethod();//setEmpno setEname //加入数据到对象 writeMethod.invoke(t, value); } }catch (Exception e){ continue; } } //返回对象 return t; } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } return null; } }
第五节 DBUtils使用
5.1 DBUtils简介
DBUtils是java编程中的数据库操作实用工具,小巧简单实用,
1.对于数据表的读操作,可以把结果转换成List,Array,Set等java集合,便于程序员操作。
2.对于数据表的写操作,也变得很简单(只需写sql语句)。
DBUtils包括主要类
DbUtils类:启动类
ResultSetHandler接口:转换类型接口
--ArrayHandler类:实现类,把记录转化成数组
--ArrayListHandler类:把记录转化成数组,并放入集合中
--ColumnListHandler类:取某一列的数据。封装到List中。
--ScalarHandler类:适合获取一行一列数据。
--BeanHandler类:实现类,把记录转成对象。
--BeanListHandler类:实现类,把记录转化成List,使记录为JavaBean类型的对象
QueryRunner类:执行SQL语句的类
完整项目
-
StudentDao
package Day20190826.Day8Task.impl; import Day20190826.Day8Task.domain.Student; import java.util.List; /** * @Auther: xbh * @Date: 2019/8/27 19:24 * @Description: */ public interface StudentDao { public List<Student> findList(); public Student findById(Integer sid); public void add(Student student); public void update(Student student); public void delete(Integer sid); }
-
StudentDaoImpl
package Day20190826.Day8Task.dao; import Day20190826.Day8Task.domain.Student; import Day20190826.Day8Task.impl.StudentDao; import Day20190826.Day8Task.utils.DbUtils_Druid; import java.util.List; /** * @Auther: xbh * @Date: 2019/8/27 19:35 * @Description: */ public class StudentDaoImpl implements StudentDao { @Override public List<Student> findList() { List<Student> list = DbUtils_Druid.findList("select * from student",Student.class, null); return list; } @Override public Student findById(Integer sid) { Student student = DbUtils_Druid.findSingle("select * from emp where empno=?", Student.class, sid); return student; } @Override public void add(Student student) { Object[] params = {student.getSid(), student.getSname()}; int i = DbUtils_Druid.executeUpdate("insert into student(sid, sname) values(?,?)", params); System.out.println(i); } @Override public void update(Student student) { Object[] params = {student.getSid(), student.getSname()}; int i = DbUtils_Druid.executeUpdate("update student set sname=? where sid=?", params); System.out.println(i); } @Override public void delete(Integer sid) { int i = DbUtils_Druid.executeUpdate("delete from student where sid=?", sid); System.out.println(i); } }
-
Student
package Day20190826.Day8Task.domain; /** * @Auther: xbh * @Date: 2019/8/27 19:25 * @Description: */ public class Student { int sid; String sname; public Student() { } public Student(int sid, String sname) { this.sid = sid; this.sname = sname; } public int getSid() { return sid; } public void setSid(int sid) { this.sid = sid; } public String getSname() { return sname; } public void setSname(String sname) { this.sname = sname; } @Override public String toString() { return "Student{" + "sid=" + sid + ", sname='" + sname + '\'' + '}'; } }
-
DbUtils_Druid
package Day20190826.Day8Task.utils; import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.pool.DruidDataSourceFactory; import java.beans.PropertyDescriptor; import java.lang.reflect.Method; import java.sql.*; import java.util.ArrayList; import java.util.List; import java.util.Properties; /** * @Auther: xbh * @Date: 2019/8/27 19:36 * @Description: */ public class DbUtils_Druid { private static DruidDataSource dataSource = null; //注册驱动(一次) static { Properties properties=new Properties(); try{ properties.load(DbUtils_Druid.class.getClassLoader().getResourceAsStream("studruid.properties")); //自动加载,不用引用,但是配置文件不能改 dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties); }catch (Exception e){ e.printStackTrace(); } } //获取连接 public static Connection getConnection(){ try { return dataSource.getConnection(); } catch (SQLException e) { e.printStackTrace(); } return null; } //释放资源 public static void closeAll(Connection conn, Statement stat, ResultSet rs){ if(rs!=null){ try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if(stat!=null){ try { stat.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn!=null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } //sql语句 public static int executeUpdate(String sql, Object...params){ Connection conn = getConnection(); PreparedStatement pstat = null; try { pstat = conn.prepareStatement(sql); //设置参数 if(params!=null){ for (int i = 0; i < params.length; i++) { pstat.setObject(i+1, params[i]); } } return pstat.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); }finally { closeAll(conn,pstat,null); } return -1; } //返回list集合的方法 public static <T> List<T> findList(String sql, Class<T> class1, Object...params){ List<T> list = new ArrayList<>(); //从数据库查询数据 Connection conn = null; PreparedStatement pstat = null; ResultSet rs = null; try{ //获取连接 conn = getConnection(); //获取执行 pstat = conn.prepareStatement(sql); //进行执行判断 if(params != null){ for (int i = 0; i < params.length; i++) { pstat.setObject(i+1, params[i]); } } //执行语句 rs = pstat.executeQuery(); //获得表头 ResultSetMetaData metaData = rs.getMetaData(); while (rs.next()){ //获得对象 T t = convertToObject(metaData, rs, class1); list.add(t); } } catch (Exception e) { e.printStackTrace(); } finally { closeAll(conn, pstat, rs); } return list; } //返回单个对象的方法 public static <T> T findSingle(String sql, Class<T> class1, Object...params){ T t = null; //从数据库查询数据 Connection conn = null; PreparedStatement pstat = null; ResultSet rs = null; try{ conn = getConnection(); pstat = conn.prepareStatement(sql); if(params != null){ for (int i = 0; i < params.length; i++) { pstat.setObject(i+1, params[i]); } } rs = pstat.executeQuery(); ResultSetMetaData metaData = rs.getMetaData(); if (rs.next()){ t = convertToObject(metaData, rs, class1); } } catch (Exception e) { e.printStackTrace(); } finally { closeAll(conn, pstat, rs); } return t; } public static <T> T convertToObject(ResultSetMetaData metaData, ResultSet rs, Class<T> class1){ try { //映射对象 T t = class1.newInstance(); for (int i = 0; i < metaData.getColumnCount(); i++) { //获得表头 String columnLabel = metaData.getColumnLabel(i + 1); //获得表头下的数据 Object value = rs.getObject(columnLabel);//empno ename try{ //内省解析属性描述符 PropertyDescriptor pd = new PropertyDescriptor(columnLabel, class1); if (pd != null) {//属性描述符不空 //获取set方法 Method writeMethod = pd.getWriteMethod();//setEmpno setEname //加入数据到对象 writeMethod.invoke(t, value); } }catch (Exception e){ continue; } } //返回对象 return t; } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } return null; } }
-
EmpDaoImpl
package Day20190827.Day9Dutils.dao; import Day20190827.Day9Dutils.Impl.EmpDao; import Day20190827.Day9Dutils.domain.Emp; import Day20190827.Day9Dutils.utils.DataSourseUtils; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.handlers.*; import java.sql.SQLException; import java.util.List; /** * @Auther: xbh * @Date: 2019/8/28 09:32 * @Description: */ public class EmpDaoImpl implements EmpDao { @Override public List<Emp> findAll() {//ctrl + H 查看实现类 QueryRunner qr = new QueryRunner(DataSourseUtils.getDataSource()); try { return qr.query("select * from emp", new BeanListHandler<Emp>(Emp.class)); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException("查询失败"); } } @Override public Emp findByEmpno(Integer empno) { QueryRunner qr = new QueryRunner(DataSourseUtils.getDataSource()); try { return qr.query("select * from emp where empno=?", new BeanHandler<Emp>(Emp.class),empno); } catch (SQLException e) { e.printStackTrace(); throw new RuntimeException("查询失败"); } } @Override public void add(Emp emp) { //创建查询执行器 QueryRunner qr = new QueryRunner(DataSourseUtils.getDataSource()); Object[] params = {emp.getEmpno(), emp.getEname(),emp.getJob(),emp.getMgr(),emp.getHiredate(),emp.getSal(),emp.getComm(),emp.getDeptno()}; try { qr.update("insert into emp values(?,?,?,?,?,?,?,?)", params); } catch (SQLException e) { e.printStackTrace(); } } @Override public void update(Emp emp) { QueryRunner qr = new QueryRunner(DataSourseUtils.getDataSource()); Object[] params = {emp.getEname(),emp.getJob(),emp.getMgr(),emp.getHiredate(),emp.getSal(),emp.getComm(),emp.getDeptno(),emp.getEmpno()}; try { qr.update("update emp set ename=?,job=?,mgr=?,hiredate=?,sal=?,comm=?,deptno=? where empno=?", params); } catch (SQLException e) { e.printStackTrace(); } } @Override public void delete(Integer empno) { //"delete from emp where empno=?", empno QueryRunner qr = new QueryRunner(DataSourseUtils.getDataSource()); try { qr.update("delete from emp where empno=?", empno); } catch (SQLException e) { e.printStackTrace(); } } @Override public long getCount() { QueryRunner qr = new QueryRunner(DataSourseUtils.getDataSource()); Long count = null; try { count = (Long)qr.query("select count(*) from emp", new ScalarHandler<>()); return count; } catch (SQLException e) { e.printStackTrace(); } return count; } @Override public Object[] findArrayEmp(Integer empno){ QueryRunner qr = new QueryRunner(DataSourseUtils.getDataSource()); try { return qr.query("select * from emp where empno=?", new ArrayHandler(),empno); } catch (SQLException e) { e.printStackTrace(); new RuntimeException("查询失败"); } return null; } @Override public List<Object[]> findArrayListEmp(){ QueryRunner qr = new QueryRunner(DataSourseUtils.getDataSource()); try { return qr.query("select * from emp", new ArrayListHandler()); } catch (SQLException e) { e.printStackTrace(); new RuntimeException("查询失败"); } return null; } @Override public List<String> findNames(){ QueryRunner qr = new QueryRunner(DataSourseUtils.getDataSource()); try { return qr.query("select * from emp", new ColumnListHandler<String>("ename")); } catch (SQLException e) { e.printStackTrace(); } return null; } }
-
DataSourseUtils
package Day20190827.Day9Dutils.utils; import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.pool.DruidDataSourceFactory; import java.io.IOException; import java.io.InputStream; import java.util.Properties; /** * @Auther: xbh * @Date: 2019/8/28 09:24 * @Description: */ public class DataSourseUtils { private static DruidDataSource dataSource; static { try{ Properties properties = new Properties(); InputStream is = DataSourseUtils.class.getClassLoader().getResourceAsStream("druid.properties"); properties.load(is); dataSource = (DruidDataSource)DruidDataSourceFactory.createDataSource(properties); } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } public static DruidDataSource getDataSource(){ return dataSource; } }
-
小结
1 封装工具类
2 Dao设计模式: 把数据访问代码抽离出来。降低代码的耦合性和提高扩展性。
dao接口
dao实现
实体类
数据库工具类
3 连接池
dbcp
c3p0
druid重点
4 Dbutils工具
第十天 Tomcat配置及创建web项目
第一节 Web应用的演变
-
自定义web服务器
package com.qf.day10; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; /** * 自定义服务器 * @author wgy * */ public class MyServer { public static void main(String[] args) { try { //1创建侦听套接字 ServerSocket listener=new ServerSocket(10086); //2接收客户端请求 System.out.println("客户端已启动...."); Socket socket=listener.accept(); //3获取输出流 OutputStream os=socket.getOutputStream(); //4创建FileInputStream FileInputStream fis=new FileInputStream("d:\\mywork\\hello.html"); byte[] buf=new byte[1024*4]; int len=0; while((len=fis.read(buf))!=-1) { os.write(buf,0,len); os.flush(); } //5关闭 fis.close(); os.close(); socket.close(); listener.close(); System.out.println("服务器执行完毕..."); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
第二节 Tomcat服务器搭建
-
tomcat目录介绍
1、bin:该目录下存放的是二进制可执行文件,如果是安装版,那么这个目录下会有两个exe文件:tomcat9.exe、tomcat9w.exe,前者是在控制台下启动Tomcat,后者是弹出UGI窗口启动Tomcat;如果是解压版,那么会有startup.bat和shutdown.bat文件,startup.bat用来启动Tomcat,但需要JDK的配置,shutdawn.bat用来停止Tomcat; 2、conf:这是一个非常非常重要的目录,这个目录下有四个最为重要的文件: server.xml:配置整个服务器信息。例如修改端口号,添加虚拟主机等; tomcatusers.xml:存储tomcat用户的文件,这里保存的是tomcat的用户名及密码,以及用户的角色信息。可以按着该文件中的注释信息添加tomcat用户,然后就可以在Tomcat主页中进入Tomcat Manager页面了; web.xml:部署描述符文件,这个文件中注册了很多MIME类型,即文档类型。这些MIME类型是客户端与服务器之间说明文档类型的,如用户请求一个html网页,那么服务器还会告诉客户端浏览器响应的文档是text/html类型的,这就是一个MIME类型。客户端浏览器通过这个MIME类型就知道如何处理它了。当然是在浏览器中显示这个html文件了。但如果服务器响应的是一个exe文件,那么浏览器就不可能显示它,而是应该弹出下载窗口才对。MIME就是用来说明文档的内容是什么类型的! context.xml:对所有应用的统一配置,通常我们不会去配置它。 3、lib:Tomcat的类库,里面是一大堆jar文件。如果需要添加Tomcat依赖的jar文件,可以把它放到这个目录中,当然也可以把应用依赖的jar文件放到这个目录中,这个目录中的jar所有项目都可以共享之,但这样你的应用放到其他Tomcat下时就不能再共享这个目录下的Jar包了,所以建议只把Tomcat需要的Jar包放到这个目录下; 4、logs:这个目录中都是日志文件,记录了Tomcat启动和关闭的信息,如果启动Tomcat时有错误,那么异常也会记录在日志文件中。 5、temp:存放Tomcat的临时文件,这个目录下的东西可以在停止Tomcat后删除! 6、webapps:存放web项目的目录,其中每个文件夹都是一个项目;如果这个目录下已经存在了目录,那么都是tomcat自带的项目。其中ROOT是一个特殊的项目,在地址栏中没有给出项目目录时,对应的就是ROOT项目。http://localhost:8080/examples,进入示例项目。其中examples就是项目名,即文件夹的名字。 7、work:运行时生成的文件,最终运行的文件都在这里。通过webapps中的项目生成的!可以把这个目录下的内容删除,再次运行时会生再次生成work目录。当客户端用户访问一个JSP文件时,Tomcat会通过JSP生成Java文件,然后再编译Java文件生成class文件,生成的java和class文件都会存放到这个目录下。 8、LICENSE:许可证。 9、NOTICE:说明文件。
-
idea 关联tomcat
-
添加tomcat服务
file->setting->Build,Execution,Deployment->Application Servers->点击+添加tomcat
-
new project->Java Enterprise->JavaEE7 并且勾选Web Application创建成功
-
-
idea打war包
-
file->ProjectStructure->Project Setting->Artifacts->点击+->Web Application Archive->for XXX:war exploded
-
Build->Build Project
-
第三节xml配置
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <!--配置项目名称--> <display-name>project2_2</display-name> <!--web应用描述--> <description>this is my first web</description> <!--配置网站首页,默认有index.html--> <welcome-file-list> <welcome-file>hello.html</welcome-file> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <!--网站错误页面--> <error-page> <error-code>404</error-code> <!--别忘了加 / --> <location>/404.html</location> </error-page> <error-page> <error-code>500</error-code> <!--别忘了加 / --> <location>/500.jsp</location> </error-page> </web-app>