威尼斯人线上娱乐

数据库死锁进程深入分析,clause的解决格局

28 7月 , 2019  

开采题目

mysql中错误:1093-You can’t specify target table for update in FROM clause的消除办法,1093-youclause

意识题目

新近在拍卖部分数据库中数据的时候,写了上边包车型客车这一条sql语句:

UPDATE f_student
SET school_id = 0
WHERE
 id > (
 SELECT
 id
 FROM
 f_student
 WHERE
 school_id = M
 LIMIT 1
 )
AND id < (
 (
 SELECT
 id
 FROM
 f_student
 WHERE
 school_id = M
 LIMIT 1
 ) + N
)

上边包车型大巴sql是想将某些区间的数据开始展览改变,不过放到测量试验情形下一跑,报下边包车型大巴错误:

[Err] 1093 – You can't specify target table ‘f_student' for update in FROM clause

乐趣很醒目了,说不能够对进行查询操作的表进行update操作,也就说咱俩的where条件中实行了子查询,况且子查询也是针对性须要开始展览update操作的表的,mysql不援助这种查询修改的主意。

缓慢解决方法

上网查了眨眼之间间,针对这种难点得以因此”绕”的格局张开落到实处,上边看sql语句。

UPDATE f_student SET school_id = 0 WHERE
                     id > 
                     (
                     SELECT id FROM ( 
                         SELECT id FROM f_student WHERE school_id = M LIMIT 1 
                       ) AS temp 
                     )
                     AND id <
                    (
                     (
                      SELECT id FROM ( 
                              SELECT id FROM f_student WHERE school_id = M LIMIT 1 
                             ) AS temp_1 
                     ) + N
                    )

ok,完全没十分。上边包车型地铁sql相比较于事先的sql只是在取id的时候绕了弹指间,通过四个子查询的章程获得到id,并不是一向开始展览获取。

总结

上述正是那篇小说的全体内容了,希望本文的原委对大家的就学或许专门的学问能带动一定的帮助,如若有疑点我们能够留言沟通。

can’t specify target table
for update in FROM clause的消除措施,1093-youclause 发掘题近些日子段时间在管理局地数据库中多少的时候,写了…

DDL
创造 create  修改 alter  删除 dorp
DML
插入 insert  删除 delete 更新 update
DQL
select from where

这段日子有二个工作须求,多台机械须求同偶尔间从Mysql三个表里查询数据并做继续专门的学业逻辑,为了防御多台机械同一时间拿到均等的数目,每台机械供给在获取时锁住获取数据的数据段,保险多台机械不获得同一的数额。

近来在管理局地数据库中多少的时候,写了上面包车型地铁这一条sql语句:

MySQL与JDBC

咱俩Mysql的蕴藏引擎是innodb,扶助行锁。化解相同的时间拿多少的措施有看不完,为了进一步简便易行,不扩充其余表和劳动的景况下,大家着想采用select…
for
update的格局,那样X锁锁住查询的数据段,表里别的数据未有锁,其余作业逻辑依然得以操作。

UPDATE f_student
SET school_id = 0
WHERE
 id > (
 SELECT
 id
 FROM
 f_student
 WHERE
 school_id = M
 LIMIT 1
 )
AND id < (
 (
 SELECT
 id
 FROM
 f_student
 WHERE
 school_id = M
 LIMIT 1
 ) + N
)

一、用命令行对数据库的操作

那般一台服务器举例select .. for update limit
0,30时,其余服务器施行同一sql语句会活动等待释放锁,等待前一台服务器锁释放后,该台服务器就能够查询下二个30条数据。要是要求更智能,oracle帮忙for
update skip
locked跳过锁区域,那样能不等待立刻询问未有被锁住的下二个30条记下。

上边的sql是想将某些区间的数额开始展览改造,不过放到测量试验意况下一跑,报上面包车型地铁荒谬:

1.  开立贰个库

create database 库名

create database 库名 character set 编码

 威尼斯人线上娱乐 1

 建带有编码的

威尼斯人线上娱乐 2

翻看编码:

 威尼斯人线上娱乐 3

上面说下mysql for update导致的死锁。

[Err] 1093 – You can't specify target table ‘f_student' for update in FROM clause

2.  删减一个库

drop database 库名

 威尼斯人线上娱乐 4

透过解析,mysql的innodb存款和储蓄引擎实际事务锁即便是锁行,但它里面是锁索引的,依照where条件和select的值是或不是唯有主键或非主键索引来决断怎么锁,比方独有主键,则锁主键索引,倘诺独有非主键,则锁非主键索引,即使主键非主键都有,则内部会安分守纪顺序锁。但同样的select
.. for
update语句怎么就死锁了吗?一样的sql语句询问条件和结果顺序都一致,按理不会促成叁个锁了主键索引,等待锁非主键索引,别的贰个锁了非主键索引,等待主键索指点致的死锁。

