MySql学习笔记(二)4.15 - 4.17

MySql学习笔记

笔记内容学习来自B站狂神说java,狂神小迷弟一枚

课程链接: 快来点我,支持狂神..

这是目录

  • MySql学习笔记
  • 6. 事务
    • 6.1 什么是事务
    • 6.2 事务转账示例
  • 7.索引
    • 7.1 索引的分类
    • 7.2 测试索引
    • 7.3 索引原则
  • 8. 权限管理和备份
    • 8.1 用户管理
    • 8.2 数据库备份
  • 9. 规范数据库设计
    • 9.1 数据库为什么需要设计
    • 9.2 三大范式
  • 10. JDBC(重点)
    • 10.1 数据库驱动
    • 10.2 JDBC
    • 10.3 第一个JDBC程序
    • 10.4 Statement 对象
      • 10.4.1 提取工具类
      • 10.4.2 编写 增 删 改
      • 10.4.3 编写查询
      • 10.4.4 SQL注入
    • 10.5 PreparedStatement 对象
    • 10.6 使用IDEA链接数据库
    • 10.7 jdbc事务
    • 10.8 数据库连接池(DBCP-C3P0)

6. 事务

6.1 什么是事务

要么都成功,要么都失败

将一组SQL放在一个批次中去执行

事务(Transaction)原则: ACID

  • 原子性:

    一组步骤要么都完成,要么都失败,不能只发生一个步骤。

  • 一致性:

    最终一致性,事务前后的数据完整性要保持一致(最后结果和预期计算的要一样)

  • 隔离性:

    针对多个用户同时操作,主要是排除其他事物对本次事务的影响。

  • 持久性:

    事务结束后的数据不随着外界原因导致数据失败,事务没有提交恢复到原状;事务已经提交,持久化到数据库。事务一旦提交就不可逆。

事务的隔离级别(出现的问题)

  • 脏读:

    指一个事务读取了另一个事务未提交的数据

  • 不可重复读:

    在一个事务内读取表中的某一行数据,多次读取结果不同。(不一定是错误,但是某些场合不对)

  • 虚读(幻读):

    指在一个事务内读取到别的事务插入的数据,导致前后读取不一致。

6.2 事务转账示例

测试事务实现转账

--事务操作
-- MySql 是默认开启事务自动提交的
SET autocommit = 0 / 1 /* 关闭 / 开启 */

--手动处理事务
SET autocommit = 0 --关闭自动处理事务
--事务开启
START TRANSACTION --标记一个事物的开始,从这个之后的sql都在同一个事务内

INSERT XX
INSERT XX
--提交 : 持久化
COMMIT
--回滚 : 回到原来的样子
ROLLBACK
--事务结束
SET autocommit = 1 --开启提交

--了解补充
SAVEPOINT 保存点名字 --设置一个事务的保存点
ROLLBACK TO SAVEPOINT保存点名字 --回滚到保存点

--模拟场景 转账
--商店 数据库
CREATE DATEBASE shop CHARACTER SET utf8 COLLATE utf_8_general_ci
USE shop
-- 账户表
CREATE TABLE `account`(
	`id` INT(3) NOT NULL AUTO_INCREMENT,
    `name` VACHAR(30) NOT NULL,
    `money` DECIMAL(9,2) NOT NULL,
    PRIMARY KEY (`id`)
)ENGIN = INNODB DEFAULT CHARSET utf8

--插入 yzy 50000元 htk 3000元
INSERT INTO account VALUES (1,'YZY',500000.00),(2,'HTK',3000.00)

--模拟事务
SET autocommit = 0;
START TRANSACTION
UPDATE account SET money = money - 500 WHERE `name` = 'HTK'  --HTK少500
UPDATE account SET money = money + 500 WHERE `name` = 'YZY' --YZY多500

COMMIT;
ROLLVACK;

SET autocommit = 1;

在java中事务就是一个方法

function(){

	try(){
	/*
	正常业务代码
	*/
	commit() //成功提交
	}catch(){
		
		roollcack() //出现异常回滚	
	}
}

7.索引

MySql 官方对索引的定义为:索引(index)是帮助MySql高效获取数据得数据结构。

