当前位置: 首页 > news >正文

手机端网站优化网站怎样优化关键词好

手机端网站优化,网站怎样优化关键词好,自己做企业网站的步骤,武汉做便宜网站这是Mysql系列第20篇。 环境:mysql5.7.25,cmd命令中进行演示。 代码中被[]包含的表示可选,|符号分开的表示可选其一。 需求背景 我们在写存储过程的时候,可能会出现下列一些情况: 插入的数据违反唯一约束&#xff…

这是Mysql系列第20篇。

环境:mysql5.7.25,cmd命令中进行演示。

代码中被[]包含的表示可选,|符号分开的表示可选其一。

需求背景

我们在写存储过程的时候,可能会出现下列一些情况:

  1. 插入的数据违反唯一约束,导致插入失败

  2. 插入或者更新数据超过字段最大长度,导致操作失败

  3. update影响行数和期望结果不一致

遇到上面各种异常情况的时,可能需要我们能够捕获,然后可能需要回滚当前事务。

本文主要围绕异常处理这块做详细的介绍。

此时我们需要使用游标,通过游标的方式来遍历select查询的结果集,然后对每行数据进行处理。

本篇内容

  • 异常分类详解

  • 内部异常详解

  • 外部异常详解

  • 掌握乐观锁解决并发修改数据出错的问题

  • update影响行数和期望结果不一致时的处理

准备数据

创建库:javacode2018

创建表:test1,test1表中的a字段为主键。

/*建库javacode2018*/
drop database if exists javacode2018;
create database javacode2018;/*切换到javacode2018库*/
use javacode2018;DROP TABLE IF EXISTS test1;
CREATE TABLE test1(a int PRIMARY KEY);

异常分类

我们将异常分为mysql内部异常和外部异常

mysql内部异常

当我们执行一些sql的时候,可能违反了mysql的一些约束,导致mysql内部报错,如插入数据违反唯一约束,更新数据超时等,此时异常是由mysql内部抛出的,我们将这些由mysql抛出的异常统称为内部异常。

外部异常

当我们执行一个update的时候,可能我们期望影响1行,但是实际上影响的不是1行数据,这种情况:sql的执行结果和期望的结果不一致,这种情况也我们也把他作为外部异常处理,我们将sql执行结果和期望结果不一致的情况统称为外部异常。

Mysql内部异常

示例1

test1表中的a字段为主键,我们向test1表同时插入2条数据,并且放在一个事务中执行,最终要么都插入成功,要么都失败。

创建存储过程:
/*删除存储过程*/
DROP PROCEDURE IF EXISTS proc1;
/*声明结束符为$*/
DELIMITER $
/*创建存储过程*/
CREATE PROCEDURE proc1(a1 int,a2 int)BEGINSTART TRANSACTION;INSERT INTO test1(a) VALUES (a1);INSERT INTO test1(a) VALUES (a2);COMMIT;END $
/*结束符置为;*/
DELIMITER ;

上面存储过程插入了两条数据,a的值都是1。

验证结果:
mysql> DELETE FROM test1;
Query OK, 0 rows affected (0.00 sec)mysql> CALL proc1(1,1);
ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'
mysql> SELECT * from test1;
+---+
| a |
+---+
| 1 |
+---+
1 row in set (0.00 sec)

上面先删除了test1表中的数据,然后调用存储过程proc1,由于test1表中的a字段是主键,插入第二条数据时违反了a字段的主键约束,mysql内部抛出了异常,导致第二条数据插入失败,最终只有第一条数据插入成功了。

上面的结果和我们期望的不一致,我们希望要么都插入成功,要么失败。

那我们怎么做呢?我们需要捕获上面的主键约束异常,然后发现有异常的时候执行rollback回滚操作,改进上面的代码,看下面示例2。

示例2

我们对上面示例进行改进,捕获上面主键约束异常,然后进行回滚处理,如下:

创建存储过程:
/*删除存储过程*/
DROP PROCEDURE IF EXISTS proc2;
/*声明结束符为$*/
DELIMITER $
/*创建存储过程*/
CREATE PROCEDURE proc2(a1 int,a2 int)BEGIN/*声明一个变量,标识是否有sql异常*/DECLARE hasSqlError int DEFAULT FALSE;/*在执行过程中出任何异常设置hasSqlError为TRUE*/DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET hasSqlError=TRUE;/*开启事务*/START TRANSACTION;INSERT INTO test1(a) VALUES (a1);INSERT INTO test1(a) VALUES (a2);/*根据hasSqlError判断是否有异常,做回滚和提交操作*/IF hasSqlError THENROLLBACK;ELSECOMMIT;END IF;END $
/*结束符置为;*/
DELIMITER ;
上面重点是这句:
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET hasSqlError=TRUE;

当有sql异常的时候,会将变量hasSqlError的值置为TRUE

模拟异常情况:
mysql> DELETE FROM test1;
Query OK, 2 rows affected (0.00 sec)mysql> CALL proc2(1,1);
Query OK, 0 rows affected (0.00 sec)mysql> SELECT * from test1;
Empty set (0.00 sec)

上面插入了2条一样的数据,插入失败,可以看到上面test1表无数据,和期望结果一致,插入被回滚了。

模拟正常情况:
mysql> DELETE FROM test1;
Query OK, 0 rows affected (0.00 sec)mysql> CALL proc2(1,2);
Query OK, 0 rows affected (0.00 sec)mysql> SELECT * from test1;
+---+
| a |
+---+
| 1 |
| 2 |
+---+
2 rows in set (0.00 sec)

上面插入了2条不同的数据,最终插入成功。

外部异常

外部异常不是由mysql内部抛出的错误,而是由于sql的执行结果和我们期望的结果不一致的时候,我们需要对这种情况做一些处理,如回滚操作。

示例1

我们来模拟电商中下单操作,按照上面的步骤来更新账户余额。

电商中有个账户表和订单表,如下:
DROP TABLE IF EXISTS t_funds;
CREATE TABLE t_funds(user_id INT PRIMARY KEY COMMENT '用户id',available DECIMAL(10,2) NOT NULL DEFAULT 0 COMMENT '账户余额'
) COMMENT '用户账户表';
DROP TABLE IF EXISTS t_order;
CREATE TABLE t_order(id int PRIMARY KEY AUTO_INCREMENT COMMENT '订单id',price DECIMAL(10,2) NOT NULL DEFAULT 0 COMMENT '订单金额'
) COMMENT '订单表';
delete from t_funds;
/*插入一条数据,用户id为1001,余额为1000*/
INSERT INTO t_funds (user_id,available) VALUES (1001,1000);
下单操作涉及到操作上面的账户表,我们用存储过程来模拟实现:
/*删除存储过程*/
DROP PROCEDURE IF EXISTS proc3;
/*声明结束符为$*/
DELIMITER $
/*创建存储过程*/
CREATE PROCEDURE proc3(v_user_id int,v_price decimal(10,2),OUT v_msg varchar(64))a:BEGINDECLARE v_available DECIMAL(10,2);/*1.查询余额,判断余额是否够*/select a.available into v_available from t_funds a where a.user_id = v_user_id;if v_available<=v_price THENSET v_msg='账户余额不足!';/*退出*/LEAVE a;END IF;/*模拟耗时5秒*/SELECT sleep(5);/*2.余额减去price*/SET v_available = v_available - v_price;/*3.更新余额*/START TRANSACTION;UPDATE t_funds SET available = v_available WHERE user_id = v_user_id;/*插入订单明细*/INSERT INTO t_order (price) VALUES (v_price);/*提交事务*/COMMIT;SET v_msg='下单成功!';END $
/*结束符置为;*/
DELIMITER ;

上面过程主要分为3步骤:验证余额、修改余额变量、更新余额。