野趣很分明了,说无法对拓展查询操作的表张开update操作,也就说咱俩的where条件中开始展览了子查询,並且子查询也是对准供给张开update操作的表的,mysql不支持这种查询修改的点子。

3.  使用库

use 库名

 威尼斯人线上娱乐 5

最终经过解析,大家项目里开掘是for
update的sql语句,和其余八个update非select数据的sql语句导致的死锁。

化解措施

4.查看当前正在操作的库

 威尼斯人线上娱乐 6

诸如有60条数据,select .. for
update查询第31-60条数据,update在革新1-10条数据,根据innodb存储引擎的行锁原理,应该不会导致区别行的锁导致的互动等待。起初以为是行锁在数据量比较大动静下,会锁数据块。导致一个段的多寡被锁住,但因此大批量数据测验,开掘以为把整个表都锁住了,但实际上不是。

上网查了须臾间,针对这种难题得以经过”绕”的不二法门开始展览落到实处,上边看sql语句。

二、对数据库表的操作

 下边举多少个例证表达:

UPDATE f_student SET school_id = 0 WHERE
                     id > 
                     (
                     SELECT id FROM ( 
                         SELECT id FROM f_student WHERE school_id = M LIMIT 1 
                       ) AS temp 
                     )
                     AND id <
                    (
                     (
                      SELECT id FROM ( 
                              SELECT id FROM f_student WHERE school_id = M LIMIT 1 
                             ) AS temp_1 
                     ) + N
                    )

1.创制一张表

create table 表名(

    字段名 类型(长度) [约束],

    字段名 类型(长度) [约束],

    字段名 类型(长度) [约束]

);

 威尼斯人线上娱乐 7

数量从id
=伍仟00的数码开首,IsSuccess和GetTime字段都为0,未来一旦陆仟00数额的IsSuccess为1了。推行上面两条sql.

ok,完全没一时。上边包车型地铁sql比较于事先的sql只是在取id的时候绕了一下,通过一个子查询的秘诀获取到id,实际不是一向开始展览获取。

2.翻看数据库表

开创完毕后,大家能够查阅数据库表

show tables;

 威尼斯人线上娱乐 8

查看表的结构

desc 表名

 威尼斯人线上娱乐 9

-- 1:
set autocommit=0;
begin;
select * from table1 where getTime < 1 and IsSuccess=0 order by id asc limit 0,30 for update;
commit;
-- 2:
update table1 a set IsSuccess=0 where id =400000; 

总结

3.去除一张表

drop table 表名

 威尼斯人线上娱乐 10

  第一条sql语句先不commit,则第二条sql语句将只好等待,由此第二条sql语句把IsSuccess修改为0,IsSuccess非主键索引锁了值为0的目录数据,第二条sql语句将不能把数量更新到被锁的行里。

如上正是那篇小说的全体内容了,希望本文的源委对大家的读书恐怕干活能推动一定的扶持,假诺有有失水准态我们能够留言沟通。

4.修改表

再实行下边包车型地铁sql语句

您恐怕感兴趣的作品:

  • mysql “ Every derived table must have its own
    alias”出现谬误化解办法
  • 读取mysql一个库下边包车型地铁全数的表table
  • MySQL不能够重启报错Warning: World-writable config file ‘/etc/my.cnf’
    is ignored的减轻措施
  • mysql Event Scheduler: Failed to open table
    mysql.event
  • mysql中You can’t specify target table for update in FROM
    clause错误化解办法
  • 出现错误mysql Table
    ”performance_schema…化解办法

4.1 增添一列

alter table 表名 add 字段名 类型(长度) [约束]

 威尼斯人线上娱乐 11

-- 1:
set autocommit=0;
begin;
select * from table1 where getTime < 1 and IsSuccess=0 order by id asc limit 0,30 for update;
commit;
-- 2:
update table1 a set IsSuccess=2 where id =400000; 

4.2 修改列的门类(长度、约束)

alter table 表名 modify 要修改的字段名 类型(长度) [约束]

 威尼斯人线上娱乐 12

  那样第二条sql语句将能够试行。因为IsSuccess=2的索引段未有被锁。

4.3 修改列的列名

alter table 表名 change 旧列名 新列名 类型(长度) [约束]

 威尼斯人线上娱乐 13

地点的事例知道了锁索引段后还相比轻巧看懂,上面就奇葩一点:

4.4 删除表的列

alter table 表名 drop 列名

 威尼斯人线上娱乐 14

先把id =四千00数额的GetTime修改为1,IsSuccess=0,然后一回进行sql:

4.5 修改表名

rename table 表名 to 新表名

 威尼斯人线上娱乐 15

-- 1:
set autocommit=0;
begin;
update ctripticketchangeresultdata a set issuccess=1 where id =400000;
commit;
-- 2:
select * from table1 where getTime < 1 and IsSuccess=0 order by id asc limit 0,30 for update; 