提取句子主干,就可以得到索引的本质,索引是数据结构。

7.1 索引的分类

索引分类

  • 主键索引(PRIMARY KEY)
    • 唯一的标识,逐渐不可重复,只有一个列作为主键
  • 唯一索引(UNIQUE KEY)
    • 避免重复的列出现,唯一索引可以重复,多个列都可以标识位,唯一索引
  • 常规索引( KEY/INDEX )
    • 默认的,index/key关键词来设置
  • 全文索引(FULLTEXT)
    • 在特定的数据库引擎才有,MyISAM
    • 快速定位数据

索引的使用

  1. 在创建表的时候给字段增加索引
  2. 创建完毕后,增加索引
/*显示所有索引*/
SHOW INDEX FROM student

/*增加一个全文索引 (索引名字)列名*/
ALTER TABLE school.student ADD FULLTEXT INDEX `studentName`(`studentName`)

/*EXPLAN 分析sql执行的状况*/
EXPLAN SELECT * FROM student; /*非全文索引(常规索引)*/

EXPLAN SELECT * FROM student WHERE MATCH(studentName) AGAINST('刘');

7.2 测试索引

SQL 编程创建 100 万条数据 测试索引 (了解即可)

-- 创建表
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(50) DEFAULT '' COMMENT '用户手机',
	`gender` TINYINT(4) UNSIGNED DEFAULT '0' COMMENT '性别(0:男 1:女)',
	`password` VARCHAR(50) NOT NULL COMMENT '密码',
	`age` TINYINT(4) DEFAULT '0' COMMENT '年龄',
	`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
	`update_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
	PRIMARY KEY(`id`)
)ENGINE = INNODB DEFAULT CHARSET = utf8mb4 COMMENT = 'app用户表'



-- 插入100万数据.
DELIMITER $$ -- 写函数之前必须要写,标志
CREATE FUNCTION mock_data ()
RETURNS INT
BEGIN
	DECLARE num INT DEFAULT 1000000;
	DECLARE i INT DEFAULT 0;
	WHILE i
  • 索引再小数据量的时候感觉不明显,在大数据上很有用很常用。

7.3 索引原则

  • 索引不是越多越好
  • 不要对经常变动的数据添加索引
  • 小数据量的表不需要加索引
  • 索引一般加载常用查询字段上

索引的数据结构

  • Hash类型的索引
  • Btree类型的索引 : INNODB的默认索引类型

索引参考资料:https://blog.codinglabs.org/articles/theory-of-mysql-index.html

8. 权限管理和备份

8.1 用户管理

SQLyod 可视化管理

  • root 最高级别
  • 自定义用户 - 可选全局特权

SQL 命令操作

