【Mysql&JDBC】---JDBC学习笔记

一、数据库分类

1、关系型数据库:(SQL)

  • MySQL,Oracle, SQL Server, DB2, SQLite
  • 通过表和表之间,行和列之间的关系进行数据的存储。

2、非关系型数据库:(NO SQL)Not Only

  • Redis,MongDB。
  • 非关系型数据库,对象存储,通过对象自身的属性来决定。

二、Navicat 安装和破解工具

一、注意事项:

1. 运行注册机时最好关闭电脑的杀毒软件;
2. 运行注册机请断网,无需将注册机放到 Navicat Premium 安装目录下;
3. 请选择对各个版本,Products 那块;
4.安装完成后不要运行软件,然后打开注册机。

二、下载地址

navicat:https://www.navicat.com.cn/download/navicat-premium

注册机:Navicat_Keygen_Patch_v5.6

运行注册机按提示搞就完事了,第一个 patch 要选择安装路径下的 exe。

【MySQL 及 JDBC】

一、数据库驱动概念

image-20210724161713601

二、需要的包

  • java.sql
  • javax.sql

还需要导入一个数据库驱动包 mysql-connector-java

这里我的的 Mysql 版本是 5.5.53

image-20210724161958082

然后去 maven 仓库下对应的版本就可以了

image-20210724162148314

三、第一个 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, zhangsan, 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 );

2、导入数据库驱动

  • 首先新建在项目下新建一个文件夹 lib,用来存 jar 包,把我们下载好的 jar 包 copy 到里面去。然后右键 lib,选择 Add as Library。
  • image-20210724163032057

3、编写测试代码

package com.darkerg.lesson01;

import java.sql.*;

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

        //2. 连接信息
        // 使用 Unicode 编码,utf8 字符集,使用 SSL 安全连接。
        String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
        String username ="root";
        String password = "root";

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

        //4. 执行 SQL 的对象  Statement 执行 sql 的对象
        Statement statement = connection.createStatement();

        //5. 执行 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-->获得返回的结果值-->释放连接
URL

//mysql --3306
//jdbc:mysql:// 主机地址:端口号 / 数据库名?参数 1& 参数 2& 参数 3
//oracle --1521
//jdbc:oracle:thin@localhost:8521:sid

Statement	执行SQL的对象	PrepareStatement也是执行SQL的对象

statement.executeQuery();// 查询操作返回 ResultSet
statement.execute();// 执行任何 SQL
statement.executeUpdate();// 更新、插入、删除。都是用这个,返回一个受影响的行数。
ResultSet查询的结果集:封装了所有的查询结果

获得指定的数据类型
resultSet.getObject();// 在不知道列类型的情况下使用
// 如果知道列的类型就是用指定的类型
resultSet.getString();
resultSet.getInt();
resultSet.getFloat();
resultSet.getDouble();

// 遍历,与指针。
resultSet.beforeFirst();// 移动到最前面
resultSet.afterLast();// 移动到最后面
resultSet.next();// 移动到下一个数据
resultSet.previous();// 移动到前一行
resultSer.absolute(row);// 移动到指定行

4、statement 对象

image-20210724172024497

image-20210724172059166

image-20210724172114225

image-20210724172140374

image-20210724172200504

5、提取工具类 --- 代码实现

①创建一个配置文件 db.properties, 必须放置在 src 目录下

image-20210724172647077

②通过编写配置类 JdbcUtils 导入配置信息

package com.darkerg.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;
    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(IOException | ClassNotFoundException e){
            e.printStackTrace();
        }
    }

    // 获取连接
    public static Connection getConnetion() 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 throwables) {
                throwables.printStackTrace();
            }
        }
        if(st!=null){
            try {
                st.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }

}

③编写增删改的方法

package com.darkerg.lesson02;

import com.darkerg.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 {
            conn = JdbcUtils.getConnetion();// 获取数据库连接
            st = conn.createStatement();// 获得 sql 的执行对象
            // 增加
            String sql = "INSERT INTO users (id, `NAME`, `PASSWORD`, `email`, `birthday`)" +
                    "VALUES(4,'darkerg','123456','1064078506@qq.com','2020-12-30')";
			// 删除
            String sql = "DELETE FROM users WHERE id=4";
            // 修改
			String sql = "UPDATE users SET `NAME`='shuaige',`email`='123456@qq.com'WHERE id=1";
            
            int i = st.executeUpdate(sql);
            if(i>0){
                System.out.println("插入成功!");
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally{

            JdbcUtils.release(conn,st,rs);

        }

    }
}

④查询的方法

package com.darkerg.lesson02;

import com.darkerg.lesson02.utils.JdbcUtils;

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.getConnetion();// 获取数据库连接
            st = conn.createStatement();// 获得 sql 的执行对象
            String sql = "SELECT * FROM users WHERE id =1";

            rs = st.executeQuery(sql);// 查询

            if (rs.next()){
                System.out.println(rs.getString("NAME"));
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally{
            JdbcUtils.release(conn,st,rs);
        }

    }
}

6、SQL 注入问题

package com.darkerg.lesson02;