4.6 修改表的字符集

alter table 表名 character set 编码

 威尼斯人线上娱乐 16

翻看当前表的编码

 威尼斯人线上娱乐 17

第4个sql先不commit,依据道理只会锁50000那行记录,第三个sql实施,根据道理只好查询从600001记录的30条记下,但第四个sql语句会阻塞等待。

三、对数据库表记录实行操作(修改)

由来是率先个sql语句还尚无commit也向来不rollback,因而它先锁主键索引,再锁IsSuccess的非主键索引,第叁个sql语句由于where里要一口咬住不放IsSuccess字段的值,由于伍仟00那条数据之前的IsSuccess是0,现在革新为1还不明确,大概会回滚,由此sql2急需等待明确四千00那条数据的IsSuccess是或不是被更换。sql2的sql语句因为推断了GetTime<1,实际伍仟00那条记下已经不知足了,但依据锁索引的规律,所以sql2语句会被卡住。

1.插入记录

insert into 表名(列名1,列名2,列名3……) values(值1,值2,值3……)

 威尼斯人线上娱乐 18

insert into 表名 values(值1,值2,值3……)

 威尼斯人线上娱乐 19

因而只要遵照业务场景,能够把sql2语句的IsSuccess条件裁撤掉,何况这里GetTime查询条件由GetTime<1修改为GetTime=0,那样就可以不封堵直接询问出来。

1.1 插入数据汉语乱码问题化解办法

方式一:【不建议!】

平素改造数据库安装目录里面的my.ini文件的第57行

 威尼斯人线上娱乐 20

方式二:

    set names gbk;

 威尼斯人线上娱乐 21

GetTime用范围查询导致的锁影响经过解析,还不是茶余用完餐之后锁的难点,以为应该是用范围作为标准,全部从第0行开首的持有查找范围都会被锁住。
比方这里更新五千00会被堵塞,但革新伍仟31不会被堵塞。

2.修改表记录

大家项目出现死锁,正是以此原理,一条sql语句先锁主键索引,再锁非主键索引;别的一条sql语句先锁非主键索引,再锁主键索引。即便三个sql语句期望锁的数据行分化,但五个sql语句询问或更新的准则或结果字段假使有同样列,则或者会促成相互等待对方锁,2个sql语句即引起了死锁。

2.1 不带条件的

update 表名 set 字段名=值, 字段名=值, 字段名=值……

 威尼斯人线上娱乐 22

它会将该列的享有记录都转移

 

村办总括一下innodb存款和储蓄引擎下的锁的分析,恐怕会有题目:

2.2 带条件的

update 表名 set字段名=值, 字段名=值, 字段名=值…… where 条件

 威尼斯人线上娱乐 23

 

1、更新或询问for
update的时候,会在where条件中开始为每一种字段决断是不是有锁,假若有锁就可以等待,因为若是有锁,那这一个字段的值不鲜明,只好等待锁commit或rollback后数据分明后再查询。

3.删除表记录

2、别的还和order
by有涉嫌,因为恐怕后边数占有锁,但从背后查询五个限量就足以查询。

3.1 带条件的

delete from 表名 where 条件

 威尼斯人线上娱乐 24

 

专注,删除后,uid不会重新载入参数!

 

3、别的limit也是有涉嫌,譬喻limit
20,30从第20条记录取30行数据,但第一行数据假诺被锁,因为不分明回滚依然提交,也会锁等待。

3.2.不带条件的

先绸缪数据

insert into tbl_user values(null,’老王’,’666’);

 

剔除操作

数据库死锁进程深入分析,clause的解决格局。    delete from 表名;

 威尼斯人线上娱乐 25

 

 

 ps:mysql使用kill命令消除死锁难点,杀死某条正在实施的sql语句

3.3 面试题

说说delete与truncate的区别?

delete删除的时候是一条一条的删除记录,它极其工作,能够将去除的数额找回。

truncate删除,它是将整身体表面摧毁,然后再成立一雷文杰模二样的表。它删除的数目不能够找回。

 

Delete操作演示:

 威尼斯人线上娱乐 26

Truncate操作演示

 威尼斯人线上娱乐 27

 

留意:delete删除,uid不会重新初始化!而利用truncate操作,uid会重新载入参数

 

 

 使用mysql运营某个语句时,会因数据量太大而致使死锁,未有展示。那一年,就供给kill掉某些正在消耗电源的query语句就可以, KILL命令的语法格式如下:

4.查询操作

语法:

    select [distinct] *| 列名,列名 from 表名 [where条件]

复制代码 代码如下:

4.1 简单询问

1.询问全体商品

select * from product;

 威尼斯人线上娱乐 28

 

  1. 询问商品名和商品价位

select pname,price from product;

 威尼斯人线上娱乐 29

 

3.询问全数商品音讯使用表外号

select * from product as  p;

 威尼斯人线上娱乐 30

 

4.询问商品名,使用列小名