-- 创建用户名和密码![在这里插入图片描述](https://img-blog.csdnimg.cn/20200417000455173.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1ODkxNTIw,size_16,color_FFFFFF,t_70)
CREATE USER xiaohu INENTIFIED BY '123456'

-- 修改密码
SET PASSWORD = PASSWORD('666666')
SET PASSWORD FOR xiaohu= PASSWORD('666666')

-- 重命名
RENAME USER xiaohu TO lwx

-- 授权(最高权限,但还不是root用户,因为并不能给别人权限)
GRANT ALL PRIVILEGES ON *.* TO rock

-- 查看权限
SHOW GRANTS FOR rock
SHOW GRANTS FOR root@localhost

-- 撤销权限
REVOKE ALL PRIVILEGES ON *.* FROM rock

8.2 数据库备份

为什么要备份:

  • 保证重要的数据不丢失
  • 数据转移

MySql数据库备份的方式

  • 直接拷贝物理文件

  • 在Sqlyog这种可视化工具手动导出

  • 使用命令行 导出 mysqldump

    • -- 导出
      mysqldump -hlocalhost -uroot -p123456school student >D:/a.sql
      
      --导入
      --先登录
      source <D:/a.sql
      

9. 规范数据库设计

9.1 数据库为什么需要设计

当数据库比较复杂的时候,我们就需要就需要设计了

糟糕的数据库设计

  • 数据冗余,浪费空间
  • 数据插入和删除都会很麻烦,异常(屏蔽使用物理外键)

良好的数据库设计

  • 节省内存空间
  • 保证数据库的完整性
  • 方便我们开发系统

软件开发中,关于数据库的设计

  • 分析需求:分析业务和需要处理的数据库的需求
  • 概念设计:关系设计图E-R图

设计数据库的步骤(以个人博客为例子)

  • 收集信息,分析需求
    • 用户表(用户登录注销,用户个人信息,写博客,创建分类)
    • 分栏表(文章分类,分类创建者)
    • 文章表(文章信息)
    • 自定义表(系统信息,某个关键的字,或者一些主字段 key:value)//不是规范,个人习惯
  • 标识实体(把需求落实到每个字段)
  • 标识实体之间的关系
    • 对博客的CUDR:user–>blog
    • 对分类的CUDR:user -->category

9.2 三大范式

为什么需要数据规范化?

  • 信息重复
  • 更新异常
  • 插入异常
    • 无法正常显示
  • 删除异常
    • 丢失有效信息

三大范式

  • 三范式的目的:(规范数据库设计)

第一范式(1NF)

  • 原子性

  • 需要保证每一列不可再分的原子数据项,不可以表中表。

第二范式(2NF)

  • 消除非主属性对主码的部分依赖

  • 在1NF的基础上,每张表只描述一件事情:既一张表中的每一列必须和该表的主键相关(可以使直接也可可是间接)。

第三范式(3NF)

  • 消除传递依赖
  • 在2NF的基础上,确保一张表中的每一列都和主键直接相关

规范性和性能有冲突

  • 阿里手册中 规定关联查询的表不得超过三张表。
  • 实际开发中,需考虑商业化需求和目标(成本,用户体验)但数据库性能更加重要。
  • 在规范性能的问题的时候,需要适当的考虑下规范性。
  • 故意给某些表增加一些冗余字段。(多表查询变为单表查询)
  • 故意增加一些计算列(从大数据量查询降低为小数据量查询)

10. JDBC(重点)

10.1 数据库驱动

驱动:声卡,显卡,数据库

为什么需要数据库驱动

  • 应用程序不能直接访问数据库,需要通过数据库驱动和数据库打交道。
  • 数据库厂商提供不同的数据库驱动。

MySql学习笔记(二)4.15 - 4.17_第1张图片

10.2 JDBC

SUN公司为简化开发人员(对数据库的统一)操作,提供了一个(java操作数据库的)规范,俗称JDBC

这些规范的实现由具体的厂商去做。

对开发人员来说,只需要掌握JDBC接口操作即可。

  • 没有什么是加一层解决不了的问题
  • java.sql
  • javax.sql
  • 还需要导入一个数据库驱动包 mysql-connector-java-5.1.47.jar
    MySql学习笔记(二)4.15 - 4.17_第2张图片

10.3 第一个JDBC程序

创建测试数据库

1.新建测试数据库

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','[email protected]','1980-12-12'),
(2,'lisi','123456','[email protected]','1980-7-04'),
(3,'wangwu','123456','[email protected]','1980-3-14');

2.在项目中导入数据库驱动jar包,记得ADD library

3.编写测试代码

package com.htk.jdbcstudy;

import java.sql.*;
import javax.sql.*;

//我的第一个jdbc程序
public class jdbcFirstDemo {

    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //1.加载驱动
        Class.forName("com.mysql.jdbc.Driver");

        //2.用户信息和url,固定的记忆
        String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
        String username = "root";
        String password = "";

        //3.连接成功,  数据库对象 Connection 代表数据库
        Connection connection = DriverManager.getConnection(url,username,password);

        //4.执行sql的对象 Statement
        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("birthday=" + resultSet.getObject("birthday"));
            System.out.println("---------------------------------------------------------------");
        }
        //6.释放连接
        resultSet.close();;
        statement.close();;
        connection.close();

    }
}

MySql学习笔记(二)4.15 - 4.17_第3张图片
步骤总结:

1、加载驱动

2、链接数据库 DriverManager

3、获得执行sql的对象 Statement

4、获取返回结果集

5、释放连接

DriverManager

Class.forName("com.mysql.jdbc.Driver"); //固定写法,加载驱动

