数据库基础笔记
博客目录
一、创建表:
注释:用 – 或则 /**/
sql关键字大小写不敏感,建议小写,所有符号全部用英文。
create table if not exists 表名(
`字段名` 列类型 [属性] [索引] [注释],
`字段名` 列类型 [属性] [索引] [注释],
..............
`字段名` 列类型 [属性] [索引] [注释],
PRIMARY KEY(`id`)
)
create table if not exists student(
`id` int(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
`name` VARCHAR(20) NOT NUll DEFAULT '匿名' COMMENT '姓名',
`pwd` VARCHAR(20) NOT NUll DEFAULT '123456' COMMENT '密码',
`sex` VARCHAR(2) NOT NULL DEFAULT '女' COMMENT '性别',
`birthday` DATETIME DEFAULT NULL COMMENT '出生日期',
`address` VARCHAR(100) DEFAULT NULL COMMENT '家庭住址',
`email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY(`id`)--主键
)ENGINE=INNODB DEFAULT CHARSET=utf8;--数据库引擎和字符编码
/*
CHARSET=utf8
不设置的话,会是mysql默认的字符集编码~(不支持中文!)
MySQL的默认编码是Latin1,不支持中文
*/
SHOW CREATE database ;数据库名/*查看数据库如何创建*/
CREATE DATABASE `westos` ;/*!40100 DEFAULT CHARACTER SET utf8 */
SHOW CREATE TABLE 表名;/*查看创建表的语句*/
DESC 表名;/*查看表的结构*/
数据引擎:
INNODB | MYISAM | |
---|---|---|
事物支持 | 支持 | 不支持 |
数据库行锁 | 支持 | 不支持 |
外键 | 支持 | 不支持 |
全文索引 | 不支持 | 支持 |
表空间大小 | 较小 | 较大,约为2倍 |
常规操作:
(1)INNODB:安全性高,事物的处理,多表多用户;
(2)MYISAM:节约空间,速度较快
所有的数据库文件存在data目录下,本质上还是文件存储。
二、修改表:
--修改表名: alter table 旧表名 RENAME AS 新表名
alter TABLE user RENAME AS user1;
--增加表的字段: ALTER TABLE 表名 add 字段名 列属性
alter TABLE user1 add age INT(11);
--修改表的字段(重命名,修改约束!)
ALTER TABLE user1 MODIFY age VARCHAR(11);--修改约束
ALTER TABLE user1 change age agel INT(1);--字段重名名
--删除表的字段
alter TABLE user1 drop age1;
--删除表
drop TABLE if exists user1;
三、MySQL数据库管理
3.1外键(了解):
/*方式一*/
--学生表的 gradeid字段要去引用年级表的gradeid
--定义外键key
--给这个外键添加约束(执行引用)references引用
create table if not exists student(
`id` int(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
`name` VARCHAR(20) NOT NUll DEFAULT '匿名' COMMENT '姓名',
`pwd` VARCHAR(20) NOT NUll DEFAULT '123456' COMMENT '密码',
`sex` VARCHAR(2) NOT NULL DEFAULT '女' COMMENT '性别',
`birthday` DATETIME DEFAULT NULL COMMENT '出生日期',
`address` VARCHAR(100) DEFAULT NULL COMMENT '家庭住址',
`email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
`gradeid` INT(10) NOT NULL COMMENT '学生的年级',
PRIMARY KEY(`id`),
KEY `fk_grade` (`gradeid`),
CONSTRAINT `fk_grade_id` FOREIGN KEY (`gradeid`) REFERENCES `grade`(`gradeid`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
CREATE TABLE `grade`(
`gradeid` INT(10) NOT NULL AUtO_INCREMENT COMMENT '年级id',
`gradename` VARCHAR(50) NOT null COMMENT '年级名称',
PRIMARY KEY(`gradeid`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
/*
删除有外键关系的表的时候,必须要先删除引用别人的表(从表),再删除被引用的表(主表)
*/
/*方式二*/
--创建表成功后,添加外键约束
--创建表的时候没有外键关系
ALTER TABLE `student`
ADD CONSTRAINT `FK_gradeid` FOREIGN KEY( `gradeid` ) REFERENCES `grade` ( `gradeid`);
--ALTER TABLE 表ADD CONSTRAINT约束名FOREIGN KEY(作为外键的列)REFERENCES那个表(哪个字段)
以上的操作都是物理外键,数据库级别的外键,我们不建议使用!(避免数据库过多造成困扰)
最佳方法
数据库就是单纯的表,只用来存数据,只有行(数据)和列(字段)
我们想使用多张表的数据,想使用外键(程序去实现)
3.2、DML语言(数据库操作语言)
数据库意义:数据存储,数据管理
1、添加(insert)
--插入语句(添加)
-- insert into表名([字段名1,字段2,字段3]) values('值1','值2','值3,...)
insert into `grade`(`gradename`) values ('大学')
--由于主键自增我们可以省略(如果不写表的字段,他就会——匹配)
insert into `grade` values ('高中')
--一般写插入语句,我们一定要数据和字段——对应!
/*插入多条语句*/
insert into `grade`(`gradename`,`gradenum`) values ('大一',52),('大二',52);
/*
注意事项:
1.字段和字段之间使用英文逗号隔开
2.字段是可以省略的,但是后面的值必须要和数据库定义字段一一对应,不能少
3.可以同时插入多条数据,VALUES后面的值,需要使用,隔开即可 values(),(),....
*/
2、修改(update)
/*修改语句*/
/*
两种理解:
语法1:update 表名 set 字段1=修改值, 字段2=修改值,....... where 条件;
语法2:update 表名 set colnum_name1=value, colnum_name2=value,....... where 条件;
*/
update `student` set `name`='小吴呀',`sex`='女' where `id`=1;
--不指定条件的情况下会改动所有表
update update `student` set `name`='小吴呀',`sex`='女'
/*
注意:
colnum_name是数据库的列,尽量带上``
条件,筛选的条件,如果没有指定,则会修改所有的列
value,是一个具体的值,也可以是一个变量
设置多个字段的值使用英文逗号隔开
UPDATE ‘student’ SET birthday'= CURRENT_TIME WHERE name'='长江7号’AND sex='女'
*/
3、删除(delete)
/*删除数据*/
/*
语法:delete from 表名 where 条件;
*/
--删除数据(避免出现这样的情况,会全部删除)
delete from `student`
--删除指定数据
delete from `student` where id=1;
/*清空一个表中数据的方法*/
--Truncate 表名;
truncate `student`;
/*
delete和truncate删除表的区别
1.delete from 表名;
删除数据不会影响主键的自增
2.Truncate 表名;
删除数据后主键的自增会归零,也就是说会影响到主键的自增
*/
了解即可:DELETE删除的问题,重启数据库,现象
INNODB:自增列会重1开始―(存在内存当中的,断电即失)
MylSAM:继续从上一个自增量开始(存在文件中的,不会丢失)
3.3、DQL查询数据(数据库查询语言)
1、基础查询语法
/*查询语句结构和位置*/ SELECT [ALL l DISTINCT] {* l table.* / [table.field1[as alias1][,table.field2[as alias2]][,...]]]} FROM table_name [as tab1e_alias] [left / right l inner join table_name2]--联合查询 [WHERE ...]--指定结果需满足的条件 [GROUP BY ...]--指定结果按照哪几个字段来分组 [HAVING]--过滤分组的记录必须满足的次要条件 [ORDER BY ...]--指定查询记录按一个或多个条件排序 [LIMIT {[offset,]row_count l row_countOFFSET offset}]; --指定查询的记录从哪条至哪条 /*查询语句*/ --查询所有的信息 select*from student; --查询指定字段 select `studentnumber`,`studentname` from `student`; --给字段起别名,用AS,也可以给表起别名,用AS select `studentnumber` as 学号,`studentname` as 姓名 from `student`; --函数 拼接字符串Concat(a,b) select CONCAT('姓名:',studentname) AS 新名字 from student;
2、去重:distinct
--查询哪些同学参加了考试
select `studentnumber` from result;
select DISTINCT `studentnumber` from result;--去掉重复的数据
select version();--查询mysql系统版本
select 100*3-1 AS 计算结果;--用于计算
select @@auto_increment_increment;--查询自增的步长
/*将学生的成绩加一分*/
select `studentnumber`,`studentresult`+1 as '加分后' from result;
3、where条件子句
作用:检索数据中符合条件的值
(1)逻辑运算符
运算符 | 语法 | 描述 |
---|---|---|
and && | a and b a&&b | 逻辑与 两个都为真结果为真 |
or || | a or b a||b | 逻辑或 其中一个为真结果为真 |
not ! | not a !a | 逻辑非 真为假 ,假为真 |
--and和&& 两者可以互换
select studentno,studentresult from result
where 80<studentresult and studentresult<100;
--查询区间(between...and...)
select studentno,studentresult from result
where studentresult between 70 and 100;
--not和!=
select studentno,studentresult from result
where not studentno=1000;
select studentno,studentresult from result
where studentno!=1000;
(2)比较运算符(模糊查询)
运算符 | 语法 | 描述 |
---|---|---|
IS NULL | a is null | 如果操作符为NULL,结果为真 |
IS NOT NULL | a is not null | 如果操作符不为空,结果为真 |
BETWEEN | a between b and c | 如在b和c之间,则结果为真 |
Like | a like b | SQL匹配,如果a匹配b,则结果为真 |
IN | a in(a1,a2,a3) | 假设a在a1或者a2…其中的某一个值,结果为真 |
/*模糊查询*/
--查询姓罗的同学,like结合 %(代表0到任意个字符) _代表一个字符
select `studentno`, `studentname` from student
where studentname like '罗%';--查询名字为任意多个字的并且姓罗
select `studentno`, `studentname` from student
where studentname like '罗_';--查询名字为两个字的并且姓罗
select `studentno`, `studentname` from student
where studentname like '%罗%';--查询名字中带有罗字的人
--in
select `studentno`, `studentname` from student
where studentno in(1001,1002,1003);--查询序号为1001,1002,1003的学生
--null not null
select `studentno`, `studentname`,`address` from student
where address='' or address is null;--查询地址为空的记录
select `studentno`, `studentname`,`address`,`birthday` from student
where birthday is not null ;--查询出生日期不为空的人
4、联表查询
学生科目表(subject):
学生信息表(student):
学生成绩表(result):
/*查询参加了考试的学生(学号,姓名,科目编号,分数)*/
--inner join
select s.studentno,studentname,subjectno,studentresult
from student as s inner join result as r
where s.studentno=r.studentno;
--right join(左连接)
select s.studentno,studentname,subjectno,studentresult
from student as s right join result as r
on s.studentno=r.studentno;
--left join(右连接)
select s.studentno,studentname,subjectno,studentresult
from student as sleft join result as r
on s.studentno=r.studentno;
/*
查询参加考试同学的信息:学号,学生姓名,科目名,分数
(学号,学生姓名)来自student表,(科目名)来自subject表,(学号,分数)来自result表
*/
select s.studentno,studentname,subjectname,studentresult
from student s
right join result r
on s.studentno=r.studentno
inner join subject sub
on r.subjectno=sub.subjectno;
操作 | 描述 |
---|---|
inner join | 如果表中至少有一个匹配就返回 |
left join | 会从左表中返回所有的值,即使右表中没有匹配 |
right join | 会从右表中返回所有的值,即使左表中没有匹配 |
自连接(了解):
自己的表和自己的表连接,本质:一张表拆为一样的表即可
5、分页和排序
排序
/*
排序:升序 ASC 降序:DESC
语法:order by 排序字段 升序(降序)
*/
select s.studentno,studentname,subjectname,studentresult
from student s
right join result r
on s.studentno=r.studentno
inner join subject sub
on r.subjectno=sub.subjectno
order by studentresult DESC;
分页
/*
limit 起始值(从哪条数据[数据的下标是从0开始的]开始查) 查询数据条数
第一页 limit 0,5 (1-1)*5
第二页 limit 5,5 (2-1)*5
第三页 limit 10,5 (3-1)*5
第N页 limit 0,5 (n-1)*pagesize
[pagesize:页面包含多少条数据,(n-1)*pagesize 起始, n当前页码 ,数据总数/页面大小=总页数]
*/
select s.studentno,studentname,subjectname,studentresult
from student s
right join result r
on s.studentno=r.studentno
inner join subject sub
on r.subjectno=sub.subjectno
order by studentresult DESC
limit 0,2;
/*
题目:查询java程序设计-1课程成绩排名前十的学生,并且要求分数要大于80分(学号,姓名,课程名称,分数)
*/
select s.studentno,studentname,subjectname,studentresult
from student s
inner join result r
on s.studentno=r.studentno
inner join subject sub
on r.subjectno=sub.subjectno
where subjectname='java程序设计-1'
and studentresult>=80
order by studentresult DESC
limit 0,10;
6、子查询
也叫嵌套查询,在where中在嵌套查询语句
/*
查询高等数学-1的所有考试结果(学号,科目编号,科目名称,成绩)按成绩升序排列;
*/
--方式一:非子查询(链表查询)
select studentno,r.subjectno,subjectname,studentresult
from result r
inner join subject sub
on r.subjectno=sub.subjectno
where subjectname='高等数学-1'
order by studentresult ASC
--方式二:子查询
select studentno,subjectno,studentresult
from result
where subjectno=(
select subjectno from subject where subjectname='高等数学-1'
)
order by studentresult ASC
/*查询高等数学-1分数不小于70分的学号,姓名,成绩并升序排列*/
--子查询一
select distinct r.studentno,studentname,studentresult
from student s
inner join result r
on r.studentno=s.studentno
where studentresult>70
and subjectno=(select subjectno from subject where subjectname='高等数学-1')
order by studentresult ASC
/*查询高等数学-1分数不小于70分的学号,姓名*/
--子查询二
select studentno,studentname
from student
where studentno
in(select studentno from result where studentresult>70
and subjectno=(select subjectno from subject where subjectname='高等数学-1'))
7、mysql函数
常用函数
/*数学运算*/ select abs(-8) --8 取绝对值 select celling(9.4) --10 向上取整 select floor(9.4) --9 向下取整 select rand() --返回一个0~1的随机数 select sing(10) --1判断一个数的符号,负数返回-1,正数返回1,0返回0; /*字符串函数*/ select char_length('小吴呀')--3 返回字符串长度 select concat('惜','君','呀') --'惜君呀' 字符串拼接 select lower('AIniyo')--ainiyo 大写字母转小写 select upper('xiaoyanzi')--XIAOYANZI 小写字母转大写 select instr('luobo','o')--3 返回第一次出现的字母的索引 select replace('java学习','学习','学习要坚持')--'java学习要坚持' 替换 select substr('java学习',2,3)--ava 从第二个开始截取三个字符 select reverse('miss you')--uoy ssim 字符串反转 /*时间日期*/ select current_date()--获取当前日期 select now()--获取当前详细时间(年月日时分秒) select localtime() --获取本地时间
聚合函数
函数名称 作用 count() 用于计数 sum() 用于求和 avg() 用于求平均值 max()、min() 用于求最大值和最小值
/*聚合函数的使用*/ select count(studentname) from student;--count(指定列的字段),忽略所用null值 select count(*) from student;--不会忽略null值,本质计算行数; select count(1) from student;--不会忽略null值,本质计算行数; select sum(studentresult) as 求和 from result; select avg(studentresult) as 平均分 from result; select max(studentresult) as 最大值 from result; select min(studentresult) as 最小值 from result; /*查询不同课程的平均分,最高分,最低分*/ --group by 字段名:表示通过什么分组,分组后可用having进行条件控制 select subjectname,max(studentresult) as 最高分,min(studentresult) as 最低分,avg(studentresult) as 平均分 from result r inner join subject sub on r.subjectno=sub.subjectno group by r.subjectno having 平均分>80
四、数据库级别的MD5加密
/*建测试表*/ create table testmd5( id int(4) not null, name VARCHAR(20) not null, pwd VARCHAR(50) not null, PRIMARY KEY(id) )ENGINE=INNODB DEFAULT CHARSET=utf8 --插入数据 insert into testmd5 VALUES(1 ,'小吴','123'),(2 ,'小网','1234'),(3 ,'小嘿','1235') --加密id=1 的数据 update testmd5 set pwd=MD5(pwd) where id=1; --加密所有密码 update testmd5 set pwd=MD5(pwd) --数据插入时加密 insert into testmd5 values (4,'微末',MD5("123456"))
五、数据库的事物
5.1、事物:
一组sql操作要么都成功,要么都失败.
事物的原则:ACID原则(原子性、一致性、隔离性、持久性)
原子性:事物要么全部被执行,要么全部不执行。
一致性:事物的执行使得数据库的状态从一种正确状态转变成另外一种正确状态(也就是事物执行前后数据完整 性保持一致)。
隔离性:事物在正确提交之前,不允许把该事物对数据的修改提供给其他任何事物(也就是说在执行过程中的所 有东西都是私有的,不允许给别人看)。
持久性:事物没有提交,恢复到执行事物之前的状态,事物正确提交,数据持久化到数据库。(一旦提交不可 逆)
隔离性产生的问题:
脏读一个事物读取了另外一个事物未提交的数据。
不可重复读:一个事物两次读取同一个数据,两次读取的数据不一样(数据被其他事物修改)。
幻读:一个事物两次读取同一个范围的记录,两次读取的记录数不一样(别的事物可能新插入了数据导致前后数 据的条数不一样)。
/*事物*/ --MySQL数据库默认是开启事物的提交的 set autocommit=0 --关闭事物自动提交 set autocommit=1 --开启事物自动提交(MySQL默认开启) /*手动处理事物*/ --1.关闭自动提交 set autocommit=0 --2.开启事物 start transaction --标记事物的开始,从该语句过后所有执行的sql语句都在同一个事物中 --3.执行具体的sql语句 insert xxx; insert xxx; --4.提交:持久化(成功) commt --5.回滚:回到事物执行的最初状态(事物执行失败才回滚) rollback --6.事物结束开启自动提交 set autocommit=1 /*了解*/ savepoint 保存点名 --设置一个事物的保存点 rollback to savepoint 保存点名 --回滚到保存点 release savepoint 保存点名 --撤销保存点
/*模拟事物场景(转账)*/ 创建一张表 create table account( `id` int(4) NOT null AUTO_INCREMENT, `name` VARCHAR(30) NOT NULL, `money` DECIMAL(9,2), PRIMARY key(`id`) )ENGINE=INNODB DEFAULT CHARSET=utf8; --插入两条数据 INSERT into account(name,money) VALUES ('秋',200),('春',100); set AUTOCOMMIT=0; --1.关闭事物自动提交 START TRANSACTION;--2.开启一个事物 --3.执行sql语句 update account set money=money-50 where name='A'; update account set money=money+50 where name='B'; --4.事物正确提交后执行 COMMIT --5.事物为正确提交执行 ROLLBACK --6.开启事物自动提交 set autocommit=1;
六、数据库索引
索引的定义:索引(index)是帮助MySQL高效获取数据的数据结构,提取句子主干,就可以得到索引的本质:索引是 数据结构。
6.1索引分类
主键索引(primary key)
唯一的标识,主键不可重复只能有一个列作为主键
唯一索引(unique key)
避免重复的列出现,唯一索引可以重复,多个列可以标识为唯一索引
常规索引(key/index)
默认的,index、key关键字来设置
全文索引(fulltext)
在特定的数据库引擎下才有,如MyISAM
快速定位数据
在一个表中主键索引只能有一个,唯一索引可以有多个
/*索引的使用*/ --1.创建表的时候给字段增加索引 2.创建完毕后增加索引 --显示所有的索引信息 show index from student; --给student表增加一个全文索引 alter table student add fulltext index studentname(studentname) --explain分析sql执行的情况 explain select*from student;--非全文所引 explain select*from student where match(studentname) against('赵');
所引在数据量小的时候用处不大,但是在数据量较大时区别就十分明显
6.2、索引原则
1.索引不是越多越好,不要对经常变动的数据加索引
2.小数据量的表不需要加索引
3.索引一般加在常用来查询的字段上
索引的数据结构:
btree:innoDB的默认数据结构
详解:http://blog.codinglabs.org/articles/theory-of-mysql-index.html
七、数据库三范式
7.1、数据库三范式
1.第一范式(1NF)
原子性:保证每一列不可再分
2.第二范式(2NF)
前提:满足第一范式
表必须有一个主键,没有包含在主键中的列必须完全依赖于主键,而不能只依赖于主键的一部分。3.第三范式(3NF)
前提:满足第一范式和第二范式
非主键列必须直接依赖于主键,不能存在传递依赖,即:不存在非主键列A依赖于非主键列B,非主键列B依赖于主键的情况。
7.2、规范性和性能的问题
关联查询的表最好不得超过三张表
1.考虑商业化的需求和目标,(成本,用户体验!)数据库的性能更加重要
2.在规范性能的问题的时候,需要适当的考虑一下规范性!
3.故意给某些表增加一些冗余的字段。(从多表查询中变为单表查询)
4.故意增加—些计算列(从大数据量降低为小数据量的查询:索引)
八、JDBC(重点)
8.1、数据库驱动
JDBC:java操作数据库的规范
JDBC编程还需导入一个驱动包:mysql-connector-java-5.1.47.jar
1.java中JDBC编程测试
测试表(users):
public class JdbcTest {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1.加载数据库驱动
Class.forName("com.mysql.jdbc.Driver");
//2.用户的信息和URL
String url="jdbc:mysql://localhost:3306/school?useUnicode=true&characterEncoding=utf8&useSSL=true";
String username="root";
String password="123";
//3.连接成功,数据库对象
Connection connection = DriverManager.getConnection(url, username, password);
//4.执行sql的对象
Statement statement = connection.createStatement();
//5.执行sql对象去执行sql,存在结果查看结果返回集
String sql="select*from users";
//该语句中封装了全部的查询结果
ResultSet resultSet = statement.executeQuery(sql);
while (resultSet.next()){
System.out.println("id="+resultSet.getObject("id"));
System.out.println("name="+resultSet.getObject("name"));
System.out.println("password="+resultSet.getObject("password"));
System.out.println("email="+resultSet.getObject("email"));
System.out.println("birthday="+resultSet.getObject("birthday"));
System.out.println("-----------------------------");
}
//释放连接(关闭顺序倒着来,最先开启的最后关闭)
resultSet.close();
statement.close();
connection.close();
}
}
//执行结果
id=1
name=zhangsan
password=123456
email=zs@qq.com
birthday=1995-08-12
-----------------------------
id=2
name=lisi
password=123456
email=lisi@qq.com
birthday=1996-08-12
-----------------------------
id=3
name=luo
password=123456
email=luo@qq.com
birthday=1997-08-12
-----------------------------
2.编写步骤
1、加载驱动
2、连接数据库DriverManager
3、获得执行sql的对象Statement
4、获得返回的结果集
5、释放连接
statement.executeQuery();//查询操作返回Resultset
statement.execute(); //执行任何SQL
statement.executeUpdate();//更新、插入、删除。都是用这个,返回一个受影响的行数
/*结果集处理*/
resu1tset.getobject(); //在不知道列奚型的情况下使用
//如果知道列的类型就使用指定的类型
resultset.getstring;
resultset.getInt(;
resu1tset.getF1oat(;
resu1tset.getDate(;
resu1tset.getobject;
/*遍历条件*/
resultset.beforeFirst();//移动到最前面
resultset.afterLast();//移动到最后面
resultset.next();//移动到下一个数据
resultset.previous();//移动到前一行
resu1tset.absolute(row);//移动到指定行
3、封装JDBCUtils工具类
//file文件中 driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/school?useUnicode=true&characterEncoding=utf8&useSSL=true username=root password=123
/*工具类*/
public class JDBCUtils {
private static String driver=null;
private static String url=null;
private static String username=null;
private static String password=null;
static{
InputStream in=JDBCUtils.class.getClassLoader().getResourceAsStream("com\\lb\\db.properties");
Properties properties = new Properties();
try {
properties.load(in);
driver=properties.getProperty("driver");
url=properties.getProperty("url");
username=properties.getProperty("username");
password=properties.getProperty("password");
//驱动只用加载一次
Class.forName(driver);
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,username,password);
}
//释放连接资源
public static void release(Connection con, Statement statement, ResultSet rs) {
if(rs!=null){
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(statement!=null){
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(con!=null){
try {
con.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
测试增加一个用户
/*通过封装的工具类来进行数据库的操作代码量明显减少*/
public class TestInsert {
public static void main(String[] args) {
Connection con = null;
Statement st = null;
ResultSet rs = null;
try {
con = JDBCUtils.getConnection();//获取数据库连接
st = con.createStatement();//获取sql的执行对象
String sql = "insert into users(id,name,password,email,birthday) values (4,'燕子','123456','yz@qq.com','1999-10-18')";
int i = st.executeUpdate(sql);
if (i > 0) {
System.out.println("添加成功");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
JDBCUtils.release(con, st, rs);
}
}
}
//测试结果:
添加成功
测试修改一个用户
public class TestUpdate {
public static void main(String[] args) {
Connection con = null;
Statement st = null;
ResultSet rs = null;
try {
con = JDBCUtils.getConnection();//获取数据库连接
st = con.createStatement();//获取sql的执行对象
String sql = "update users set name='lb',password='123',email='lb@qq.com',birthday='1997-07-15' where id=3";
int i = st.executeUpdate(sql);
if (i > 0) {
System.out.println("修改成功");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
JDBCUtils.release(con, st, rs);
}
}
//测试结果:
修改成功
总结:
用户的增删改都用:executeUpdate(sql)
用户的查询使用:executeQuery(sql) 查询后会返回一个结果集(ResultSet)然后通过结果集将数据拿到
4、sql注入问题(Statement)
sql存在漏洞,可能会被攻击导致数据泄漏问题
//sql注入的问题(拼接字符串) public class SqlDanger { public static void main(String[] args) { //login("lb","123");//正常登陆(select *from users where name='"+lb+"' and password='"+123456+"') //login(" 'or'1=1","123456");//sql注入(select *from users where name='"+ 'or'1=1+"' and password='"+password+"') login(" 'or'1=1"," 'or'1=1");//sql注入(select *from users where name='"+ 'or'1=1+"' and password='"+ 'or'1=1+"') } //模拟登陆 public static void login(String username,String password){ Connection con = null; Statement st = null; ResultSet rs = null; try { con = JDBCUtils.getConnection();//获取数据库连接 st = con.createStatement();//获取sql的执行对象 String sql = "select *from users where name='"+username+"' and password='"+password+"'"; rs = st.executeQuery(sql); while (rs.next()){ System.out.println("id="+rs.getObject("id")); System.out.println("name="+rs.getObject("name")); System.out.println("password="+rs.getObject("password")); System.out.println("email="+rs.getObject("email")); System.out.println("birthday="+rs.getObject("birthday")); System.out.println("-----------------------------"); } } catch (SQLException throwables) { throwables.printStackTrace(); } finally { JDBCUtils.release(con, st, rs); } } }
5、防止sql注入(PreparesStatement对象)
PreparesStatement对象可以有效防止Sql注入问题,执行效率更高,它会把传递进来的参数当做字符直接转义。
以增删改查为列
1.新增public class TestInsert { public static void main(String[] args) { Connection con = null; PreparedStatement st = null; ResultSet rs = null; try { con = JDBCUtils.getConnection();//获取数据库连接 //使用英文?占位符代替参数 String sql = "insert into users(id,name,password,email,birthday) values (?,?,?,?,?)"; st=con.prepareStatement(sql);//预编译过程先写SQL并不会执行 //设置问好所对应的的值,sql语句中参数是什么类型就设置为什么类型 //set..设置参数说明:第一个代表sql中SQL的问号处于第几个位置,第二个代表相应问号所对应的的参数类型 st.setInt(1,5); st.setString(2,"干将莫邪"); st.setString(3,"123456"); st.setString(4,"gjmy@qq,com"); // new Date 指的是sql数据库的时间是java.sql中的 //new java.util.Date() 是java中的包为java.util.* getTime()获取当前时间 st.setDate(5, new Date(new java.util.Date().getTime())); int i = st.executeUpdate(); if (i > 0) { System.out.println("添加成功"); } } catch (SQLException throwables) { throwables.printStackTrace(); } finally { JDBCUtils.release(con, st, rs); } } }
2.删除
public class TestDelete { public static void main(String[] args) { Connection con = null; PreparedStatement st = null; ResultSet rs = null; try { con = JDBCUtils.getConnection();//获取数据库连接 //使用英文?占位符代替参数 String sql = "delete from users where id=?"; st=con.prepareStatement(sql);//预编译过程先写SQL并不会执行 //设置问好所对应的的值,sql语句中参数是什么类型就设置为什么类型 //set..设置参数说明第一个代表sql中SQL的问号处于第几个位置,第二个代表相应问号所对应的的参数类型 st.setInt(1,2); int i = st.executeUpdate(); if (i > 0) { System.out.println("删除成功"); } } catch (SQLException throwables) { throwables.printStackTrace(); } finally { JDBCUtils.release(con, st, rs); } } }
3.修改
public class TestUpdate { public static void main(String[] args) { Connection con = null; PreparedStatement st = null; ResultSet rs = null; try { con = JDBCUtils.getConnection();//获取数据库连接 //使用英文?占位符代替参数 String sql = "update users set name=?,password=?,email=?,birthday=? where id=?"; st=con.prepareStatement(sql);//预编译过程先写SQL并不会执行 //设置问好所对应的的值,sql语句中参数是什么类型就设置为什么类型 //set..设置参数说明第一个代表sql中SQL的问号处于第几个位置,第二个代表相应问号所对应的的参数类型 st.setString(1,"百里守约"); st.setString(2,"666666"); st.setString(3,"百里守约@qq,com"); // new Date 指的是sql数据库的时间是java.sql中的 //new java.util.Date() 是java中的包为java.util.* getTime()获取当前时间 st.setDate(4, new Date(new java.util.Date().getTime())); st.setInt(5,1);//修改id=1的数据 int i = st.executeUpdate(); if (i > 0) { System.out.println("修改成功"); }else { System.out.println("修改失败"); } } catch (SQLException throwables) { throwables.printStackTrace(); } finally { JDBCUtils.release(con, st, rs); } } }
结果:
执行前
执行后
4.查询public class TestSelect { public static void main(String[] args) { Connection con = null; PreparedStatement st = null; ResultSet rs = null; try { con = JDBCUtils.getConnection();//获取数据库连接 //使用英文?占位符代替参数 String sql = "select *from users"; st=con.prepareStatement(sql);//预编译过程先写SQL并不会执行 rs=st.executeQuery(); while (rs.next()){ System.out.println(rs.getString("name")+"\t"+ rs.getString("password")+"\t"+ rs.getString("email") +"\t"+ rs.getDate("birthday")); } } catch (SQLException throwables) { throwables.printStackTrace(); } finally { JDBCUtils.release(con, st, rs); } } }
总结:
1.获取连接获取数据库连接 con = JDBCUtils.getConnection();2.编写SQL语句( 使用英文?占位符代替参数)
3.sql的预编译过程 con.prepareStatement(sql);
4.设置对应参数的值 (例如一个String类型,st.setString(1,“百里守约”);)
5.处理相应的结果,若是st.executeQuery()则需遍历结果集对象,若是st.executeUpdate()则需判断返回值是否大于0,大于0表示对数据库的行数有影响。`
九、数据库连接池
过程:数据库的连接 –>执行完毕–>释放资源。
连接–>释放:该过程是一个十分浪费资源的过程。
池化技术:准备一些预先的资源,当需要的时候可以直接从准备好的池中拿。
一个池中有:最小连接数(基本)、最大连接数(最大负载)、等待超时