select pname as  p from product

 威尼斯人线上娱乐 31

 

5.去掉重复值(遵照价格)

select distinct(price) from product;

先策动数据:

insert into product values (null,’李士雪’,38,null);

 威尼斯人线上娱乐 32

6.将具有的货品的价格+10开始展览体现

select pname,price+10 from product;

 威尼斯人线上娱乐 33

 

KILL [CONNECTION | QUERY] thread_id

4.2 条件查询

1.查询商品名叫”左慈”的商品音讯

威尼斯人线上娱乐 34

2.查询价格>60元的兼具商品音信

 威尼斯人线上娱乐 35

3.询问商品名称含有”士”字的商品音讯

 威尼斯人线上娱乐 36

4.询问商品id在(3,6,9)范围内的享有商品消息

 威尼斯人线上娱乐 37

5.询问商品名称含有”士”字何况id为6的商品新闻

 威尼斯人线上娱乐 38

6.询问id为2依旧6的商品音信

 威尼斯人线上娱乐 39

 

各类与mysqld的接连都在五个单身的线程里运营,您能够动用SHOW
PROCESSLIST语句查看哪些线程正在周转,并选拔KILL
thread_id语句终止三个线程。

4.3 排序

1.询问全部的货品,按价格实行排序(升序、降序)

 威尼斯人线上娱乐 40

威尼斯人线上娱乐 41

 

2.询问名称有”士”的商品音信而且依照标价降序排序

 威尼斯人线上娱乐 42

 

KILL允许自行选购的CONNECTION或QUE奥迪Q7Y修改符:KILL
CONNECTION与不含修改符的KILL同样:它会告一段落与给定的thread_id有关的连日。KILL
QUEEvoqueY会终止连接当前正值实行的语句,但是会保持再而三的原状。

4.4 聚合函数

1.获取全体商品的价钱的总额

 威尼斯人线上娱乐 43

2.到手全数商品的平均价格

 威尼斯人线上娱乐 44

3.获得全部商品的个数

威尼斯人线上娱乐 45

只要您具有PROCESS权限,则您可以查阅全数线程。即使你有所最棒管理员权限,您可以告一段落全部线程和语句。不然,您不得不查看和截止您本人的线程和言辞。您也得以应用mysqladmin
processlist和mysqladmin kill命令来检查和小憩线程。

4.5 分组操作

1.加多分拣id (alter table product add cid varchar(32);)

2.早先化数据

update product set cid=’1′;

update product set cid=’2′ where  pid in (5,6,7);

1.基于cid字段分组,分组后总计商品的个数。

 威尼斯人线上娱乐 46

2.依照cid分组,分组总计每组商品的平均价格,况兼平均价格大于30000元。

 威尼斯人线上娱乐 47

率首先登场陆mysql,然后使用: show processlist;
查看当前mysql中逐条线程状态。

4.6 查询总计

select  一般在的前面包车型大巴源委都以要询问的字段

from  要询问到表

where

group by

having  分组后含有条件只可以利用having

order by 它必须置于最前面

 

mysql> show processlist;
+------+------+----------------------+----------------+---------+-------+-----------+--------------------- 
| Id  | User | Host         | db       | Command | Time | State   | Info
+------+------+----------------------+----------------+---------+-------+-----------+--------------------- 
| 7028 | root | ucap-devgroup:53396 | platform    | Sleep  | 19553 |      | NULL
| 8352 | root | ucap-devgroup:54794 | platform    | Sleep  | 4245 |      | NULL
| 8353 | root | ucap-devgroup:54795 | platform    | Sleep  |   3 |      | NULL
| 8358 | root | ucap-devgroup:62605 | platform    | query  | 4156 | updating | update t_shop set |

二、回看JDBC,落成查询

上述呈现出脚下正值实行的sql语句列表,找到消耗电源最大的那条语句对应的id.

1 什么是JDBC

  JDBC(Java DataBase
Connectivity)正是Java数据库连接,说白了正是用Java语言来操作数据库。原本大家操作数据库是在调节台使用SQL语句来操作数据库,JDBC是用Java语言向数据库发送SQL语句。

接下来运转kill命令,命令格式如下:

2 JDBC原理

中期SUN集团的天资们想编写一套可以接二连三天下全数数据库的API,不过当她们刚刚开始时就意识那是不足达成的职分,因为各种厂家的数据库服务器差距太大了。后来SUN始于与数据库厂家们座谈,最终得出的定论是,由SUN提供一套访谈数据库的科班(正是一组接口),并提供连接数据库的商谈正式,然后逐个数据库香港中华厂商联合会坚守SUN的正规化提供一套访问自身公司的数据库服务器的API出现。SUN提供的正规命名称为JDBC,而相继商家提供的,遵从了JDBC标准的,能够访谈自身数据库的API被喻为驱动!

威尼斯人线上娱乐 48