//Connection 代表数据库
//数据库设置自动提交
//事务提交
//事务回滚
connection.rollback();
connection.commit();
connection.setAutoCommit(true);

URL

//协议://主机地址:端口号/数据库名?参数1&参数2&参数3
//mysql默认端口号3306

String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";

Statement执行sql的对象

String sql = "SELECT * FROM users"; //编写sql

statement.executeQuery(); //查询操作返回ResultSet
statement.execute();//执行任何sql
statement.executeUpdate(); //更新,插入,删除都是用这个,返回一个受影响的行数

ResultSet 查询的结果集:封装了所有查询结果

获得指定的数据类型

//获取指定类型
        resultSet.getObject(); //在不知道列类型的情况使用
        resultSet.getString();
        resultSet.getInt();
        resultSet.getFloat();
        resultSet.getDate();

遍历

//查询出的结果就是像数组,可以自由移动
        resultSet.next(); //向下移动
        resultSet.beforeFirst(); //移动到最前面
        resultSet.afterLast();  //移动到最后面

释放资源

//释放连接
        resultSet.close();;
        statement.close();;
        connection.close();
//好资源,用完关闭

10.4 Statement 对象

jdbc中的statement对象用于向数据库发送sql语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可。

statement对象的executeUpdate方法,用于向数据库发送增、删、改的sql语句,executeUpdate执行完成后,将会返回一个整数(既增删改查语句导致了数据库有多少行数据发生变化)。

Statement.executeQuery方法用于向数据库发送查询语句,excuteQuery方法返回代表查询结果的ResultSet对象。

CRUD 操作 - - - create

使用executeUpdate(String sql)方法完成数据添加操作,示例操作:

Statement st = connection.createStatement();
String sql = "insert into user(...) values(...)";
int num = st.executeUpdate(sql);
if(num>0){
	System.out.println("插入成功!");
}

CRUD 操作 - - - delete

使用executeUpdate(String sql)方法完成数据删除操作,示例操作:

Statement st = connection.createStatement();
String sql = "delete from user";
int num = st.executeUpdate(sql);
if(num>0){
	System.out.println("删除成功!");
}

CRUD 操作 - - - update

使用executeUpdate(String sql)方法完成数据修改操作,示例操作:

Statement st = connection.createStatement();
String sql = "update user set name ='' where name = ''";
int num = st.executeUpdate(sql);
if(num>0){
	System.out.println("修改成功!");
}

CRUD 操作 - - - query

使用executeQuery(String sql)方法完成数据添加操作,示例操作:

Statement st = connection.createStatement();
String sql = "SELECT * FROM users where id = 1";
ResultSet resultSet = st.executeQuery(sql);
while(resultSet.next()){
	System.out.println("...");
}

代码实现

10.4.1 提取工具类

  • db.properties File 放在src下
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true
username=root
password=
  • utils 工具类
package com.htk.jdbcstudy.lesson02.utils;

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;

    static {

        try{
            //输入流
            InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
            Properties properties = new Properties();
            properties.load(in);

           driver = properties.getProperty("driver");
           url = properties.getProperty("url");
           username = properties.getProperty("username");
           password = properties.getProperty("password");

           //1.驱动只用加载一次
            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 cont, 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 (cont!=null){
            try{
                cont.close();
            }catch (SQLException e){
                e.printStackTrace();
            }
        }

    }

}

10.4.2 编写 增 删 改

package com.htk.jdbcstudy.lesson02;

import com.htk.jdbcstudy.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 cont = null;
        Statement st = null;
        ResultSet rs = null;

        try {
            cont = JdbcUtils.getConnection();
            st = cont.createStatement();
            String sql ="INSERT INTO users(id,`name`,`password`,email,birthday) VALUES(4,'htk','123456','[email protected]','1997-01-12')";
            int num = st.executeUpdate(sql);
            if(num>0){
                System.out.println("插入成功!");
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(cont,st,rs);
        }

    }
}

package com.htk.jdbcstudy.lesson02;