import com.darkerg.lesson02.utils.JdbcUtils;

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

public class SQLInjection {
    public static void main(String[] args) {
        //login("shuaige","123456"); 正常登陆
        login("'or'1=1","123456");
    }

    // 登录业务
    public static void login(String username,String password){
        Connection conn = null;
        Statement st = null;
        ResultSet rs = null;

        try {
            conn = JdbcUtils.getConnetion();// 获取数据库连接
            st = conn.createStatement();// 获得 sql 的执行对象
            String sql = "SELECT * FROM users WHERE `NAME`='"+username+"' AND `password` ='"+password+"'";

            rs = st.executeQuery(sql);// 查询

            if (rs.next()){
                System.out.println(rs.getString("NAME"));
                System.out.println(rs.getString("password"));
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally{
            JdbcUtils.release(conn,st,rs);
        }
    }
}

7、PreparedStatement 对象 预编译 SQL

PreparedStatement 可以防止 SQL 注入,效率也更好。

①新增

package com.darkerg.lesson03;

import com.darkerg.lesson02.utils.JdbcUtils;
import java.util.*;
import java.net.ConnectException;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;

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

        Connection conn = null;
        PreparedStatement st = null;


        try {
            conn = JdbcUtils.getConnetion();

            // 区别
            // 使用? 号占位符代替参数
            String sql = "INSERT INTO users (id, `NAME`, `PASSWORD`, `email`, `birthday`) values(?,?,?,?,?)";

            st = conn.prepareStatement(sql);    // 预编译 SQL,先写 SQl,然后不执行。

            // 手动给参数赋值
            st.setInt(1,4);//id
            st.setString(2,"qinjiang");//name
            st.setString(3,"123789");//pwd
            st.setString(4,"128937@qq.com");//email
            // 注意点:sql.Data  数据库
            //      util.Data  Java
            st.setDate(5,new java.sql.Date(new java.util.Date().getTime()));

            // 执行
            boolean execute = st.execute();
            if (execute){
                System.out.println("插入成功!");
            }

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,null);
        }

    }
}

②删除

String sql = "delete from users where id=?";

st.setInt(1,4);

③更新

String sql = "update users set `NAME`=? where id = ?";

st.setString(1,"狂神");
st.setInt(2,4);

④查询

package com.darkerg.lesson03;

import com.darkerg.lesson02.utils.JdbcUtils;

import java.sql.*;

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

        Connection conn = null;
        PreparedStatement st = null;
        ResultSet rs = null;

        try {
            conn = JdbcUtils.getConnetion();

            // 区别
            // 使用? 号占位符代替参数
            String sql = "select * from users where id = ?";

            st = conn.prepareStatement(sql);    // 预编译 SQL,先写 SQl,然后不执行。

            st.setInt(1,1);

            // 执行
            rs = st.executeQuery();
            if (rs.next()){
                System.out.println(rs.getString("NAME"));
            }

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,null);
        }

    }
}

⑤测试 SQL 注入问题

PreparedStatement 防止 SQL 注入的本质就是,把传递进来的参数当做字符,假设在其中存在转义字符,就直接忽略。' 单引号会被直接转移

package com.darkerg.lesson03;

import com.darkerg.lesson02.utils.JdbcUtils;

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

public class SQLInjection {
    public static void main(String[] args) {
//        login("shuaige","123456");
        login("'' or 1=1","123456");
    }

    public static void login(String username,String password){
        Connection conn = null;
        PreparedStatement st = null;
        ResultSet rs = null;

        try {
            conn = JdbcUtils.getConnetion();

            String sql = "select * from users where `NAME`=? and `PASSWORD`=?";

            st = conn.prepareStatement(sql);    // 预编译 SQL,先写 SQl,然后不执行。
            st.setString(1,username);
            st.setString(2,password);

            rs = st.executeQuery();
            if (rs.next()){
                System.out.println(rs.getString("NAME"));
                System.out.println(rs.getString("PASSWORD"));
                System.out.println("=============================");
            }

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtils.release(conn,st,null);
        }
    }
}

8、IDEA 连接 MySQL

image-20210725182143704

配置连接后可以选择数据库

image-20210725182422447

四、补充:事务

1、什么是事务

要么都成功,要么都失败。


1、SQL 执行 A 给 B 转账 A 1000 ---->200 B 200

2、SQL 执行 B 收到 A 的钱 A 800 ------>B 400


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

2、事务的 ACID 原则

原子性、一致性、隔离性、持久性。(脏读,幻读)

①原子性

一个事务要么全部提交成功,要么全部失败回滚,不能只执行其中的一部分操作,这就是事务的原子性。

②一致性

事务的执行不能破坏数据库数据的完整性和一致性,一个事务在执行之前和执行之后,数据库都必须处于一致性状态。

如果数据库系统在运行过程中发生故障,有些事务尚未完成就被迫中断,这些未完成的事务对数据库所作的修改有一部分已写入物理数据库,这是数据库就处于一种不正确的状态,也就是不一致的状态