JDBC是接口,而JDBC驱动才是接口的达成,未有驱动无法实现数据库连接!种种数据库厂家都有和好的驱动,用来再而三本身公司的数据库。

自然还只怕有第三方商号特意为某一数据库提供驱动,这样的驱动往往不是开源无需付费的!

 

kill id;
— 示例:
 kill 8358

3 JDBC核心类(接口)介绍

JDBC中的宗旨类有:DriverManager、Connection、Statement,和ResultSet!

DriverManger(驱动管理器)的意义有四个:

l  注册驱动:那能够让JDBC知道要动用的是哪位驱动;


获取Connection:借使得以博得到Connection,那么阐明已经与数据库连接上了。

Connection对象表示连接,与数据库的报导都以通过这么些指标举行的:

l  Connection最为关键的一个措施正是用来得到Statement对象;


Statement是用来向数据库发送SQL语句的,那样数据库就会试行发送过来的SQL语句

l  void executeUpdate(String
sql):推行更新操作(insert、update、delete等);

l  ResultSet executeQuery(String
sql):施行查询操作,数据库在施行查询后会把询问结果,查询结果正是ResultSet;

ResultSet对象表示查询结果集,只有在实行查询操作后才会有结果集的爆发。结果集是三个二维的报表,有行有列。操作结果集要上学活动ResultSet内部的“行光标”,以及取稳当前行上的每一列上的数码:

l  boolean next():使“行光标”移动到下一行,并重回移动后的行是或不是存在;

l  XXX getXXX(int
col):获取当前行内定列上的值,参数正是列数,列数从1发端,并不是0。

 

干掉就可以。

4 Hello JDBC

 下边开首编制第三个JDBC程序

介绍eclipse的相关文化

单元测验junit

你或然感兴趣的小说:

  • Mysql数据库锁定机制详细介绍
  • mysql锁表和平解决锁语句分享
  • MySQL行级锁、表级锁、页级锁详细介绍
  • MySQL
    Innodb表导致死锁日志景况分析与综合
  • MYSQL锁表难题的减轻方法
  • mysql
    数据库死锁原因及化解办法
  • mysql
    锁表锁行语句分享(MySQL事务管理)
  • 一次Mysql死锁排查过程的全纪录
  • Mysql(MyISAM)的读写互斥锁难题的缓慢解决办法
  • mysql锁定单个表的法子
  • 找寻MySQL线程中死锁的ID的点子
  • MySQL锁机制与用法深入分析

4.1 导入mysql数据库的驱动jar包:

mysql-connector-java-5.1.39-bin.jar;

4.2 注册驱动

看精晓了,注册驱动就独有一句话:Class.forName(“com.mysql.jdbc.Driver”),上边包车型大巴源委都以对那句代码的解释。未来我们的代码中,与注册驱动相关的代码唯有这一句。

DriverManager类的registerDriver()方法的参数是java.sql.Driver,但java.sql.Driver是一个接口,实现类由mysql驱动来提供,mysql驱动中的java.sql.Driver接口的兑现类为com.mysql.jdbc.Driver!那么注册驱动的代码如下:

DriverManager.registerDriver(new com.mysql.jdbc.Driver());

位置代码固然能够注册驱动,不过出现硬编码(代码注重mysql驱动jar包),即使今后想连接Oracle数据库,那么需求求修改代码的。并且实际这种注册驱动的不二诀要是注册了两遍驱动!

JDBC中分明,驱动类在被加载时,须求和谐“主动”把团结注册到DriverManger中,上边大家来看看com.mysql.jdbc.Driver类的源代码:

com.mysql.jdbc.Driver.java

public class Driver extends NonRegisteringDriver implements java.sql.Driver {

    static {

        try {

            java.sql.DriverManager.registerDriver(new Driver());

        } catch (SQLException E) {

            throw new RuntimeException("Can’t register driver!");

        }

    }

……

}

 

com.mysql.jdbc.Driver类中的static块会成立本类对象,并登记到DriverManager中。这注明只要去加载com.mysql.jdbc.Driver类,那么就能够奉行这些static块,进而也就能够把com.mysql.jdbc.Driver注册到DriverManager中,所以能够把挂号驱动类的代码修改为加载驱动类

Class.forName(“com.mysql.jdbc.Driver”);

4.3 获取连接

取得连接要求两步,一是选择DriverManager来注册驱动,二是使用DriverManager来获取Connection对象。

 

获取连接的也独有一句代码:

DriverManager.getConnection(url,username,password),

当中username和password是登陆数据库的用户名和密码,假如本身没说错的话,你的mysql数据库的用户名和密码分别是:root、123。

url核查复杂一点,它是用来找到要连接数据库“网站”,就好比你要浏览器中检索百度时,也亟需提供贰个url。上边是mysql的url:

jdbc:mysql://localhost:3306/mydb1

威尼斯人线上娱乐,JDBC规定url的格式由三局地构成,每种部分中档使用冒号分隔。