import com.htk.jdbcstudy.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class Testdelete {
    public static void main(String[] args) {

        Connection cont = null;
        Statement st = null;
        ResultSet rs = null;

        try {
            cont = JdbcUtils.getConnection();
            st = cont.createStatement();
            String sql ="DELETE FROM users WHERE id = 4";
            int num = st.executeUpdate(sql);
            if(num>0){
                System.out.println("删除成功!");
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(cont,st,rs);
        }

    }
}

package com.htk.jdbcstudy.lesson02;

import com.htk.jdbcstudy.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class Testupdate {
    public static void main(String[] args) {

        Connection cont = null;
        Statement st = null;
        ResultSet rs = null;

        try {
            cont = JdbcUtils.getConnection();
            st = cont.createStatement();
            String sql ="update users set `name`='yzy',email='[email protected]',birthday='1999-06-15' where id = 1 ";
            int num = st.executeUpdate(sql);
            if(num>0){
                System.out.println("修改成功!");
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(cont,st,rs);
        }

    }
}

10.4.3 编写查询

package com.htk.jdbcstudy.lesson02;

import com.htk.jdbcstudy.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TestQuery {
    public static void main(String[] args) {

        Connection cont = null;
        Statement st = null;
        ResultSet rs = null;

        try {
            cont = JdbcUtils.getConnection();
            st = cont.createStatement();
            String sql ="select * from users";
            rs = st.executeQuery(sql);
            while(rs.next()){
                System.out.println(rs.getString("name"));
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(cont,st,rs);
        }

    }
}

10.4.4 SQL注入

SQL注入

SQL存在漏洞,会被攻击导致数据泄露,SQL会被拼接。

package com.htk.jdbcstudy.lesson02;

import com.htk.jdbcstudy.lesson02.utils.JdbcUtils;

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("yzy","123456");
        //非正常登陆
        login(" 'or '1=1","'or '1=1");
        //"select * from users where `name` = ''or '1=1' and password = ''or '1=1'"
        //name是空或者1=1则为真是恒成立的,说明可通过拼接字符串的漏洞来获取用户信息,有安全隐患。
    }

    //登陆业务
    public static void login(String username,String password){

        Connection cont = null;
        Statement st = null;
        ResultSet rs = null;

        try {
            cont = JdbcUtils.getConnection();
            st = cont.createStatement();
            String sql ="select * from users where `name` = '"+username+"' and password = '"+password+"'";
            rs = st.executeQuery(sql);
            while(rs.next()){
                System.out.println("登陆成功");
                System.out.print("账号:");
                System.out.println(rs.getString("name"));
                System.out.print("密码:");
                System.out.println(rs.getString("password"));
                System.out.println("====================================");
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(cont,st,rs);
        }

    }
}

10.5 PreparedStatement 对象

PreparedStatement 可以防止SQL注入,还可以调高效率

package com.htk.jdbcstudy.lesson03;

import com.htk.jdbcstudy.lesson02.utils.JdbcUtils;

import java.sql.*;

public class TestInsert {
    public static void main(String[] args) {

        Connection cont = null;
        PreparedStatement pst = null;
        ResultSet rs = null;

        try{
        cont = JdbcUtils.getConnection();
        //区别是,使用? 占位符代替参数
        String sql ="INSERT INTO users(id,`name`,`password`,email,birthday) VALUES(?,?,?,?,?)";
        //预编译SQL,先写sql,然后不执行
        pst = cont.prepareStatement(sql);
        //手动设置参数
        pst.setInt(1,5);
        pst.setString(2,"yyy");
        pst.setString(3,"123456");
        pst.setString(4,"[email protected]");
        //注意点 sql.Date  数据库 java.sql.Date()
            // 和 util.Date java  new Date().getTime()获得时间戳
        pst.setDate(5,new java.sql.Date(new java.util.Date().getTime()));
        //预编译完后直接调用执行方法
        int num = pst.executeUpdate();
        if(num > 0){
            System.out.println("插入成功");
        }
        }catch(SQLException e){
            e.printStackTrace();
        }finally {
            JdbcUtils.release(cont,pst,rs);
        }
    }
}

package com.htk.jdbcstudy.lesson03;

import com.htk.jdbcstudy.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 cont = null;
        PreparedStatement pst = null;
        ResultSet rs = null;

        try{
            cont = JdbcUtils.getConnection();
            //区别是,使用? 占位符代替参数
            String sql ="DELETE FROM users WHERE id = ?";
            //预编译SQL,先写sql,然后不执行
            pst = cont.prepareStatement(sql);
            //手动设置参数
            pst.setInt(1,4);

            //预编译完后直接调用执行方法
            int num = pst.executeUpdate();
            if(num > 0){
                System.out.println("删除成功");
            }
        }catch(SQLException e){
            e.printStackTrace();
        }finally {
            JdbcUtils.release(cont,pst,rs);
        }
    }
}

