数据库中可以编写并保存一段程序,做数据运算
视图View
存储过程Procudure
函数Function
触发器Trigger
mysql数据库编程能力较弱,很多功能无法实现
一个客户端与服务器连接期间的变量
set @v1= 123;
select @v1;
begin... end; 是一对大括号,局部变量只能在 begin 到 end之间使用,end结束后,变量消失
使用 declare 关键字来定义局部变量
delimiter; 结束符改成 ;
delimiter// 结束符改成//
创建复杂的存储过程中间会用到;结束符,如果几个;放在一起,MySQL只会识别第一个,以后的不会识别,这样会及
其不完整
begin
declarev2 int default 123;
selectv2;
select@v1;
end//
(上面无法执行,只是参考)
3.1 简单视图
视图本质就是一个查询语句
SELECT* FROM t_goods
WHEREcategory_id=238
CREATEVIEW v_goods AS
SELECT* FROM t_goods
WHEREcategory_id=238
SELECT* FROM v_goods
DELIMITER$$ 设定一个标识符,标识结束$$
USE`tedu_store`$$ 打开指定数据库tedu_store
DROPVIEW IF EXISTS `v_goods238`$$ 如果此视图已经存在,就删除
CREATEALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINERVIEW `v_goods238` AS
SELECT
`t_goods`.`id` AS `id`,
`t_goods`.`category_id` AS `category_id`,
`t_goods`.`item_type` AS `item_type`,
`t_goods`.`title` AS `title`,
`t_goods`.`sell_point` AS `sell_point`,
`t_goods`.`price` AS `price`,
`t_goods`.`num` AS `num`,
`t_goods`.`barcode` AS `barcode`,
`t_goods`.`image` AS `image`,
`t_goods`.`status` AS `status`,
`t_goods`.`priority` AS `priority`,
`t_goods`.`created_time` AS `created_time`,
`t_goods`.`modified_time`AS `modified_time`,
`t_goods`.`created_user` AS `created_user`,
`t_goods`.`modified_user`AS `modified_user`
FROM`t_goods`
WHERE(`t_goods`.`category_id` = 238)$$
DELIMITER;
3.1 多级关联视图
CREATEVIEW v_cat_goods AS
SELECTc.name,g.item_type,g.title FROM t_goods g
LEFTJOIN t_goods_category c
ONg.category_id=c.id
SELECT* FROM v_cat_goods
视图在大型项目中被废除!!!!
视图过程是把查询所有的记录都查询回来,然后再过滤数据,过滤掉非238.
如果这张表中有一千万数据。数据量大时无法优化。
Java程序可以吗?mybatis它直接处理,返回结果数据。结果就比视图快。
4 存储过程
存储过程是存储在数据库服务器中的一段过程代码
优点:
Jsp-java-database(proc)
存储过程离数据库最近,所以它执行代码效率最高的。
Client(brower)-WebServer(tomcat)-DatabaseServer(mysql)
WebServer和DatabaseServer,在企业中,WebServer一般服务器即可,但是DatabaseServer是所有服务器中最好的。甚
至大型项目,小型机。Unix+Oracle。
废除:
-
写数据库代码(存储过程-单独学习语法,无法断点,system.out没有输出,几乎无法调试。DBA),写java代码(人员众多,好调试)。后期维护。不好维护。Java好维护。
-
存储过程不好写,质量不好控制。
-- 修改结束符
delimiter //
-- 创建存储过程p1
createprocedure p1()
begin -- 大括号开始
-- 定义局部变量v2
declare v2int default 123;
select v2; -- 显示v2变量的值
end// -- 大括号结束
call p1()//
showprocedure status\G
所有存储过程
showprocedure status where db='db1'\G
查看指定库中的存储过程
showcreate procedure p1\G
dropprocedure if exists p1//
三种参数:
in 输入参数
out 输出参数
inout 既能输入又能输出
存储过程参数测试
-- 向学生表和联系方式表同时插入数据
-- 1) 插入学生数据
-- 2) 得到新插入的自增主键值
-- 3) 插入联系方式表
传统方式:
-
页面填写两张表的数据,学生名称,学生的电话,存在两个表中
-
学生表自增主键
-
联系表中和学生表的关联(一对一)
CREATE TABLE`t_student` (
`stu_id` int(11) NOTNULL AUTO_INCREMENT,
`name` varchar(20)DEFAULT NULL,
PRIMARY KEY(`stu_id`)
) ENGINE=InnoDBDEFAULT CHARSET=utf8
CREATE TABLE `t_tel` (
`stu_id` int(11) NOT NULL,
`tel` varchar(30) DEFAULT NULL,
PRIMARY KEY (`stu_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
DELIMITER//
createprocedure p_student_tel
(in namevarchar(20),
in telvarchar(20), out idint)
begin
declare vint;-- 定义临时变量用来存自增主键值
-- 插入学生数据
insertinto t_student(name)
values(name);
-- 获得新生成的自增主键值存到v
set v= last_insert_id();
-- 插入联系方式数据
insertinto t_tel(stu_id,tel)
values(v,tel);
-- 自增主键值存到输出参数id
set id=v;
end//
-- 调用
CALLp_student_tel('刘强东',13010100808,@id);
select * from t_student;
select * from t_tel;
select @stu_id;
if 条件 then
代码
endif
if 条件 then
代码1
else
代码2
endif
case
when 条件1then ...
when 条件2then ...
else...
endcase
case 变量或表达式
when 值1then ...
when 值2then ...
else
endcase
分支判断测试
delimiter//
dropprocedure if exists p1//
createprocedure p1(in vint)
begin
if v=1 then
select 'v的值是1';
endif;
case v
when 2 thenselect 'v的值是2';
when 3 thenselect 'v的值是3';
elseselect 'v的值不是2,3';
endcase;
end//
call p1(1)//
call p1(2)//
call p1(3)//
call p1(4)//
while 条件 do
代码
endwhile
-- lp: 循环命名,可以起任意的名字
lp:loop
...
if 条件 then
leavelp; -- 指定离开哪个循环
endif;
...
endloop;
repeat
代码
until 条件 endrepeat;
循环测试
-- 新建 tb1 表
use db1//
droptable if exists tb1//
createtable tb1(
idint primarykey auto_increment,
numint
)engine=innodb charset=utf8//
delimiter//
dropprocedure ifexists p2//
createprocedure p2(inn int)
begin
declare iint default 0;
-- while
while i<n do --i的值从0递增到n-1
insertinto tb1(num) values(i+1);
seti=i+1;
endwhile;
-- loop
set i=0;
lp: loop
insertinto tb1(num) values(i+1);
seti=i+1;
if i=n then --i等于n时退出loop循环
leave lp;
endif;
endloop;
-- repeat
set i=0;
repeat
insertinto tb1(num) values(i+1);
seti=i+1;
until i=n endrepeat; --i等于n时退出repeat循环
end//
call p2(10)//
select * from tb1//
函数有返回值
调用存储过程用call,调用函数直接调
函数不让?
分布式?又放在java端
Zookeeper集群管理者,当一台服务的配置更新,zk会自动把配置改变信息更新到其它所有的机器
上。
5.1 创建函数
createfunction fn()
returnsvarchar(100)
begin
执行代码运算产生计算结果
return 计算结果;
end//
求平方的函数 fn_pow
DELIMITER//
dropfunction if exists fn_pow//
createfunction fn_pow(nint)
returns int -- 函数返回什么类型的数据
begin
declare rint;
set r= n*n;
return r; -- 向调用位置返回计算结果
end //
select fn_pow(5)//
select *,fn_pow(num) from tb1//
showfunction status\G
showfunction status where db='test'\G
showcreate function fn_pow\G
dropfunction if exists fn_pow //
对表中的数据操作时,可以触发一段代码执行
三个数据操作:
insert
update
delete
两个触发时间:
before
after
一张表中最多可以有6个触发器
beforeinsert
afterinsert
beforeupdate
afterupdate
beforedelete
afterdelete
两个隐含对象
new
新的数据行
insert的new:要插入的新行
update的new:修改后的新行
delete的new:没有
old
旧的数据行
insert的old:没有
update的old:修改前的旧数据
delete的old:被删除的旧数据
访问新行或旧行数据:
new.id
new.name
old.age
old.tel
操作商品表insert,before,new
createtrigger 名 触发时间 on 表
foreach row
being
代码
end;
用触发器自动更新updated字段
-- 学生表添加 updated字段
altertable t_student
add createddatetime //
-- 添加触发器,插入数据时自动填入时间
-- beforeinsert
DELIMITER//
CREATETRIGGER tr_b_i
BEFOREINSERT ON t_student FOR EACH ROW
BEGIN
SETnew.created=NOW();
END//
insertinto t_student(name)
values('tony')//
select * from t_student//
-- 添加触发器,修改数据时自动修改时间
altertable t_student
add updateddatetime //
DELIMITER//
CREATETRIGGER tr_b_u
BEFOREUPDATE ON t_student FOR EACH ROW
BEGIN
SETnew.updated = NOW();
END//
UPDATEt_student SET NAME='tina' WHERE stu_id=2
select * from t_student//
-- 级联删除,删除主表信息时利用触发器删除子表信息
-- beforedelete
DELIMITER//
CREATETRIGGER tr_b_d
BEFOREDELETE ON t_student FOR EACH ROW
BEGIN
DELETEFROM t_tel WHERE stu_id=old.stu_id;
END//
deletefrom t_student where name='a'//
进入系统库 information_schema
useinformation_schema //
查询 triggers 表中触发器信息
select* from triggers\G
droptrigger 触发器名
级联删除
删除主表的数据时,要先把子表的数据删除。
备份方式:
-
冷备份(按月)
-
热备份
-
定时任务Job(按周,日(凌晨2点),小时)、
-
实时备份(主从复制,实时同步)
查看数据安装路径
SELECT@@basedir AS basePath FROM DUAL;
C:\ProgramFiles\MySQL\MySQL Server 5.5\bin>
使用mysqldump命令备份数据库
使用mysql命令恢复数据库
退出mysql,在系统命令行执行:
下面命令是一行代码,不能折行
mysqldump -uroot-p
--default-character-set=utf8 //表中存的是什么编码
hr>d:\hr.sql //库>文件
数据库名
两步恢复:
1) 在数据库中新建一个库
createdatabase jtdb2 charset utf8;
2) 在系统命令行执行恢复命令
下面命令是一行代码,不能折行
mysql-uroot -p
--default-character-set=utf8
jtdb2<d:\jtds.sql
9.1 存储过程产生大量数据
1) 创建一个内存表tm, engine=memory
2) 创建一个磁盘表td
3) 在存储过程中,循环20000次向内存表插入随机字符串
4) 把20000条数据,一批存入磁盘表
5) 清空内存表
-- 内存表
droptable if exists tm;
createtable tm(
cvarchar(20)
) engine=memory charset=utf8;
-- 磁盘表
droptable if exists td;
createtable td(
idint primarykey auto_increment,
cvarchar(20)
) engine=innodb charset=utf8;
-- 存储过程
DROPPROCEDURE IF EXISTS gen_data;
DELIMITER//
CREATEPROCEDURE gen_data(IN n INT)
BEGIN
DECLAREi INT DEFAULT 0;
WHILEi<n DO
INSERTINTO tm VALUES (UUID());
SETi=i+1;
ENDWHILE;
INSERTINTO td(c) SELECT c FROM tm;
DELETEFROM tm;
END//
CALLgen_data(1000)
DROPPROCEDURE IF EXISTS test_insert;
DELIMITER//
CREATEPROCEDURE test_insert(cnt INT)
BEGIN
DECLAREi INT DEFAULT 0;
STARTTRANSACTION;
WHILEi<cnt
DO
INSERTINTO td(c) VALUES(UUID());
SETi=i+1;
ENDWHILE;
COMMIT;
END//
9.2 索引优化
索引其本质是创建了一张索引表,现有表的拷贝
(索引需要代价,插入数据要重写排序)
只拷贝现有表的指定索引字段。重要是做了一件事情:
排序
为什么它要排序呢?为什么排序后就快了呢?
不创建索引,查询时,全表遍历。
折半算法
用索引提高数据查找效率
-- 没有索引,花3.5秒查询
select* from td where c='ab' //
-- 对c字段创建索引,花1分40秒左右
createindex td_c_index on td(c) //
-- 有索引查询花费 0.00 秒
select* from td where c='ab' //
9.3MySQL验证索引的使用-最左前缀特性
复合索引
通过EXPLAIN关键字可以判断查询SQL语句是否使用索引
Possible_keys如果有值就代表使用了哪个索引,如果null就代表查询没有使用索引,全表遍历。
SELECT* FROM tb1
WHEREuser_id=100;
SELECT* FROM tb1
WHEREorder_id=300;
SELECT* FROM tb1
WHEREuser_id=100 AND order_id=300;
SELECT* FROM tb1
WHEREorder_id=300 AND user_id=100 ;
没使用索引
EXPLAIN
SELECT* FROM t_goods
WHEREtitle LIKE '%皮面%'
使用索引
EXPLAIN
SELECT* FROM t_goods
WHEREtitle LIKE '皮面%'
没有使用索引
EXPLAIN
SELECT* FROM t_goods
WHEREtitle LIKE '%皮面'
EXPLAINSELECT * FROM tb_cart WHERE user_id=1 AND item_id=1
EXPLAINSELECT * FROM tb_cart WHERE user_id=1
EXPLAINSELECT * FROM tb_cart WHERE item_id=1
查看SQL的执行计划,可以看出第一句、第二句SQL使用了索引,第三句SQL未使用索引。很好的证明了索引左侧前缀特性。
注意:
1)下面的语句违反了左侧前缀的特性,为何仍然可以使用索引呢?因为MYSQL对SQL语句有优化,它会重新组合where条件。
EXPLAINSELECT * FROM tb_cart WHERE item_id=1 AND user_id=1
2)没有where条件的查询是不会使用索引的。