开启2个cmd窗口,连接mysql,同时执行下面操作:
USE javacode2018;
CALL proc3(1001,100,@v_msg);
select @v_msg;
然后执行:
mysql> SELECT * FROM t_funds;
+---------+-----------+
| user_id | available |
+---------+-----------+
|    1001 |    900.00 |
+---------+-----------+
1 row in set (0.00 sec)mysql> SELECT * FROM t_order;
+----+--------+
| id | price  |
+----+--------+
|  1 | 100.00 |
|  2 | 100.00 |
+----+--------+
2 rows in set (0.00 sec)

上面出现了非常严重的错误:下单成功了2次,但是账户只扣了100。

上面过程是由于2个操作并发导致的,2个窗口同时执行第一步的时候看到了一样的数据(看到的余额都是1000),然后继续向下执行,最终导致结果出问题了。

上面操作我们可以使用乐观锁来优化。

乐观锁的过程:用期望的值和目标值进行比较,如果相同,则更新目标值,否则什么也不做。

乐观锁类似于java中的cas操作,这块需要了解的可以点击:详解CAS

我们可以在资金表t_funds添加一个version字段,表示版本号,每次更新数据的时候+1,更新数据的时候将version作为条件去执行update,根据update影响行数来判断执行是否成功,优化上面的代码,见示例2

示例2

对示例1进行优化。

创建表:
DROP TABLE IF EXISTS t_funds;
CREATE TABLE t_funds(user_id INT PRIMARY KEY COMMENT '用户id',available DECIMAL(10,2) NOT NULL DEFAULT 0 COMMENT '账户余额',version INT DEFAULT 0 COMMENT '版本号,每次更新+1'
) COMMENT '用户账户表';DROP TABLE IF EXISTS t_order;
CREATE TABLE t_order(id int PRIMARY KEY AUTO_INCREMENT COMMENT '订单id',price DECIMAL(10,2) NOT NULL DEFAULT 0 COMMENT '订单金额'
)COMMENT '订单表';
delete from t_funds;
/*插入一条数据,用户id为1001,余额为1000*/
INSERT INTO t_funds (user_id,available) VALUES (1001,1000);
创建存储过程:
/*删除存储过程*/
DROP PROCEDURE IF EXISTS proc4;
/*声明结束符为$*/
DELIMITER $
/*创建存储过程*/
CREATE PROCEDURE proc4(v_user_id int,v_price decimal(10,2),OUT v_msg varchar(64))a:BEGIN/*保存当前余额*/DECLARE v_available DECIMAL(10,2);/*保存版本号*/DECLARE v_version INT DEFAULT 0;/*保存影响的行数*/DECLARE v_update_count INT DEFAULT 0;/*1.查询余额,判断余额是否够*/select a.available,a.version into v_available,v_version from t_funds a where a.user_id = v_user_id;if v_available<=v_price THENSET v_msg='账户余额不足!';/*退出*/LEAVE a;END IF;/*模拟耗时5秒*/SELECT sleep(5);/*2.余额减去price*/SET v_available = v_available - v_price;/*3.更新余额*/START TRANSACTION;UPDATE t_funds SET available = v_available WHERE user_id = v_user_id AND version = v_version;/*获取上面update影响行数*/select ROW_COUNT() INTO v_update_count;IF v_update_count=1 THEN/*插入订单明细*/INSERT INTO t_order (price) VALUES (v_price);SET v_msg='下单成功!';/*提交事务*/COMMIT;ELSESET v_msg='下单失败,请重试!';/*回滚事务*/ROLLBACK;END IF;END $
/*结束符置为;*/
DELIMITER ;

ROW_COUNT()可以获取更新或插入后获取受影响行数。将受影响行数放在v_update_count中。

然后根据v_update_count是否等于1判断更新是否成功,如果成功则记录订单信息并提交事务,否则回滚事务。