package com.htk.jdbcstudy.lesson03;

import com.htk.jdbcstudy.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 cont = null;
        PreparedStatement pst = null;
        ResultSet rs = null;

        try{
            cont = JdbcUtils.getConnection();
            //区别是,使用? 占位符代替参数
            String sql ="update users set `name`=?,email=?,birthday=? where id = ?";
            //预编译SQL,先写sql,然后不执行
            pst = cont.prepareStatement(sql);
            //手动设置参数
            pst.setInt(4,1);
            pst.setString(1,"yzy");
            pst.setString(2,"[email protected]");
            //注意点 sql.Date  数据库 java.sql.Date()
            // 和 util.Date java  new Date().getTime()获得时间戳
            pst.setDate(3,new java.sql.Date(new java.util.Date().getTime()));
            //预编译完后直接调用执行方法
            int num = pst.executeUpdate();
            if(num > 0){
                System.out.println("修改成功");
            }
        }catch(SQLException e){
            e.printStackTrace();
        }finally {
            JdbcUtils.release(cont,pst,rs);
        }
    }
}

package com.htk.jdbcstudy.lesson03;

import com.htk.jdbcstudy.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class TestQuery {

    public static void main(String[] args) {

        Connection cont = null;
        PreparedStatement pst = null;
        ResultSet rs = null;

        try{
            cont = JdbcUtils.getConnection();
            //区别是,使用? 占位符代替参数
            String sql ="select * from users where id >= ?";
            //预编译SQL,先写sql,然后不执行
            pst = cont.prepareStatement(sql);
            //手动设置参数
            pst.setInt(1,1);

            //预编译完后直接调用执行方法
            rs = pst.executeQuery();
            while(rs.next()){
                System.out.println("账号:"+rs.getString("name")+" 密码:"+rs.getString("password"));
            }
        }catch(SQLException e){
            e.printStackTrace();
        }finally {
            JdbcUtils.release(cont,pst,rs);
        }
    }
}

SQL注入

  • prepareStatement 防止 SQL注入的本质,就是把传递进来的参数当做字符。
  • 假设其中存在转义字符,会被直接转义。 比如说 ’ 号会被直接转移 后期进阶 mybatis
package com.htk.jdbcstudy.lesson02;

import com.htk.jdbcstudy.lesson02.utils.JdbcUtils;

import java.sql.*;

public class SQL注入 {
    public static void main(String[] args) {
        //正常登陆
        login("yzy","123456");
        //非正常登陆
        login(" ''or 1=1","'' or 1=1");
        //"select * from users where `name` = ''or '1=1' and password = ''or '1=1'"
        //name是空或者1=1则为真是恒成立的,说明通过拼接字符串的漏洞导致被攻击。
    }

