学习Mysql的第n天【完结】
MySQL第二天
上一期的MySQL安装补充:https://blog.csdn.net/a802976/article/details/119255644
DQL查询数据(重点)
Data Query Language :数据查询语言
- 所有查询都是用 select
- 数据库最核心的语言,最重要的语句
- 使用频率最高
简单查询
--查全部学生信息
--语法:select 字段··· from 表
select * from student--查询指定字段
select `sno` ,`sname` from student --取别名 AS ,为了方便浏览,可以给结果、字段、表取别名 字段名 AS 新名字
--函数 concat(a,b) ,拼接字符串达到新名字
select concat('姓名:',sname) AS 新名字 from studnet
取别名是因为,有时候列名是英文,难以理解意思,所以我们起别名 AS , 表名 AS 别名
去重 distinct
作用 : 去除select 查询出来的结果中重复的数据 ,重复数据只显示一条
select * from result --查询全部的考试成绩
select `sno` from result --查询有哪些同学参加了考试
select distinct `sno` from result--发现学生学号重复了,去重
数据库的列(表达式)
select version() --查询系统版本(函数)
select 100-8*3 AS 计算结果 --计算(表达式)
select @@auto_increment_increment --查询自增步长(变量)
--学生考试成绩 + 1分
select `sno`,`result` +1 AS '加分后' from result
数据库中的表达式:文本值、列、 null、函数、计算、变量····
select 表达式 from 表名
where 条件子句
作用:检索数据中符合条件的值
搜索条件由一个或多个表达式组成,结果为布尔值
逻辑运算符
模糊查询:本质是比较运算符
联表查询
七种join理论 关系
join语句简单使用
操作 | 描述 |
---|---|
Inner join | 如果表中至少有一个匹配 ,就会返回 |
left join | 会从左表中返回所有的值,即使右表中没有匹配 |
right join | 会从右表中返回所有的值,即使左表中没有匹配 |
s.studentNo 是为了明确studentNo到底从哪个表取,否则报错。
on是代表连接查询,一般与join联用,是join on语法格式
关于Left/right join的选择:
根据题目具体要求,去选择主表为哪一边(左or右)
例:查询缺考人员的信息,关键点在考生的信息,所以选择以左表student表为主要信息表;查询参加考试了学生信息,侧重分数、科目,则选择以右表result表为主要查询信息表。
缺考学生科目,分数为null,为了不显示值为null的学生而选择右表查询,具体实例解析看下方两者的区别图例。
Right join 与 Left join 查询区别 看最后一行信息即可!
三表查询
自连接 (了解)
- 自己表与自己表连接,核心:一张表拆为两张一样的表
例:
父类表
子类表
查询父类对应子类关系
代码查询:
分页和排序
排序 升序ASC 降序 desc
语法:order by 列字段名 升/降
分页 limit
语法:limit 起始值,页面的大小
为什么要分页:
- 数据库庞大的时候使用
- 缓解数据库压力,给人的体验更好
- 博客等信息较多的时候使用
- 瀑布流,图片,抖音等使用较多
- 网页应用: 当前页 ,总的页数,页面大小
--分页,每页显示五条数据
--第一页 limit 0,5 (1-1)*5,5
--第二页 limit 5,5 (2-1)*5,5
--第三页 limit 10,5 (3-1)*5,5
--第n页 limit n,5 (n-1)*页面大小,页面大小
子查询
where (值是计算得出)
本质:在where 语句中嵌套一个子查询语句
连接查询
子查询
子查询.png)]
上方是拆分的子查询语句,下方是传统的联表查询
--再改造 (由里及外)
先执行select SubjectNo ,再查询 StudentNo,不断往外扩。
分组和过滤
分组前只能筛选出一个,分组后筛选出多个。
MySQL函数 (方法)
常用函数
数字运算 (x) x表示要输入数字
SELECT ABS(-8) -- 绝对值 ABS(x)
SELECT CEILING(8.8) -- 向上取整 CEILING(x)
SELECT FLOOR (90.20) -- 向下取整 FLOOR (x)
SELECT RAND () -- 返回一个0-1之间的随机数
SELECT SIGN(10) -- 判断一个数的符号 0-0 ,负数返回-1,正数返回 1 SIGN(x)
字符串函数
SELECT ABS(-8) -- 绝对值
SELECT CEILING(8.8) -- 向上取整
SELECT FLOOR (90.20) -- 向下取整
SELECT RAND () -- 返回一个0-1之间的随机数
SELECT SIGN(10) -- 判断一个数的符号 0-0 ,负数返回-1,正数返回 1
SELECT CHAR_LENGTH('正在努力的码农') -- 字符串长度
SELECT CONCAT ('坚','持','住啊') -- 拼接字符串
SELECT INSERT('正在努力的码农',1,3,'坚持就是胜利') -- 查询 ,从某个位置开始替换某个长度
SELECT LOWER ('Lzjzj') -- 小写字母
SELECT UPPER ('Sadsad') -- 大写字母
SELECT INSTR ('Lzjzj', z) -- 返回第一次出现字符的索引
SELECT REPLACE('正在努力的码农','的','坚持的') -- 替换出现的指定字符串
SELECT SUBSTR ('正在努力的码农',4) -- 返回指定的子字符串(原字符串,截取的位置,截取的长度)
SELECT REVERSE('正在努力的码农') -- 反转字符串的字符
实操
> -- 查询 姓周的同学,并改为姓路的
>
> select replace (stdentname ,'周','路')
> from student
> where studentname like '周%'
聚合函数(常用)
函数名称 | 描述 |
---|---|
count() | 计数 |
sum() | 求和 |
AVG() | 平均值 |
MAX() | 最大值 |
MIN() | 最小值 |
数据库级别MD5加密(面试加分)
- MD5,主要增强算法复杂度和不可逆性
- MD5不可逆,具体的值的MDS是一样的,破解网站的原理是背后有个字典(循环查询),这个字典存放每个值对应的MD5。常见的密码弄了一个集合,复杂的密码无法破解。
- 放入MD5加密后的值,如果查询成功则返回加密前的值。
select 小结
顺序很重要
select 去重 要查询的字段 from 表 (注意:表和字段可以取别名)
xxx join 要连接的表 on 等值判断
where (具体的值,子查询语句)
Group By (通过哪个字段来分组)
Having (过滤分组后的信息,条件和 where是一样的,位置不同)
Order By …(通过哪个字段排序)[升序/降宇]
Limit startIndex, pagesize
业务层面: 使用Java代码
查询:跨表,跨数据库····
事务
什么是事务
- 要么都成功,要么都失败
- 解决单方面成功,而造成的数据丢失情况
案例:
- SQL执行 A转账B 成功
- SQL 执行 B收到A的钱 失败
导致的结果是A 丢失了钱 ,B没收到钱。
核心是将一组SQL放在一个批次去执行 。
事务原则:ACID原则
- 数据库正确执行的四个基本要素
- 分为为原子性,一致性,隔离性,持久性
参考博客文献:https://blog.csdn.net/dengjili/article/details/82468576
原子性:要么都成功,要么都失败
一致性:事务前后数据完整性要保持一致
持久性:事务一旦提交则不可逆,被持久化到数据库中
隔离性:事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
隔离所导致的一些问题
脏读
指一个事务读取了另外一个事务未提交的数据。
不可复复读
在一个事务内读取表中的某一行数据,多次读取结果不同。(这个不一定是错误,只是某些场合不对,一般是数据读着就改变了 )
虚读(幻读)
是指在一个事务内读取到了别的事务插入的数据,导致前后读取数量总量不一致。(一般是行影响,多了一行)
mysql 事务 语法 流程
-- mysql 是默认开启事务自动提交
Set autocommit = 0 --关闭
Set autocommit = 1 --开启(默认的)-- 手动处理事务
Set autocommit = 0 --关闭自动提交
-- 事务开启
start transaction -- 标记一个事务的开始,从这个之后的sql都在同一个事务内
-- 一组事务: insert xx insert xx
-- 提交:持久化 (成功了)
commit
-- 回滚 :回到原来的样子 (失败了)
rollback
-- 事务结束
Set autocommit = 1 -- 开启自动提交
=================================
-- 了解即可
savepoint 保存点名 -- 设置一个事务 的保存点
rollback to savepoint 保存点名 -- 回滚到保存点
release savepoint 保存点名 -- 撤销保存点
模拟流程图
模拟场景
-- 转账
CREATE DATABASE shop CHARACTER SET utf8 COLLATE utf8_general_ciUSE shop CREATE TABLE `account` (
`id` INT(3) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL ,
`money` DECIMAL (9.5) NOT NULL ,
PRIMARY KEY (`id`)) ENGINE =INNODB DEFAULT CHARSET =utf8INSERT INTO `account`(`name`,`money`)VALUES ('a',2555.001),('ss',56.616)-- 模拟转账 ,事务
SET autocommit =0; -- 关闭自动提交
START TRANSACTION -- 开启一个事务
-- 一组事务
UPDATE `account` SET money=money-500 WHERE `name`= 'a' -- a-500
UPDATE `account` SET money=money+500 WHERE `name`= 'ss' -- ss+500COMMIT; -- 提交事务 ,就会被持久化,无法回滚。
ROLLBACK; -- 回滚SET autocommit = 1; -- 恢复默认值
索引
分类
基础语法
测试
-- 建表 字段
DROP TABLE IF EXISTS `app_user`;
CREATE TABLE `app_user` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) DEFAULT'' COMMENT'用户昵称',
`email` VARCHAR(50) NOT NULL COMMENT'用户邮箱',
`phone` VARCHAR(20) DEFAULT'' COMMENT'手机号',
`gender` TINYINT(4) UNSIGNED DEFAULT '0'COMMENT '性别(0:男;1:女)',
`password` VARCHAR(100) NOT NULL COMMENT '密码',
`age` TINYINT(4) DEFAULT'0' COMMENT '年龄',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
`update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8 COMMENT = 'app用户表' -- 插入100万条数据-- 插入100万数据.
DELIMITER $$ -- 写函数之前必须要写,标志
CREATE FUNCTION mock_data ()
RETURNS INT
BEGINDECLARE num INT DEFAULT 1000000;DECLARE i INT DEFAULT 0;WHILE i<num DOINSERT INTO `app_user`(`name`,`email`,`phone`,`gender`,`password`,`age`)VALUES(CONCAT('用户',i),'979812855@qq.com',CONCAT('18',FLOOR( RAND()*(999999999-100000000))) ,FLOOR(RAND()*2),UUID(),FLOOR(RAND()*100));SET i=i+1; END WHILE; RETURN i;
END;
SELECT mock_data ();-- 执行查询 打开表查看数据即可
建立索引前后区别
-- 为创建索引前100万数据的查询
SELECT * FROM `app_user` WHERE `name` = '用户9999' -- 0.583 sec
SELECT * FROM `app_user` WHERE `name` = '用户9999' -- 0.620 sec
EXPLAIN SELECT * FROM `app_user` WHERE `name` = '用户9999' -- rows列显示998523条数据,即查询998523条数据才出现-- 创建常规索引 id_表名_字段名
-- create index 索引名 on 表(字段)
CREATE INDEX id_app_user_name ON app_user(`name`) -- 4.631 sec-- 创建索引后
SELECT * FROM `app_user` WHERE `name` = '用户9999' -- 0.002 sec
SELECT * FROM `app_user` WHERE `name` = '用户9999' -- 0 sec
EXPLAIN SELECT * FROM `app_user` WHERE `name` = '用户9999' -- rows列显示1条数据,即唯一定位
索引原则
索引的数据结构
hash 类型的索引
Btree : INNDB 的默认数据结构
阅读文献:http://blog.codinglabs.org/articles/theory-of-mysgl-index.html
权限管理和备份
用户管理
操作1
可视化界面直接点击操作即可
操作2
---- 命令行 linux 服务器需使用命令行
-- 创建用户 create user 用户名 identified by '密码'
create user rootroot identified by '112233'
-- 修改密码 (修改当前用户密码)
Set password = password('112233')
-- 修改密密码(修改指定用户密码)
set password for rootroot =password('112233')
-- 重命名 rename user 原来的名字 to 新的名字
rename user rootroot to root2
-- 用户授权
-- all PRIVILEGES 全部的权限,库和表,除了给别人授权
grant all PRIVILEGES on *.* to root2
-- 查询权限
show grants for root2 -- 查看指定用户的权限
SHOW GRANTS FOR root@localhost
-- root用户权限GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION-- 撤销权限 revoke revoke all PRIVILEGES on *.* from root2--删除用户drop user root2
MySQL备份
为什么要备份:
- 保证重要数据不丢失
- 数据转移
MySQL数据库备份方式
- 直接拷贝物理文件(mysql目录下的date文件)
- 在sqlyog等可视化工具手动导出
选择要导出的表,库,右键导出,sql转储,一般选择结构和数据
结构:创建表相关的语句
数据:insert相关的语句
- 使用命令行导出 mysqldump 命令行使用
作用:
- 备份数据库,防止数据丢失,即使在sqlyog等可视化工具删除了,也能重新导入
- 把数据库文件给别人,导出sql文件即可
规范数据库设计
为什么需要设计?
基于三大范式评判数据库设计好坏
糟糕的数据库设计:
- 数据库冗余,浪费空间
- 数据库插入和删除都会麻烦、异常,也会屏蔽使用外键
- 程序性能差
良好的数据库设计:
- 节省内存空间
- 保证数据库完整性
- 方便我们开发系统
软件开发中,关于数据库的设计
- 分析需求:分析业务和需要处理的数据库的需求
- 概要设计:设计关系图E-R图
设计数据库步骤(个人博客)
三大范式
为什么需要数据规范化?
信息重复
更新异常
插入异常
无法正常显示信息删除异常
丢失有效信息
三大范式(记)
关于规范性和性能问题的讨论(面试与笔试)
阿里规范:关联查询的表不得超过三张表
- 考虑商业化的需求和目标 ,(成本,用户体验) --(成本是公司成立之初过分规范会导致成本过大问题;拆分多表会查询过慢,用户体验差),数据库性能更加重要
- 在规范性能的问题的时候,需要适当考虑规范性。(会产生冗余)
- 故意给某些表增加一些冗余字段,目的为了方便,实际商用一个表可以显示全部信息(特别是关键的信息),拆成两张表不易观看。(从多表查询变为单表查询,会导致冗余)
- 故意增加一些计算列。一般用于统计accout值,一次性统计与每次统计(然后只需查询计算那一列即可)的区别。(从大数据量降低为小数据量的查询,类似索引)
JDBC(重点)
数据库驱动
为什么需要?
驱动:声卡、显卡、数据库
应用程序无法直接连接数据库,都要先连接数据库驱动,通过驱动连接数据库,而数据库驱动是产家给予的。
我们的程序会通过 数据库 驱动 和数据库打交道,但数据库种类不同,驱动也不同,如果需要多个数据库实现,就要写多个程序,不便于程序管理。
JDBC
sun 公司为了简化 开发人员的(对数据库的统一)操作,提供了一个(Java操作数据库的)规范,俗称 JDBC
这些规范的实现由具体的厂商去做
对于开发人员,我们学会操作JDBC即可。
java本身有的两个包
- java.sql
- javax.sql
- 再导入数据库驱动包 MySQL-connector-java-5.1.47.jar
- 驱动下载
第一个JDBC程序
创建测试数据库
CREATE DATABASE jdbcStudy CHARACTER SET utf8 COLLATE utf8_general_ci;USE jdbcStudy;CREATE TABLE `users`(id INT PRIMARY KEY,NAME VARCHAR(40),PASSWORD VARCHAR(40),email VARCHAR(60),birthday DATE
)INSERT INTO `users`(id,NAME,PASSWORD,email,birthday)
VALUES(1,'zhansan','123456','zs@sina.com','1980-12-04'),
(2,'lisi','123456','lisi@sina.com','1981-12-04'),
(3,'wangwu','123456','wangwu@sina.com','1979-12-04')
创建普通项目
导入数据库驱动
编写测试代码
package com.lzi.demo01;
import java.sql.*;public class JdbcFirstDemo {public static void main(String[] args) throws ClassNotFoundException, SQLException{// 1.加载驱动Class.forName("com.mysql.jdbc.Driver");// 2.输入用户信息和urlString url="jdbc:mysql://localhost:3306/jdbcStudy?useUnicode=true&characterEncoding=utf8&useSSL=true";String username = "root";String password = "123456";//3.连接成功,数据库对象 connectionConnection connection = DriverManager.getConnection(url,username,password);//4.执行SQL的对象 Statement 执行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("pwd=" + resultSet.getObject("password"));System.out.println("email=" + resultSet.getObject("email"));System.out.println("birth=" + resultSet.getObject("birthday"));System.out.println("======= ============================================ ");}//6.释放连接resultSet.close();statement.close();connection.close();}
}
步骤总结:
- 加载驱动
- 连接数据库 DriverManager
- 获取执行sql的对象 Statement (不安全的)
- 获得返回的结果集(只有查询语句有结果,其它是受影响的行)
- 释放连接
扩展:关于连接数据出错问题,如果出现下图同样的错误,连接失败
解决办法:
- 重下jdbc驱动包8.0以上的版本,
- 将 url 中的 useSSL=true 改为 useSSL =false
解决思路参考:https://blog.csdn.net/L_it123/article/details/106845391
JDBC中对象解释
DriverManager
// 1.加载驱动Class.forName("com.mysql.jdbc.Driver");// 注册静态驱动 DriverManager.registerDriver(new Driver());// 包里已经有了静态方法 如果此处再用一次则注册两次,所以直接调用即可// 推荐使用第一种
Connection connection = DriverManager.getConnection(url,username,password);// connection 代表数据库
//数据库设置自动提交
//事务提交
//事务回滚connection.commit();connection.rollback(); connection.setAutoCommit();
URL
String url="jdbc:mysql://localhost:3306/jdbcStudy?useUnicode=true&characterEncoding=utf8&useSSL=false";//mysql 默认端口号为3306
// 协议://主机地址(也可远程地址):端口号/数据库名?参数1&参数2&参数3
//oracle 默认端口 1521
//jdbc:oracle:thin:@losthost:1521:sid
Statement 执行SQL对象 PrepareStatement 执行SQL对象
String sql="select * from users"; //编写SQL代码
statement.executeQuery();//查询操作返回 ResultSet
statement.execute();//执行任何SQL
statement.executeupdate();// 更新,插入,删除,返回一个影响的行数
statement.executeBatch();// 批处理,可以放多个SQL进去执行
ResultSet 查询的结果集,封装了所有的查询结果
获得指定的数据类型
遍历 指针
resultset.beforeFirst ;//移动到最前面
resultset.afterLast();// 移动到最后面
resultset.next();//移动到下一个数据
resultset.previous();//移动到前一行
resultSet.beforeFirst();//往后走一个
resultset.absolute(row);//移动到指定行
释放资源
//6.释放连接resultSet.close();statement.close();connection.close();// 耗资源,用完必须关闭
Statement 对象
代码实现
- 配置文件
# 记住没有分号和双引号!!
#文件名 db.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true
username = root
password=123456
- 提取工具类
package com.manong.lesson02.utils;import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;public class jdbcutils {private static String driver=null;private static String url=null;private static String username=null;private static String password=null;//读取配置文件,scr下的文件,配置文件没有分号,双引号之说static{try {//输入流InputStream in =jdbcutils.class.getClassLoader().getResourceAsStream("db.properties");//类加载器,获取指定资源,资源名,返回输入流Properties properties = new Properties();// 拿到流后创建对象然后写入properiesproperties.load(in);// 信息读取完毕//去properties获取资源driver =properties.getProperty("driver");url =properties.getProperty("url");username =properties.getProperty("username");password =properties.getProperty("password");//驱动只需要加载一次Class.forName(driver);} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}}//获取连接/* 新手写法 public static void getConnection() throws SQLException{Connection connection= DriverManager.getConnection(url,username,password);}*///标准方法,public static Connection getConnection() throws SQLException{return DriverManager.getConnection(url,username,password);}//释放资源,大写的是对象,小写是对象名,传入对象public static void release(Connection conn, Statement st, ResultSet rs) {if (rs != null){try {rs.close();} catch (SQLException e) {e.printStackTrace();}}if (st !=null){try {st.close();} catch (SQLException e) {e.printStackTrace();}}if (conn !=null){try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}
}
- 编写增删改方法 executeUpdate() 方法
-- 增删改操作只需要更改sql语句和输出结果即可,其他一样
package com.manong.lesson02.utils;
import com.manong.lesson02.utils.jdbcutils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;public class Testinsert {public static void main(String[] args) {//全局配初始化Connection conn =null;Statement st =null;ResultSet rs =null;try {//不用写配置,工具类好处,简化直接jdbc获得即可conn= jdbcutils.getConnection();//获取数据库连接st=conn.createStatement();//获取SQL的执行对象,若已经创建了变量,则使用引用名即可String sql ="delete from `users` where id =4";//更新 String sql ="update `users` set `NAME`='haha',`email`='555555@qq.com' where id =4";//插入 String sql ="INSERT INTO `users` VALUES (4,'kokoko','123456','979812855@qq.com','1888-11-11')";//SQL语句int i=st.executeUpdate(sql);//查询sql语句,会返回一个值,用i表示,又因为插入语句rs为空,无法知道是否成功if (i>0){//因此出现一个判断语句// System.out.println("插入成功");System.out.println("删除成功");// System.out.println("更新成功");}} catch (SQLException e) {e.printStackTrace();}finally {//释放资源jdbcutils.release(conn,st,rs);}}
}
- 查询 executeQuery
package com.manong.lesson02.utils;import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;public class Testselect {public static void main(String[] args) {//全局配初始化Connection conn =null;Statement st =null;ResultSet rs =null;try {conn= jdbcutils.getConnection();st=conn.createStatement();String sql ="select * from `users` where id =1";rs=st.executeQuery(sql);//使用executeUpdate也可,最佳executeQuery//如果查询单条语句用if,多条whilewhile (rs.next()){//读取,get一个System.out.println(rs.getString("NAME"));System.out.println(rs.getString("id"));System.out.println(rs.getString("email"));}} catch (SQLException e) {e.printStackTrace();}finally {//释放资源jdbcutils.release(conn,st,rs);}}
}
SQL注入
- sql存在漏洞,会被攻击导致信息泄露,本质是SQL会被拼接 是因为存在 or,满足一个条件即可。
- java里的Preparestatement对象可纯天然屏蔽它,下图的Statement这个对象不安全。
package com.manong.lesson02.utils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class SQL注入 {public static void main(String[] args) {//login("zhansan","123456");login(" 'or '1=1","123'or'1=1");//SQL注入的原因,登入一个,即可输出全部数据// 'or '1=1 被过滤了 ,密码随便输入,都可输出}//登录业务 ,写个测试方法public static void login(String username,String password){Connection conn =null;Statement st =null;ResultSet rs =null;try {conn= jdbcutils.getConnection();st=conn.createStatement();// String sql ="SELECT * FROM `users` WHERE `NAME`='zhansan' AND `PASSWORD` = '123456'"; //对比// 字符串的拼接//SELECT * FROM `users` WHERE `NAME`='zhansan' AND `PASSWORD` = '123456' //语句//SELECT * FROM `users` WHERE `NAME`='' or'1=1' AND `PASSWORD` = '' or '1=1'//如何SQL注入// String sql ="SELECT * FROM `users` WHERE `NAME`='' or '1=1' AND `PASSWORD` = '' 'or'1=1";//完整句String sql ="select * from users where `NAME`= '"+username+"'AND `PASSWORD`= '"+password+"' ";rs = st.executeQuery(sql);while (rs.next()){System.out.println(rs.getString("NAME"));System.out.println(rs.getString("password"));System.out.println("-------------");}} catch (SQLException e) {e.printStackTrace();}finally {//释放资源jdbcutils.release(conn,st,rs);}}}
Preparestatement对象
- Preparestatement对象,预编译,可以防止SQL注入,效率更高,更安全
- Preparestatement是Statement的子类,子类继承父类,扩展和改变
插入
package com.manong.lesson03;
import com.manong.lesson02.utils.jdbcutils;
import java.sql.*;
import java.util.Date;
public class TestInsert {public static void main(String[] args) {Connection conn =null;PreparedStatement st =null;ResultSet rs =null;try {conn = jdbcutils.getConnection();//区别 对比Statement做法//使用?做占位符代替参数// 同理,删除、更新操作更改SQL语句即可String sql ="insert into users(id,`NAME`,`PASSWORD`,`email`,`birthday`) values(?,?,?,?,?) ";st=conn.prepareStatement(sql);//预编译SQL,先写sql,但不执行//手动输参,即上方?处传参st.setInt(1,4);st.setString(2,"wawawa");st.setString(3,"123456");st.setString(4,"2222@qq.com");//sql.Date 数据库 执行java.sql.Date() 转化为sql.Date//util.Date java new Date().getTime()获得时间戳st.setDate(5,new java.sql.Date(new Date().getTime()));//现在要执行的是sql语句,所以要包装一下//预编译结束,输入结束,SQL填充结束,下面开始执行int i=st.executeUpdate();//区别 直接调用if (i>0){System.out.println("插入成功");//删除成功 // 更新成功}} catch (SQLException e) {e.printStackTrace();}finally {jdbcutils.release(conn,st,rs);}}
}
删除
package com.manong.lesson03;import com.manong.lesson02.utils.jdbcutils;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;public class Testdelete {public static void main(String[] args) {Connection conn =null;PreparedStatement st =null;ResultSet rs =null;try {conn = jdbcutils.getConnection();//区别 对比Statement做法//使用?做占位符代替参数String sql ="delete from users where id=?";st=conn.prepareStatement(sql);//预编译SQL,先写sql,但不执行//手动输参,即上方?处传参st.setInt(1,4);//预编译结束,输入结束,SQL填充结束,下面开始执行int i=st.executeUpdate();//区别 直接调用if (i>0){System.out.println("删除成功");}} catch (SQLException e) {e.printStackTrace();}finally {jdbcutils.release(conn,st,rs);}
}}
更新
package com.manong.lesson03;
import com.manong.lesson02.utils.jdbcutils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Testupdate {public static void main(String[] args) {Connection conn =null;PreparedStatement st =null;ResultSet rs =null;try {conn = jdbcutils.getConnection();//区别 对比Statement做法//使用?做占位符代替参数String sql ="update users set `NAME` = ? where id=?";st=conn.prepareStatement(sql);//预编译SQL,先写sql,但不执行//手动输参,即上方?处传参st.setString(1,"koko");st.setInt(2,1);//预编译结束,输入结束,SQL填充结束,下面开始执行int i=st.executeUpdate();//区别 直接调用if (i>0){System.out.println("更新成功");}} catch (SQLException e) {e.printStackTrace();}finally {jdbcutils.release(conn,st,rs);}}
}
查询 (完全自动化)
package com.manong.lesson03;
import com.manong.lesson02.utils.jdbcutils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestSelect {public static void main(String[] args) {Connection conn =null;PreparedStatement st =null;ResultSet rs =null;try {//Properties规律步骤conn = jdbcutils.getConnection(); //连接String sql ="select * from users where id=?"; //编写SQLst=conn.prepareStatement(sql);//预编译SQL,但不执行st.setInt(1,1);//传参//预编译结束,输入结束,SQL填充结束,下面开始执行//上方不变,下方执行rs = st.executeQuery();//先查询,然后得出一个结果while (rs.next()){//读取,get一个System.out.println(rs.getString("NAME"));}} catch (SQLException e) {e.printStackTrace();}finally {jdbcutils.release(conn,st,rs);//关闭}} }
防止SQL注入
package com.manong.lesson03;
import com.manong.lesson02.utils.jdbcutils;
import java.sql.*;
public class SQL注入 {public static void main(String[] args) {//login(" 'or '1=1","123'or'1=1"); //对比login("'' or 1=1","123456");//完美的防止SQL注入,}//登录业务 ,写个测试方法public static void login(String username,String password){Connection conn =null;PreparedStatement st =null;ResultSet rs =null;try {conn= jdbcutils.getConnection();//连接// PreparedStatement对象 防止SQL注入的本质是,把传递进来的参数当作字符,//'' or 1=1外面用引号再包一层字符,解除//假设其中有转义字符,就直接忽略,比如传入 ' 引号会被直接转义//String sql ="select * from users where `NAME`= ? and `PASSWORD` = ?"; // 该条语句有错误String sql=" SELECT * FROM users WHERE `Name`=? and `PASSWORD`=? ";st=conn.prepareStatement(sql);//预编译//传参st.setString(1,username);//st.setString(1,username);st.setString(2,password);rs= st.executeQuery();//查询不变while (rs.next()){System.out.println(rs.getString("NAME"));System.out.println(rs.getString("password"));System.out.println("-------------");}} catch (SQLException e) {e.printStackTrace();}finally {//释放资源jdbcutils.release(conn,st,rs);}}}
使用IDEA连接数据库
具体操作见图:
菜单栏打开:View -->Tool windows–>database
点击”+“,找到MySQL
用户连接–>
导入库–>
- 编写SQL语句的位置
- 切换数据库
- 双击表即可打开表
- 打开表后更新操作
- 导入了jdbc包后,测试连接失败,可能是版本问题
- 下图是修改Mysql版本
- class,选择driver
- 下方的URL路径不能更改
JDBC操作事务
package com.manong.lesson04;
import com.manong.lesson02.utils.jdbcutils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Testtranscaction {public static void main(String[] args) {Connection conn= null;PreparedStatement st=null;ResultSet rs =null;try {conn = jdbcutils.getConnection();//连接conn.setAutoCommit(false);//关闭数据库自动提交,并开启事务 下一步编写SQL
//一组事务String sql1="update account set money= money - 100 where name='A'";st = conn.prepareStatement(sql1);// 可以先打开SQL预编译,再编写SQL,但语句顺序不能错,否则报错st.executeUpdate();//查询// int x=1/0; // 一定失败,sql1 已经执行,sql2 没有执行,但回滚了,数据没有丢失String sql2="update account set money= money + 100 where name='B'";st = conn.prepareStatement(sql2); //如果不出现st引用会报错 java.lang.NullPointerExceptionst.executeUpdate();//查询//业务完毕,提交事务conn.commit();System.out.println("执行成功");} catch (SQLException e) {try {conn.rollback();//可以手动显示回滚,如果失败,程序会默认回滚} catch (SQLException ex) {ex.printStackTrace();}e.printStackTrace();}finally {jdbcutils.release(conn,st,rs);}}
}
数据库连接池
一般步骤:数据库连接 – 执行完毕 – 释放 , 而连接 – 释放的过程十分浪费资源
池化技术:预先准备一些资源,过来就连接预先准备好的
- 将对象放入池子,使用时从池中取,用完之后交给池子管理。通过优化资源分配的效率,达到性能的调优。
- java中常见的池化技术有对象池,复用对象;连接池,复用连接;线程池,复用线程。
最小连接数 10
最大连接数 15
等待超时 : 100ms
编写连接池,实现一个接口 DataSource,为了获得连接
接口的实现类
开源数据源实现 (拿来即用)
DBCP
C3P0
Druid: 阿里巴巴
使用了这些数据库连接池之后,我们在项目开发中就不需要编写连接数据库的代码了。
DBCP
需要用到的jar包
commons-dbcp-1.4 , commons -pool -1.6
- 导入包,编写DBCP的配置文件dbcpconfig.properties
#连接设置 这里面的名字,是DBCP数据源中定义好的
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?userUnicode=true&characterEncoding=utf8&useSSL=true
username=root
password=123456
#driverClassName 开头标识不能更改,否则无法自动识别
#前面的是我们手动读
代码实现
package com.manong.lessons05.untils;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class jdbcutils_DBCP {private static DataSource dataSource=null;static{try {//输入流InputStream in = com.manong.lesson02.utils.jdbcutils.class.getClassLoader().getResourceAsStream("dbconfig.properties");//类加载器,获取指定资源,资源名,返回输入流 只改变了资源名Properties properties = new Properties();properties.load(in);//创建数据源 工厂模式 --> 创建对象使用dataSource= BasicDataSourceFactory.createDataSource(properties);} catch (Exception e) {e.printStackTrace();}}public static Connection getConnection() throws SQLException {return dataSource.getConnection();}public static void release(Connection conn, Statement st, ResultSet rs) {if (rs != null){try {rs.close();} catch (SQLException e) {e.printStackTrace();}}if (st !=null){try {st.close();} catch (SQLException e) {e.printStackTrace();}}if (conn !=null){try {conn.close();} catch (SQLException e) {e.printStackTrace();} } }
}---------------------------------------测试类----------------------------------package com.manong.lessons05.untils;
import com.manong.lesson02.utils.jdbcutils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestDBCP {public static void main(String[] args) {Connection conn =null;Statement st =null;ResultSet rs =null;try {conn= jdbcutils_DBCP.getConnection();//获取数据库连接st=conn.createStatement();//获取SQL的执行对象,若已经创建了变量,则使用引用名即可String sql ="delete from `users` where id =4";int i=st.executeUpdate(sql);//查询sql语句,会返回一个值,用i表示,又因为插入语句rs为空,无法知道是否成功if (i>0){//因此出现一个判断语句// System.out.println("插入成功");System.out.println("删除成功");// System.out.println("更新成功");}} catch (SQLException e) {e.printStackTrace();}finally {//释放资源jdbcutils_DBCP.release(conn,st,rs);}}
}
C3P0 有配置日志
需要用到的jar包 c3p0-0.9.5.5 mchange commons-java-0.2.19
- 导入包,编写c3p0的配置文件c3p0-config.xml
<!--如果在代码中"ComboPooledDataSource ds=new ComboPooledDataSource("MySQL");
"这样写就表示使用的是mysql的缺省(默认)
可以添加多个数据库,oracle--><c3p0-config>
<named-config name="MySQL"><property name="driverClass">com.mysql.cj.jdbc.Driver</property><property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&uesSSL=true&serverTimezone=UTC</property><property name="user">root</property><property name="password">123456</property><property name="acquiredIncrement">5</property><property name="initialPoolSize">10</property><property name="minPoolSize">5</property><property name="maxPoolSize">20</property>
</named-config></c3p0-config>
代码实现
package com.manong.lessons05.untils;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class jdbcutils_c3p0 {private static ComboPooledDataSource dataSource=null;static{try {dataSource=new ComboPooledDataSource("MySQL");//配置文件的写法} catch (Exception e) {e.printStackTrace();}}//标准方法,public static Connection getConnection() throws SQLException {return dataSource.getConnection();}public static void release(Connection conn, Statement st, ResultSet rs) {if (rs != null){try {rs.close();} catch (SQLException e) {e.printStackTrace();}}if (st !=null){try {st.close();} catch (SQLException e) {e.printStackTrace();}}if (conn !=null){try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}
}
---------------------------------------测试类--------------------------------
package com.manong.lessons05.untils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class Testc3p0 {public static void main(String[] args) {Connection conn =null;Statement st =null;ResultSet rs =null;try {conn= jdbcutils_c3p0.getConnection();//原来是自己实现的,现在用别人的实现st=conn.createStatement();//获取SQL的执行对象,若已经创建了变量,则使用引用名即可String sql ="delete from `users` where id =1";int i=st.executeUpdate(sql);if (i>0){//因此出现一个判断语句// System.out.println("插入成功");System.out.println("删除成功");// System.out.println("更新成功");}} catch (SQLException e) {e.printStackTrace();}finally {//释放资源jdbcutils_c3p0.release(conn,st,rs);} }
}
结论
无论使用什么数据源,本质还是一样的,DataSource接口不会变,方法就不会变,只是实现类改变
学习Mysql的第n天【完结】相关推荐
- 这38个小技巧告诉你如何快速学习MySQL数据库
无论是运维.开发.测试,还是架构师,数据库技术是一个必备加薪神器,那么,一直说学习数据库.学MySQL,到底是要学习它的哪些东西呢?此文为你揭晓,你值得一看!看过别忘记点赞+转发支持哦. 1.如何快速 ...
- 学mysql是学指令吗_学习Mysql (二) 常用指令
环境搭建OK.可视化查看看得我一脸懵逼,还是命令行学习下. 常用指令: 1. 登录: mysql -h 主机名 -u 用户名 -p 注:本机localhost的话,-h部分可以省略.-p后面不写密码的 ...
- access 导入 txt sql语句_从零开始学习 MySQL 系列索引、视图、导入和导出
阅读本文大概需要 8 分钟 前言上篇文章我们学习了数据库和数据表操作语句,今天我们学习下数据库索引,视图,导入和导出的知识.作为基础篇,不会涉及到关于索引和视图的高级应用和核心概念,但是基本操作大家会 ...
- java 一个大事务下的新增、修改、查询_重新学习Mysql数据库8:MySQL的事务隔离级别实战...
本文转自:https://blog.csdn.net/sinat_27143551/article/details/80876127 本系列文章将整理到我在GitHub上的<Java面试指南&g ...
- 惊呆!学习MySQL真的这一篇就够了!太全了
这是我见过学习MySQL最全的一篇文章! https://caochenlei.blog.csdn.net/article/details/107640904 目录 第一章 数据库概述 1.1.数据库 ...
- 学习MySQL我们应该知道哪些东西?
随笔:小编由于年前一直在找工作,而年后找到工作后又一直在忙工作,所以也很少有时间给大家写点什么,总的来说呢,回顾一下之前面试的几次经历,也曾小小的总结了一下自己的不足,发现自己虽然一直在原有的公司(外 ...
- mysql导入dat文件_从零开始学习 MySQL 系列--索引、视图、导入和导出
前言 上篇文章我们学习了数据库和数据表操作语句,今天我们学习下数据库索引,视图,导入和导出的知识. 作为基础篇,不会涉及到关于索引和视图的高级应用和核心概念,但是基本操作大家会了解,尤其是关于索引的内 ...
- 再次学习mysql优化
再次学习mysql优化 表的设计规范化(三范式) 添加索引(普通索引.主键索引.唯一索引.全文索引) 分表(水平分割.垂直分割) 读写分离(写add.update.delete) 存储过程 对mysq ...
- 5天学习MYSQL数据库第一天剩余全部笔记(超级详细的mysql入门笔记适合新手反复看加深记忆)
这是关于五天学习MYSQL数据库的笔记,如果想要观看视频可以访问(视频链接(b站) 或者访问视频链接 之前的笔记已经记到了1.3的mysql基本介绍,接下来主要是: 2.1MySQL服务端框架 一. ...
- 零基础带你学习MySQL—foreign key 外键(二十六)
零基础带你学习MySQL-foreign key 外键(二十六) -- 外键演示 -- 创建 主表 my_class CREATE TABLE my_class ( id INT PRIMARY KE ...
最新文章
- 十、Hadoop学习笔记————Hive与Hbase以及RDBMS(关系型数据库)的关系
- 计算机专业英语公开课教案,小学英语公开课教案,小学英语优质课教案?
- 前端学习(2930):内嵌改变样式
- 羡慕,浙江大学的双 11 快递,全部由物流机器人配送
- 2010多校第一题 hdu3440House Man 差分约束系统
- 地理空间数据云下载的dem数据打不开怎么办? 显示光盘映像已损坏
- 浪曦struts2学习笔记3
- 尝试用朴素贝叶斯分析借款信用等级
- OpenCV IplImage图片结构
- 互联网大佬生存法则 如何防守周鸿祎
- vm安装centos,黑屏或黑屏且左上角有光标闪动
- 通过关键词爬取百度图片——Python爬虫
- SQL教程之使用 dbt 和 SQLfluff 整理 SQL
- 网站首页导航栏移入移出动画(一)slideDown、slideUp
- php网站设计说课ppt,电子教案5-2网页设计.ppt
- Unity-Live2d(鼠标拖拽触发动作变化)
- 【R语言文本挖掘】:n-grams和相关性计算
- Error response from daemon: Container xxx is not running的解决方法
- 求1到n中与n互质的和(数论)解释及证明
- Frog Jumps
热门文章
- iOS通itms-services://协议安装ipa,省去https环境的搭建
- ChatGPT神奇用法:定点周边景点推荐,Get私人导游!
- 一个程序猿的讨薪日记
- win10系统安装iso文件,绝对可下。
- 【旧资料整理】解决firefox3迅雷插件右键查看页面源代码无效问题
- 浅谈SAP关于存货计价过程
- Programming Languages PartA Week5学习笔记——SML进阶与编程哲学
- r语言nonzerocoef函数_R语言pec包深度验证Cox模型
- 总结两个Javascript的哈稀对象的一些编程技巧
- 4W家庭理财 V2.3