l  第一有的是jdbc,这是定位的;

l  第二部分是数据库名称,那么连接mysql数据库,第二有个别当然是mysql了;


第三部分是由数据库厂家规定的,大家供给精通各类数据库厂家的需求,mysql的第三有的各自由数据库服务器的IP地址(localhost)、端口号(3306),以及DATABASE名称(mydb1)组成。

 

下边是得到连接的言辞:

Connection con =
DriverManager.getConnection(“jdbc:mysql://localhost:3306/web08”,”root”,”root”);

 

还足以在url中提供参数:

jdbc:mysql://localhost:3306/web08?useUnicode=true&characterEncoding=UTF8

useUnicode参数钦定那么些延续数据库的进程中,使用的字节集是Unicode字节集;

characherEncoding参数钦命穿上连年数据库的进度中,使用的字节集编码为UTF-8编码。请留意,mysql中钦赐UTF-8编码是付诸的是UTF8,实际不是UTF-8。要小心了!

 

4.4 获取Statement

在获取Connectoin之后,表达已经与数据库连接上了,上边是经过Connection获取Statement对象的代码:

Statement stmt = con.createStatement();

Statement是用来向数据库发送要推行的SQL语句的!

4.5 发送SQL查询语句

String sql = “select * from user”;

ResultSet rs = stmt.executeQuery(sql);

请留意,推行查询利用的不是executeUpdate()方法,而是executeQuery()方法。executeQuery()方法重返的是ResultSet,ResultSet封装了询问结果,我们称为结果集。

4.6 读取结果聚焦的多少

ResultSet就是一张二维的表格,它在这之中有二个“行光标”,光标暗许的任务在“第一行上方”,我们能够调用rs对象的next()方法把“行光标”向下活动一行,当第三次调用next()方法时,“行光标”就到了第一行记录的职责,那时就能够使用ResultSet提供的getXXX(int
col)方法来赢得钦命列的数额了:

rs.next();//光标移动到第一行

rs.getInt(1);//获取第一行第一列的数额

当你采用rs.getInt(1)方法时,你无法无法肯定第1列的数据类型就是int类型,借让你不可能确定,那么最棒利用rs.getObject(1)。在ResultSet类中提供了一密密麻麻的getXXX()方法,比较常用的艺术有:

Object getObject(int col)

String getString(int col)

int getInt(int col)

double getDouble(int col)

4.7 关闭

与IO流同样,使用后的东西都亟需关闭!关闭的一一是先获得的后关闭,后获得的先关闭。

rs.close();

stmt.close();

con.close();

4.8 完结查询操作代码

    public static Connection getConnection() throws Exception {

        Class.forName("com.mysql.jdbc.Driver");

        String url = "jdbc:mysql://localhost:3306/web08";

        return DriverManager.getConnection(url, "root", "root");

    }

    @Test

    public void query() throws Exception {

        Connection con = getConnection();

        Statement stmt = con.createStatement();

        String sql = "select * from user";

        ResultSet rs = stmt.executeQuery(sql);

        while(rs.next()) {

            String username = rs.getString(1);

            String password = rs.getString(2);

            System.out.println(username + ", " + password);

        }

    }

 

4.9 标准化代码

所谓规范化代码便是随意是还是不是出现至极,都要关闭ResultSet、Statement,以及Connection,尽管您还记得IO流的标准化代码,那么下边包车型客车代码你就驾驭什么看头了。

 

    @Test

    public void query() {

        Connection con = null;

        Statement stmt = null;

        ResultSet rs = null;

        try {

            con = getConnection();

            stmt = con.createStatement();

            String sql = "select * from user";

            rs = stmt.executeQuery(sql);

            while(rs.next()) {

                String username = rs.getString(1);

                String password = rs.getString(2);

                System.out.println(username + ", " + password);

            }

        } catch(Exception e) {

            throw new RuntimeException(e);

        } finally {

            try {

                if(rs != null) rs.close();

                if(stmt != null) stmt.close();

                if(con != null) con.close();

            } catch(SQLException e) {}

        }

    }

 

JDBC对象介绍

 

1 JDBC中的首要类(接口)

在JDBC中常用的类有:

l  DriverManager;

l  Connection;

l  Statement;

l  ResultSet。

 

2 DriverManager

实则我们之后只供给会用DriverManager的getConnection()方法就可以:

  1. Class.forName(“com.mysql.jdbc.Driver”);//注册驱动
  2. String url = “jdbc:mysql://localhost:3306/web08”;
  3. String username = “root”;
  4. String password = “root”;
  5. Connection con = DriverManager.getConnection(url, username,
    password);

 

只顾,上面代码大概出现的二种非常:

  1. ClassNotFoundException:那一个可怜是在第1句上面世的,出现那一个非常有八个只怕:

l  你从未给出mysql的jar包;

l  你把类名称打错了,查看类名是或不是com.mysql.jdbc.Driver。

 

  1. SQLException:这些非常出现在第5句,出现那几个极度即是几个参数的标题,往往username和password一般不是失误,所以须要认真查看url是或不是打错。

 

对此DriverManager.registerDriver()方法理解就能够,因为大家未来登记驱动只会Class.forName(),而不会动用那个措施。

3 Connection

Connection最为关键的艺术正是获得Statement:

l  Statement stmt = con.createStatement();

 

末端在攻读ResultSet方法时,还要学习一下底下的方法:

l  Statement stmt = con.createStatement(int,int);

 

4 Statement

Statement最为重大的点子是:

l  int executeUpdate(String
sql):施行更新操作,即实行insert、update、delete语句,其实那一个点子也得以实践create
table、alter table,以及drop
table等语句,但我们相当少会动用JDBC来实践这个言辞;

l  ResultSet executeQuery(String
sql):试行查询操作,实施查询操作会重临ResultSet,即结果集。

 

l   boolean execute()

Statement还也许有三个boolean
execute()方法,这一个措施能够用来实行增、删、改、查全体SQL语句。该格局重返的是boolean类型,表示SQL语句是还是不是实施成功。

假若使用execute()方法实施的是翻新语句,那么还要调用int
getUpdateCount()来博取insert、update、delete语句所影响的行数。

譬如使用execute()方法实施的是询问语句,那么还要调用ResultSet
getResultSet()来赢得select语句的询问结果。

 

5 ResultSet之滚动结果集(领悟)

ResultSet表示结果集,它是三个二维的报表!ResultSet内部维护八个行光标(游标),ResultSet提供了一三种的章程来运动游标:

l  void beforeFirst():把光标放到第一行的前头,那也是光标暗中认可的职分;

l  void afterLast():把光标放到最终一行的前面;

l  boolean
first():把光标放到第一行的岗位上,再次来到值表示调节光标是不是成功;

l  boolean last():把光标放到末了一行的岗位上;

l  boolean isBeforeFirst():当前光标地点是还是不是在首先行前面;

l  boolean isAfterLast():当前光标地点是或不是在结尾一行的后边;

l  boolean isFirst():当前光标地点是还是不是在首先行上;

l  boolean isLast():当前光标地点是还是不是在最终一行上;

l  boolean previous():把光标向上挪一行;

l  boolean next():把光标向下挪一行;

l  boolean relative(int
row):相对位移,当row为正数时,表示向下移动row行,为负数时表示发展移动row行;

l  boolean absolute(int row):相对位移,把光标移动到钦定的行上;

l  int getRow():重临当前光标全体行。

 

地方方法分为两类,一类用来决断游标地点的,另一类是用来运动游标的。假若结果集是不可滚动的,那么只好使用next()方法来移动游标,而beforeFirst()、afterLast()、first()、last()、previous()、relative()方法都不能利用!!!

结果集是还是不是帮助滚动,要从Connection类的createStatement()方法聊起。也正是说创设的Statement决定了应用Statement创建的ResultSet是或不是支持滚动。

Statement createStatement(int resultSetType, int resultSetConcurrency)

resultSetType的可选值:

l  ResultSet.TYPE_FORWARD_ONLY:不滚动结果集;


ResultSet.TYPE_SCROLL_INSENSITIVE:滚动结果集,但结果集数据不会再尾随数据库而生成;


ResultSet.TYPE_SCROLL_SENSITIVE:滚动结果集,但结果集数据不会再尾随数据库而更换;

 

可以看出,假设想利用滚动的结果集,大家应有采用TYPE_SCROLL_INSENSITIVE!其实非常少有数据库驱动会协助TYPE_SCROLL_SENSITIVE的特点!经常大家也不须要查询到的结果集再境遇数据库变化的熏陶。

 

resultSetConcurrency的可选值:


CONCUR_READ_ONLY:结果集是只读的,不能够透过修改结果集而反向影响数据库;


CONCUR_UPDATABLE:结果集是可更新的,对结果集的创新能够反向影响数据库。

 

一般说来可更新结果集这一“高等特性”我们也是不须要的!

 

收获滚动结果集的代码如下:

Connection con = …

Statement stmt =
con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
CONCUR_READ_ONLY);