    //登陆业务
    public static void login(String username,String password){

        Connection cont = null;
        PreparedStatement pst = null;
        ResultSet rs = null;

        try {
            cont = JdbcUtils.getConnection();

            cont = JdbcUtils.getConnection();
            //区别是,使用? 占位符代替参数
            //prepareStatement 防止 SQL注入的本质,就是把传递进来的参数当做字符。
            //假设其中存在转义字符,会被直接转义。 比如说 ' 号会被直接转移 后期进阶 mybatis
            String sql ="select * from users where `name`=? and `password`=?";
            //预编译SQL,先写sql,然后不执行
            pst = cont.prepareStatement(sql);
            //手动设置参数
            pst.setString(1,username);
            pst.setString(2,password);

            rs = pst.executeQuery();
            while(rs.next()){
                System.out.println("登陆成功");
                System.out.print("账号:");
                System.out.println(rs.getString("name"));
                System.out.print("密码:");
                System.out.println(rs.getString("password"));
                System.out.println("====================================");
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(cont,pst,rs);
        }

    }
}

10.6 使用IDEA链接数据库

打开右侧Datebase - - - 添加 Date Source - - - MySQL

MySql学习笔记(二)4.15 - 4.17_第4张图片

在General 选项卡中输入数据库账号密码,test 连接

在Schemas选项卡中添加数据库,添加完成后可直接双击表查看,修改需要点击上方的DB确定修改

Console

切换数据库

10.7 jdbc事务

隔离性产生的问题

脏读、不可重复读、虚读(幻读)

事务代码实现示例

package com.htk.jdbcstudy.lesson04;

import com.htk.jdbcstudy.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class TestTransaction01 {
    public static void main(String[] args) {
        Connection cont = null;
        PreparedStatement pst = null;
        ResultSet rs = null;

        try{
            cont = JdbcUtils.getConnection();
            //关闭额自动提交,就会开启事务
            cont.setAutoCommit(false);

            String sql1 = "update users set id =id + 10 where id < ?";
            pst = cont.prepareStatement(sql1);
            pst.setInt(1,2);
            pst.executeUpdate();

            // int x = 1/0;

            String sql2 = "update users set id =id - 10 where id > ?";
            pst = cont.prepareStatement(sql2);
            pst.setInt(1,2);
            pst.executeUpdate();

            cont.commit();
            System.out.println("提交事务成功");
        }catch (SQLException e){
            //若失败则默认回滚,不写rollback也会回滚。
            try {
                cont.rollback();   //失败回滚
            } catch (SQLException ex) {
                ex.printStackTrace();
            }

            e.printStackTrace();
        }

    }
}

10.8 数据库连接池(DBCP-C3P0)

  • 数据库连接 — 执行完毕 — 释放

  • 连接 – 释放这一流程十分系统资源

池化技术:准备一些预先的资源,过来就连接预先准备好的

  • 最小连接数:10,一般情况下为常用连接数。
  • 最大连接数:100,,业务的最高承载上限。
  • 等待超时:100ms

编写连接池,只需要实现一个接口DateSource

开源数据源实现 (拿来即用)

DBCP

C3P0

Druid:阿里

  • 使用了这些数据库连接池之后,在项目开发中就不需要编写连接数据库的代码了!

DBCP

需要用到的jar包 commons-dbcp-1.4.jar、commons-pool-1.4.jar

  • utils包更新 JdbcUtils_DBCP
package com.htk.jdbcstudy.lesson05;

import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

public class JdbcUtils_DBCP {

    private  static DateSource dateSource = null;

    static {

        try{
            //输入流
            InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
            Properties properties = new Properties();
            properties.load(in);

            //创建数据源 工厂模式 - - - > 创建
            dateSource = BasicDateSourceFactory.createDateSource(properties);

           //1.驱动只用加载一次
            Class.forName(driver);

        }catch (Exception e){
            e.printStackTrace();

        }

    }

    //获取连接
    public static Connection getConnection() throws SQLException {
        return dateSource.getConnection(); //从数据源中获取连接
    }


    //释放资源
    public static void release(Connection cont, 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 (cont!=null){
            try{
                cont.close();
            }catch (SQLException e){
                e.printStackTrace();
            }
        }

    }

}
  • 对应的主程序里只需要把原先的 JdbcUtils 替换为 JdbcUtils_DBCP即可
//无任何变化,读源码学习
//原来为
cont = JdbcUtils.getConnection();
JdbcUtils.release(cont,pst,rs);
//修改后
cont = JdbcUtils_DBCP.getConnection();
JdbcUtils_DBCP.release(cont,pst,rs);

C3P0

需要用到的jar包 c3p0-0.9.5.5.jar 、mchange-commons-java-0.2.19.jar

  • C3P0 使用 xml配置

结论

无论使用何种数据源,本质还是相同的

Apache大法好

MySql学习笔记(二)4.15 - 4.17_第5张图片

你可能感兴趣的:(MySql)