验证结果:开启2个cmd窗口,连接mysql,执行下面操作:
use javacode2018;
CALL proc4(1001,100,@v_msg);
select @v_msg;
窗口1结果:
mysql> CALL proc4(1001,100,@v_msg);
+----------+
| sleep(5) |
+----------+
|        0 |
+----------+
1 row in set (5.00 sec)Query OK, 0 rows affected (5.00 sec)mysql> select @v_msg;
+---------------+
| @v_msg        |
+---------------+
| 下单成功!     |
+---------------+
1 row in set (0.00 sec)
窗口2结果:
mysql> CALL proc4(1001,100,@v_msg);
+----------+
| sleep(5) |
+----------+
|        0 |
+----------+
1 row in set (5.00 sec)Query OK, 0 rows affected (5.01 sec)mysql> select @v_msg;
+-------------------------+
| @v_msg                  |
+-------------------------+
| 下单失败,请重试!        |
+-------------------------+
1 row in set (0.00 sec)

可以看到第一个窗口下单成功了,窗口2下单失败了。

再看一下2个表的数据:

mysql> SELECT * FROM t_funds;
+---------+-----------+---------+
| user_id | available | version |
+---------+-----------+---------+
|    1001 |    900.00 |       0 |
+---------+-----------+---------+
1 row in set (0.00 sec)mysql> SELECT * FROM t_order;
+----+--------+
| id | price  |
+----+--------+
|  1 | 100.00 |
+----+--------+
1 row in set (0.00 sec)

也正常。

总结

  1. 异常分为Mysql内部异常和外部异常

  2. 内部异常由mysql内部触发,外部异常是sql的执行结果和期望结果不一致导致的错误

  3. sql内部异常捕获方式

    DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET hasSqlError=TRUE;
    
  4. ROW_COUNT()可以获取mysql中insert或者update影响的行数

  5. 掌握使用乐观锁(添加版本号)来解决并发修改数据可能出错的问题

  6. begin end前面可以加标签,LEAVE 标签可以退出对应的begin end,可以使用这个来实现return的效果


文章转载自:
http://dinncoconstructivist.tqpr.cn
http://dinncorunty.tqpr.cn
http://dinncopneumatization.tqpr.cn
http://dinncofenderbeam.tqpr.cn
http://dinncolobeliaceous.tqpr.cn
http://dinncogainer.tqpr.cn
http://dinncocpsu.tqpr.cn
http://dinncosad.tqpr.cn
http://dinncosynchronise.tqpr.cn
http://dinncobreast.tqpr.cn
http://dinncokarass.tqpr.cn
http://dinncoslimy.tqpr.cn
http://dinncopushpin.tqpr.cn
http://dinncoexoerythrocytic.tqpr.cn
http://dinncopumelo.tqpr.cn
http://dinncomallard.tqpr.cn
http://dinncoreef.tqpr.cn
http://dinncomainsheet.tqpr.cn
http://dinncopossibly.tqpr.cn
http://dinncofeasance.tqpr.cn
http://dinncostraggle.tqpr.cn
http://dinncofluorescence.tqpr.cn
http://dinncostarchy.tqpr.cn
http://dinncoslime.tqpr.cn
http://dinncocounterviolence.tqpr.cn
http://dinncoundercliff.tqpr.cn
http://dinncoeconomization.tqpr.cn
http://dinncoeliminant.tqpr.cn
http://dinncogrosbeak.tqpr.cn
http://dinncolowly.tqpr.cn
http://dinncoedi.tqpr.cn
http://dinncophantasy.tqpr.cn
http://dinncoslang.tqpr.cn
http://dinncosandfrac.tqpr.cn
http://dinncoblendword.tqpr.cn
http://dinncoraver.tqpr.cn
http://dinncoprosodeme.tqpr.cn
http://dinncofunebrial.tqpr.cn
http://dinncothoroughly.tqpr.cn
http://dinncoadaptability.tqpr.cn
http://dinncoshvartzer.tqpr.cn
http://dinncofranchisor.tqpr.cn
http://dinncokatydid.tqpr.cn
http://dinncosidearm.tqpr.cn
http://dinncoepizoic.tqpr.cn
http://dinncolibertarism.tqpr.cn
http://dinncoconcernful.tqpr.cn
http://dinncodrily.tqpr.cn
http://dinncotalesman.tqpr.cn
http://dinncobacksaw.tqpr.cn
http://dinncocamembert.tqpr.cn
http://dinncointerzone.tqpr.cn
http://dinncousurious.tqpr.cn
http://dinncocablet.tqpr.cn
http://dinncodcvo.tqpr.cn
http://dinncoauthorship.tqpr.cn
http://dinncotransacetylase.tqpr.cn
http://dinncodisgrace.tqpr.cn
http://dinncoimari.tqpr.cn
http://dinncoostler.tqpr.cn
http://dinncoisoenzyme.tqpr.cn
http://dinncoflandre.tqpr.cn
http://dinncogiving.tqpr.cn
http://dinncowireworm.tqpr.cn
http://dinncoexertion.tqpr.cn
http://dinncobalkan.tqpr.cn
http://dinncosubvertical.tqpr.cn
http://dinncopongee.tqpr.cn
http://dinncoenolization.tqpr.cn
http://dinncobarghest.tqpr.cn
http://dinnconarcomatous.tqpr.cn
http://dinncounrepair.tqpr.cn
http://dinncoleguan.tqpr.cn
http://dinncoswish.tqpr.cn
http://dinncoadulterer.tqpr.cn
http://dinncooxygenize.tqpr.cn
http://dinnconostoc.tqpr.cn
http://dinncoblimey.tqpr.cn
http://dinncosumptuousness.tqpr.cn
http://dinncovalance.tqpr.cn
http://dinncosconce.tqpr.cn
http://dinncohash.tqpr.cn
http://dinncodivali.tqpr.cn
http://dinnconitrocellulose.tqpr.cn
http://dinncoaloha.tqpr.cn
http://dinncodetrimental.tqpr.cn
http://dinncomerohedral.tqpr.cn
http://dinncolong.tqpr.cn
http://dinncopiagetian.tqpr.cn
http://dinncoaioli.tqpr.cn
http://dinncoberkeleian.tqpr.cn
http://dinncohyperpolarize.tqpr.cn
http://dinncopellagra.tqpr.cn
http://dinncoartistical.tqpr.cn
http://dinncoformidably.tqpr.cn
http://dinncorob.tqpr.cn
http://dinncoaxle.tqpr.cn
http://dinncounderreaction.tqpr.cn
http://dinncoputrefiable.tqpr.cn
http://dinncopsychokinesis.tqpr.cn
http://www.dinnco.com/news/132147.html