String sql = …//查询语句

ResultSet rs = stmt.executeQuery(sql);//这么些结果集是可滚动的

 

6 ResultSet之获取列数据

能够由此next()方法使ResultSet的游标向下移动,当游标移动到您供给的行时,就供给来获取该行的多少了,ResultSet提供了一密密麻麻的获得列数据的不二秘技:

l  String getString(int columnIndex):获取钦赐列的String类型数据;

l  int getInt(int columnIndex):获取内定列的int类型数据;

l  double getDouble(int columnIndex):获取钦定列的double类型数据;

l  boolean getBoolean(int columnIndex):获取钦点列的boolean类型数据;

l  Object getObject(int columnIndex):获取内定列的Object类型的多寡。

 

上面方法中,参数columnIndex表示列的目录,列索引从1从头,实际不是0,那首先点与数组分裂。倘令你知道当前列的数据类型,那么能够应用getInt()之类的方式来获得,假让你不明了列的门类,那么您应当采用getObject()方法来获得。

ResultSet还提供了一套通过列名称来收获列数据的秘籍:

l  String getString(String
columnName):获取名称叫columnName的列的String数据;

l  int getInt(String columnName):获取名叫columnName的列的int数据;

l  double getDouble(String
columnName):获取名为columnName的列的double数据;

