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代码
查询:跨表,跨数据库····

事务

什么是事务

  • 要么都成功,要么都失败
  • 解决单方面成功,而造成的数据丢失情况

案例:

  1. SQL执行 A转账B 成功
  2. 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')
  1. 创建普通项目

  2. 导入数据库驱动

  3. 编写测试代码

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();}
}

步骤总结:

  1. 加载驱动
  2. 连接数据库 DriverManager
  3. 获取执行sql的对象 Statement (不安全的)
  4. 获得返回的结果集(只有查询语句有结果,其它是受影响的行)
  5. 释放连接

扩展:关于连接数据出错问题,如果出现下图同样的错误,连接失败

解决办法:

  1. 重下jdbc驱动包8.0以上的版本,
  2. 将 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();}}}
}
  1. 编写增删改方法 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);}}
}
  1. 查询 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&amp;characterEncoding=utf8&amp;uesSSL=true&amp;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天【完结】相关推荐

  1. 这38个小技巧告诉你如何快速学习MySQL数据库

    无论是运维.开发.测试,还是架构师,数据库技术是一个必备加薪神器,那么,一直说学习数据库.学MySQL,到底是要学习它的哪些东西呢?此文为你揭晓,你值得一看!看过别忘记点赞+转发支持哦. 1.如何快速 ...

  2. 学mysql是学指令吗_学习Mysql (二) 常用指令

    环境搭建OK.可视化查看看得我一脸懵逼,还是命令行学习下. 常用指令: 1. 登录: mysql -h 主机名 -u 用户名 -p 注:本机localhost的话,-h部分可以省略.-p后面不写密码的 ...

  3. access 导入 txt sql语句_从零开始学习 MySQL 系列索引、视图、导入和导出

    阅读本文大概需要 8 分钟 前言上篇文章我们学习了数据库和数据表操作语句,今天我们学习下数据库索引,视图,导入和导出的知识.作为基础篇,不会涉及到关于索引和视图的高级应用和核心概念,但是基本操作大家会 ...

  4. java 一个大事务下的新增、修改、查询_重新学习Mysql数据库8:MySQL的事务隔离级别实战...

    本文转自:https://blog.csdn.net/sinat_27143551/article/details/80876127 本系列文章将整理到我在GitHub上的<Java面试指南&g ...

  5. 惊呆!学习MySQL真的这一篇就够了!太全了

    这是我见过学习MySQL最全的一篇文章! https://caochenlei.blog.csdn.net/article/details/107640904 目录 第一章 数据库概述 1.1.数据库 ...

  6. 学习MySQL我们应该知道哪些东西?

    随笔:小编由于年前一直在找工作,而年后找到工作后又一直在忙工作,所以也很少有时间给大家写点什么,总的来说呢,回顾一下之前面试的几次经历,也曾小小的总结了一下自己的不足,发现自己虽然一直在原有的公司(外 ...

  7. mysql导入dat文件_从零开始学习 MySQL 系列--索引、视图、导入和导出

    前言 上篇文章我们学习了数据库和数据表操作语句,今天我们学习下数据库索引,视图,导入和导出的知识. 作为基础篇,不会涉及到关于索引和视图的高级应用和核心概念,但是基本操作大家会了解,尤其是关于索引的内 ...

  8. 再次学习mysql优化

    再次学习mysql优化 表的设计规范化(三范式) 添加索引(普通索引.主键索引.唯一索引.全文索引) 分表(水平分割.垂直分割) 读写分离(写add.update.delete) 存储过程 对mysq ...

  9. 5天学习MYSQL数据库第一天剩余全部笔记(超级详细的mysql入门笔记适合新手反复看加深记忆)

    这是关于五天学习MYSQL数据库的笔记,如果想要观看视频可以访问(视频链接(b站) 或者访问视频链接 之前的笔记已经记到了1.3的mysql基本介绍,接下来主要是: 2.1MySQL服务端框架 一. ...

  10. 零基础带你学习MySQL—foreign key 外键(二十六)

    零基础带你学习MySQL-foreign key 外键(二十六) -- 外键演示 -- 创建 主表 my_class CREATE TABLE my_class ( id INT PRIMARY KE ...

最新文章

  1. 十、Hadoop学习笔记————Hive与Hbase以及RDBMS(关系型数据库)的关系
  2. 计算机专业英语公开课教案,小学英语公开课教案,小学英语优质课教案?
  3. 前端学习(2930):内嵌改变样式
  4. 羡慕,浙江大学的双 11 快递,全部由物流机器人配送
  5. 2010多校第一题 hdu3440House Man 差分约束系统
  6. 地理空间数据云下载的dem数据打不开怎么办? 显示光盘映像已损坏
  7. 浪曦struts2学习笔记3
  8. 尝试用朴素贝叶斯分析借款信用等级
  9. OpenCV IplImage图片结构
  10. 互联网大佬生存法则 如何防守周鸿祎
  11. vm安装centos,黑屏或黑屏且左上角有光标闪动
  12. 通过关键词爬取百度图片——Python爬虫
  13. SQL教程之使用 dbt 和 SQLfluff 整理 SQL
  14. 网站首页导航栏移入移出动画(一)slideDown、slideUp
  15. php网站设计说课ppt,电子教案5-2网页设计.ppt
  16. Unity-Live2d(鼠标拖拽触发动作变化)
  17. 【R语言文本挖掘】:n-grams和相关性计算
  18. Error response from daemon: Container xxx is not running的解决方法
  19. 求1到n中与n互质的和(数论)解释及证明
  20. Frog Jumps

热门文章

  1. iOS通itms-services://协议安装ipa,省去https环境的搭建
  2. ChatGPT神奇用法:定点周边景点推荐,Get私人导游!
  3. 一个程序猿的讨薪日记
  4. win10系统安装iso文件,绝对可下。
  5. 【旧资料整理】解决firefox3迅雷插件右键查看页面源代码无效问题
  6. 浅谈SAP关于存货计价过程
  7. Programming Languages PartA Week5学习笔记——SML进阶与编程哲学
  8. r语言nonzerocoef函数_R语言pec包深度验证Cox模型
  9. 总结两个Javascript的哈稀对象的一些编程技巧
  10. 4W家庭理财 V2.3