③隔离性事务的隔离性是指在并发环境中,并发的事务时相互隔离的,一个事务的执行不能不被其他事务干扰。不同的事务并发操作相同的数据时,每个事务都有各自完成的数据空间,即一个事务内部的操作及使用的数据对其他并发事务时隔离的,并发执行的各个事务之间不能相互干扰。

脏读:指一个事务读取了另外一个事务未提交的数据。
不可重复读:在一个事务内读取表中的某一行数据,多次读取结果不同。(这个不一定是错误,只是某些场合不对)。
幻读:是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。

④持久性

事务一旦提交就不可逆

一旦事务提交,那么它对数据库中的对应数据的状态的变更就会永久保存到数据库中。-- 即使发生系统崩溃或机器宕机等故障,只要数据库能够重新启动,那么一定能够将其恢复到事务成功结束的状态

3、JDBC 操作事务

①创建测试用例:

image-20210725201341774

#创建账户表
create table account(
    id INT PRIMARY KEY AUTO_INCREMENT,
    NAME VARCHAR(40),
    money FLOAT
);

#插入测试数据
insert into account(name,money) values('A',1000);
insert into account(name,money) values('B',1000);
insert into account(name,money) values('C',1000);

②代码实现

package com.darkerg.lesson04;

import com.darkerg.lesson02.utils.JdbcUtils;

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

public class TestTransaction {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement st = null;
        ResultSet rs = null;

        try {
            conn = JdbcUtils.getConnetion();
            // 关闭数据库的自动提交功能,自动会开启事务。
            conn.setAutoCommit(false);

            // 转账
            String sql1 = "update account set money = money - 100 where name ='A'";

            st = conn.prepareStatement(sql1);
            st.executeUpdate();

            int x= 1/0;// 报错,测试事务。

            String sql2 = "update account set money = money + 100 where name ='B'";
            st = conn.prepareStatement(sql2);
            st.executeUpdate();

            // 业务完毕,提交事务
            conn.commit();
            System.out.println("转账成功");

        } catch (SQLException e) {
//            try {
//                conn.rollback();// 如果失败就回滚事务。
//            } catch (SQLException e1) {
//                e1.printStackTrace();
//            }
        }finally {
            JdbcUtils.release(conn,st,rs);
        }

    }
}

五、数据库连接池

1、概念

数据库连接 ---- 执行完毕 ----- 释放 十分浪费系统的资源

池化技术:

准备一些预先的资源,过来就连接预先准备好的

---- 开门 --- 业务员:等待 --- 服务 ----

常用连接数

最小连接数:5 个 10 个 100 个

最大连接数:1000 业务最高承载上限

排队等待

等待超时:100ms

2、编写连接池

①开源数据源实现

DBCP C3P0 Druid: 阿里巴巴

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

②DBCP

需要用到的 jar 包

commons-dbcp-1.4、commons-poll-1.6

下载后,添加到 lib 目录下。

DBCP 配置

#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?userUnicode=true&characterEncoding=utf8&useSSL=true
username=root
password=123456

#!-- 初始化连接 --
initialSize=10

#最大连接数量
maxActive=50

#!-- 最大空闲连接 --
maxIdle=20

#!-- 最小空闲连接 --
minIdle=5

#!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 --
maxWait=60000
# JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:【属性名=property;】
#注意:user 与 password 两个属性会被明确地传递,因此这里不需要包含他们。
connectionProperties=useUnicode=true;characterEncoding=utf8

#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true

#driver default 指定由连接池所创建的连接的只读(read-only)状态。
#如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix)
defaultReadOnly=true

#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_COMMITTED

**JdbcUtils_DBCP.java **

package com.darkerg.lesson05.utils;

import com.darkerg.lesson02.utils.JdbcUtils;
import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

public class JdbcUtils_DBCP {

    private static DataSource dataSource = null;

    static{
        try{
            InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.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 throwables) {
                throwables.printStackTrace();
            }
        }
        if(st!=null){
            try {
                st.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

测试类:TestDBCP.java

package com.darkerg.lesson05;

import com.darkerg.lesson02.utils.JdbcUtils;
import com.darkerg.lesson05.utils.JdbcUtils_DBCP;

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

public class TestDBCP {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement st = null;


        try {
            conn = JdbcUtils_DBCP.getConnection();

            // 区别
            // 使用? 号占位符代替参数
            String sql = "INSERT INTO users (id, `NAME`, `PASSWORD`, `email`, `birthday`) values(?,?,?,?,?)";

            st = conn.prepareStatement(sql);    // 预编译 SQL,先写 SQl,然后不执行。

            // 手动给参数赋值
            st.setInt(1,4);//id
            st.setString(2,"qinjiang");//name
            st.setString(3,"123789");//pwd
            st.setString(4,"128937@qq.com");//email
            // 注意点:sql.Data  数据库
            //      util.Data  Java
            st.setDate(5,new java.sql.Date(new java.util.Date().getTime()));

            // 执行
            boolean execute = st.execute();
            if (execute){
                System.out.println("插入成功!");
            }

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtils_DBCP.release(conn,st,null);
        }
    }
}

__EOF__

  • 本文作者: DarkerG
  • 本文链接: https://www.cnblogs.com/darkerg/p/15059123.html
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。