l  boolean getBoolean(String
columnName):获取名字为columnName的列的boolean数据;

l  Object getObject(String
columnName):获取名称叫columnName的列的Object数据;

 

PreparedStatement

1 什么是SQL攻击

在须要用户输入的地点,用户输入的是SQL语句的一部分,最后用户输入的SQL片段与我们DAO中写的SQL语句合成叁个完好的SQL语句!举例用户在登入时输入的用户名和密码都认为SQL语句的部分!

 

2 演示SQL攻击

先是大家必要成立一张用户表,用来存款和储蓄用户的新闻。

CREATE TABLE user(

    uid CHAR(32) PRIMARY KEY,

    username   VARCHAR(30) UNIQUE KEY NOT NULL,

    PASSWORD   VARCHAR(30)

);

 

INSERT INTO user VALUES(‘U_1001’, ‘zs’, ‘zs’);

SELECT * FROM user;

于今用户表中独有一行记录,就是zs。

上面大家写叁个login()方法!

    public void login(String username, String password) {

        Connection con = null;

        Statement stmt = null;

        ResultSet rs = null;

        try {

            con = JdbcUtils.getConnection();

            stmt = con.createStatement();

            String sql = "SELECT * FROM user WHERE " +

                    "username=’" + username +

                    "’ and password=’" + password + "’";

            rs = stmt.executeQuery(sql);

            if(rs.next()) {

                System.out.println("欢迎" + rs.getString("username"));

            } else {

                System.out.println("用户名或密码错误!");

            }

        } catch (Exception e) {

            throw new RuntimeException(e);

        } finally {

            JdbcUtils.close(con, stmt, rs);

        }      

    }

 

下边是调用这么些主意的代码:

login("a’ or ‘a’=’a", "a’ or ‘a’=’a");

 

那行当前会使我们登入成功!因为是输入的用户名和密码是SQL语句片段,最后与大家的login()方法中的SQL语句组合在一道!大家来看看组合在一齐的SQL语句:

SELECT * FROM tab_user WHERE username=’a’ or ‘a’=’a‘ and password=’a’ or ‘a’=’a

 

3 防止SQL攻击

l  过滤用户输入的数额中是还是不是含有非法字符;

l  分步兵学校验!先采纳用户名来查询用户,假设查找到了,再比较密码;

l  使用PreparedStatement。

4 PreparedStatement是什么?

PreparedStatement叫预编写翻译评释!

PreparedStatement是Statement的子接口,你能够使用PreparedStatement来替换Statement。

PreparedStatement的好处:

l  防止SQL攻击;

l  升高代码的可读性,以可维护性;

l  提升功用。

5 PreparedStatement的使用

l  使用Connection的prepareStatement(String
sql):即创设它时就让它与一条SQL模板绑定;

l  调用PreparedStatement的setXXX()连串措施为问号设置值


调用executeUpdate()或executeQuery()方法,但要注意,调用未有参数的格局;

 

String sql = “select * from tab_student where s_number=?”;

PreparedStatement pstmt = con.prepareStatement(sql);

pstmt.setString(1, “S_1001”);

ResultSet rs = pstmt.executeQuery();

rs.close();

pstmt.clearParameters();

pstmt.setString(1, “S_1002”);

rs = pstmt.executeQuery();

 

在利用Connection成立PreparedStatement对象时索要提交一个SQL模板,所谓SQL模板正是有“?”的SQL语句,当中“?”就是参数。

在赢得PreparedStatement对象后,调用它的setXXX()方法为“?”赋值,那样就能够获得把模版变成一条完整的SQL语句,然后再调用PreparedStatement对象的executeQuery()方法取得ResultSet对象。

留心PreparedStatement对象唯有的executeQuery()方法是不曾参数的,而Statement的executeQuery()是索要参数(SQL语句)的。因为在开创PreparedStatement对象时已经让它与一条SQL模板绑定在一同了,所以在调用它的executeQuery()和executeUpdate()方法时就不再须要参数了。

PreparedStatement最大的功利正是在乎重复使用同一模板,给予其区别的参数来再度的施用它。这才是真正提升功能的来由。

 

就此,提议我们在后来的开拓中,无论怎么意况,都去须求PreparedStatement,并不是使用Statement。

 


相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图