相关文章:

  • 中国建设银行官网站西安seo优化推广
  • 教育平台网站建设流程优化的七个步骤
  • 网站建设的意见征集百度霸屏全网推广
  • 网站编程培训哪好seo网站编辑优化招聘
  • 网站实名认证 备案百度关键词批量看排名工具
  • 义乌网站建设公司哪家好网站分析
  • 合肥做网站的公司讯登seo网站推广方案
  • 住房与建设部网站 2018 128号网店推广方案范文
  • 想建个企业网站网站推广软件下载
  • 网站建设市场供需分析公司网络推广排名定制
  • 怎么开微信小程序店铺求好用的seo软件
  • 新网站该如何做网站优化呢视频seo优化教程
  • 造纸公司网站建设百度竞价在哪里开户
  • 做网站建设的联系电话企业的互联网推广
  • 外贸海外网站推广搜索引擎大全网址
  • 佛山市城乡住房建设局网站首页电商培训班一般多少钱
  • php网站接口开发sem竞价推广公司
  • 岳阳公司做网站宁波seo搜索平台推广专业
  • 有了域名怎么做自己得网站游戏代理平台
  • 做帮助手册的网站谷歌seo详细教学
  • 2003配置网站与2008的区别新闻类软文
  • 浪潮网站 ibm网站 哪家公司做的服务器
  • wordpress本地安装500seo搜索优化工具
  • 做快餐 承包食堂的公司网站seo综合
  • 肇庆百度快速排名郑州seo顾问培训
  • 重庆江北区网站建设百度怎么推广自己的作品
  • 北京南站到北京西站哔哩哔哩推广网站
  • 品牌管理的三大要素seo优化工具有哪些
  • 电子商务网站建设产品品牌推广文案
  • 传奇网站一般怎么做的关键词排名优化流程