JDBC的学习笔记

JDBC

学习完了mysql之后,下一步就是用Java去连接数据库,实现具体的操作,那么最基础的就是JDBC了,于是学习了JDBC,放在博客上,一方面方便自己之后忘记来快速回顾,另一方面希望帮助小伙伴们。大家如果有什么问题,或者对本博客的代码由异议或者有更好的看法与建议,欢迎评论。我们一起学习,一起进步(如果有幸能得到大佬访问,那就更好了)


``在开始之前,还是想约定一下环境:

  • 数据库版本:mysql5.7
  • mysql驱动的依赖版本:5.1.27
  • 使用工具:IDEA

一、数据库驱动

  • 数据库驱动实际上就是各大数据库实现了Java中的JDBC接口。所以数据库的驱动就是JDBC的实现类
  • 实现驱动需要加载一个jar包
    • 在Maven仓库中下载:https://mvnrepository.com/artifact/mysql/mysql-connector-java
    • 下载的时候注意版本和使用的人数(关系到是否稳定的问题)

二、第一个JDBC程序

2.1 创建一个新的项目

  • 创建一个Java项目
  • 创建待会执行sql语句要用到的表
    • 可以基于命令行
    • 也可以基于SQLyog等图形化界面

2.2 加载数据库驱动

  • 在项目文件中创建一个lib目录
  • 将jar包导入
  • 右键单击lib,选择Add as library ,添加到项目文件当中
  • 当导入的jar包可以在lib目录下展开的时候,说明加载数据库驱动成功

2.3 编写测试代码

  • 首先要先连接数据库

    • 点击最右面的Database,加载mysql,将创建的表导入
    • 测试导入是否成功
  • 编写测试代码

    • 步骤:
      • 1、加载驱动
      • 2、填写用户信息
      • 3、连接数据库
      • 4、执行SQL对象
      • 5、执行SQL的对象 去 执行SQL , 可能存在结果,查看返回的结果
      • 6、释放资源(先定义后释放)
    package com.zhang.jdbc.demos;
    
    import java.sql.*;
    
    public class demo2 {
        public static void main(String[] args) throws ClassNotFoundException, SQLException {
            // 1、加载驱动
            Class.forName("com.mysql.jdbc.Driver");
            /**
             * 加载驱动不需要返回一个class的结果,因为后面用不到
             * 在Driver当中本身就有一个注册驱动的语句,所以不需要自己注册
             * */
    
            // 2、用户信息和url
    //        useUnicode=true       //可以使用中文编码
    //                &characterEncoding=UTF8   // 设置中文编码格式
    //                &useSSL=true      // 使用安全的连接
            String url = "jdbc:mysql://localhost:3306/db3?useUnicode=true&characterEncoding=UTF8&useSSL=false";
            String username = "root";
            String password = "20zzy100588A";
            /**
             * url的格式:
             *         协议//主机地址:端口号/数据库名称?设置1&设置2&设置3
             * username 和 password 是你自己的数据库的登录账号和密码 --- 需要匹配起来
             * */
    
            // 3、连接成功,数据库对象    Connection 代表数据库
            Connection conn = DriverManager.getConnection(url , username , password);
    
            /**
             * Connection可以执行事务,代表数据库可执行的操作
             *
             * conn.commit();
             * conn.isReadOnly();
             * conn.rollback();
             * */
    
    
            // 4、执行SQL的对象
            Statement statement = conn.createStatement();
    
            // 5、执行SQL的对象 去 执行SQL , 可能存在结果,查看返回的结果
            // 查询
            String sql = "select * from db3 " ;
            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("balance = " + resultSet.getObject("balance"));
            }
    
            // 改
            String sql1 = "update db3 set balance = 500 where id = 1 ";
             int count = statement.executeUpdate(sql1);
    
            System.out.println(count);
    
            /**
             * statement.executeUpdate();   // 增删改都使用这个 , 返回对应的数据,如果返回的结果大于0 ,说明执行成功
             * statement.execute() ;        // 可以执行所有的SQL语句
             * statement.executeQuery();    // 返回查询的ResultSet结果集
             *
             * Result的结果集 , 封装了所有的查询结果
             *
             * // 返回结果集
             *  resultSet.getObject();      // 不知道数据类型的时候
             *  // 已知数据类型的时候
             *  resultSet.getByte();
             *  resultSet.getShort();
             *  resultSet.getInt();
             *  resultSet.getLong();
             *  resultSet.getFloat();
             *  resultSet.getDouble();
             *  resultSet.getBoolean();
             *  resultSet.getString();
             *
             *  // 遍历
             *   resultSet.beforeFirst();   // 移动到最前面
             *   resultSet.afterLast();     // 移动到最后面
             *   resultSet.next();          // 移动到下一个数据
             *   resultSet.previous();      // 移动到前一行
             *   resultSet.absolute(row);  // 移动到指定行
             * */
    
    
            // 6、释放连接      (后定义先释放)
            resultSet.close();
            statement.close();
            conn.close();
        }
    }
    
    

2.4 JDBC中对象的解释

  • 参见上方的代码的注释

三、Statement对象

3.1 Statement对象简述

  • 对statement对数据库进行增删改查,相当于对表内容的修改
  • connection 是对数据库的表的结构进行操作

3.2 工具类的提取

  • 提取工具类JdbcUtils

    • 第一步是配置依赖包(db.properties)

      # 此处是存放jdbc的通用配置
      #注意:里面不能有;和空格
      
      driver = com.mysql.jdbc.Driver
      url = jdbc:mysql://localhost:3306/db3?useUnicode=true&characterEncoding=UTF8&useSSL=false
      username = root
      //下面是写自己的密码
      password = *******
      
    • 第二步是书写工具类的代码

    package com.zhang.jdbc.utils;
    
    import java.io.InputStream;
    import java.sql.*;
    import java.util.Properties;
    
    // 工具类
    public class JdbcUtils {
    
        public static String driver = null;
        public static String url = null ;
        public static String username = null ;
        public static String password = null ;
    
    
        static{
            try {
                //获取到db.properties中的资源
                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 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.zhang.jdbc.demos;
    
    import com.zhang.jdbc.utils.JdbcUtils;
    
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    
    // 封装
    public class demo3 {
    
        public static void main(String[] args){
            Connection connection = null ;
            Statement st = null ;
            ResultSet rs = null ;
    
            try {
                connection = JdbcUtils.getConnection();
                String sql = "delete from db3 where id = 3 ";
                String sql1 = "insert into db3 (id , NAME , balance) values(3 , 'wangwu', 1500 )";
                st = connection.createStatement();
                int j = st.executeUpdate(sql);
                if(j >= 0){
                    System.out.println("删除成功!");
                }
    
                int i = st.executeUpdate(sql1);
                if(i >= 0 ){
                    System.out.println("插入成功!");
                }
    
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }finally{
                JdbcUtils.release(connection , st , rs);
            }
    
    
        }
    
    }
    
    

3.3 SQL注入

package com.zhang.jdbc.sqlhack;

import com.zhang.jdbc.utils.JdbcUtils;

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

// 演示sql注入
public class SqlHack {
    public static void main(String[] args){
       // 正常登录
       // login("root","123456");

        // SQL注入
        /**
         * SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,
         * 攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,
         * 在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,
         * 从而进一步得到相应的数据信息
         * */

        login(" 'or ' 1=1 "," 'or ' 1=1 ");
    }

    public static void login(String username , String password){
        Connection connection = null ;
        Statement statement = null ;
        ResultSet resultSet = null ;

        try {
            connection = JdbcUtils.getConnection();
            statement = connection.createStatement();

            //select * from user where NAME= '' or '1=1' and PASSWORD= ''or '1=1';
           String sql = "select * from user where NAME='"+ username +"' and PASSWORD='"+ password + "'" ;
            resultSet = statement.executeQuery(sql);
            while(resultSet.next()){
                System.out.println(resultSet.getString("NAME"));
                System.out.println(resultSet.getString("PASSWORD"));
                System.out.println("=======================================================");
            }

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally{
            JdbcUtils.release(connection,statement,resultSet);
        }
    }

}

3.4 PreparedStament

  • 可以防止SQL注入,效率更高
  • 步骤:
    • 利用工具类创建对象
    • 先写SQL语句,进行预编译
    • 后填写,然后执行
package com.zhang.jdbc.sqlhack.solvesqlhack;

import com.zhang.jdbc.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();

            String sql = "delete from user where NAME = 'zhaoliu' or NAME = 'zhaoqi'";
            st = conn.prepareStatement(sql);

            int res = st.executeUpdate();
            if(res >= 0){
                System.out.println("删除成功!");
            }

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

    }
}

防止SQL注入

package com.zhang.jdbc.sqlhack;

import com.zhang.jdbc.utils.JdbcUtils;

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

public class SqlHack2 {
    public static void main(String[] args){
        // 正常登录
        //login("root" , "123456");

        // SQL注入
        login(" 'or '1=1 " , " 'or ' 1=1 ");
        /**
         * 采用先编译 ,之后运行的方法对SQL注入进行截断,从而防止了SQL的注入
         * */

    }

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

        try {
            conn = JdbcUtils.getConnection();

            String sql = "select * from user where NAME = ? and PASSWORD = ?" ;
            st = conn.prepareStatement(sql);

            st.setString(1,username);
            st.setString(2,password);

            rs = st.executeQuery();

            while(rs.next()){
                System.out.println(rs.getObject("NAME"));
                System.out.println(rs.getObject("password"));
                System.out.println("======================================");
            }

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

    }
}

四、 JDBC操作事务

  • 满足ACID原则:
    • 原子性:或者全部成功,要么全部失败
    • 一致性:总数不变
    • 隔离性:多个进程互不干扰
      • 脏读:见Mysql数据库
      • 不可重复读:见Mysql数据库
      • 虚读(幻读):见Mysql数据库
    • 持久性:一旦提交不可逆,持久化到数据库
package com.zhang.jdbc.transaction;

import com.zhang.jdbc.utils.JdbcUtils;

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

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

        try {
            conn = JdbcUtils.getConnection();

            String sql = "update db3 set balance = ?";
            st = conn.prepareStatement(sql);
            st.setInt(1 , 1000);
            int i = st.executeUpdate();
            if(i >= 0 ){
                System.out.println("事务开启的准备工作已经完成");
                System.out.println("初始化完成!");
            }


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

package com.zhang.jdbc.transaction;

import com.zhang.jdbc.utils.JdbcUtils;

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

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

        try {
            conn = JdbcUtils.getConnection();

            // 关闭系统的自动提交功能, 相当于开启事务
            conn.setAutoCommit(false);

            // 事务的主体
            String sql1 = "update db3 set balance = (balance-500)  where id = ?";
            st = conn.prepareStatement(sql1);
            st.setInt(1 , 1);
            int i =  st.executeUpdate();

            String sql2 = "update db3 set balance = (balance + 500) where id = ?";
            st = conn.prepareStatement(sql2);
            st.setInt(1 , 3);
            int j = st.executeUpdate();

            if(i >= 0 && j >= 0){
                conn.commit();
                System.out.println("转账成功!");
            }

        } catch (SQLException throwables) {
            try {
                // 如果失败会自动执行回滚
                conn.rollback();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            throwables.printStackTrace();
        }finally {
            JdbcUtils.release(conn , st , rs);
        }
    }
}

五、数据库连接池

5.1 连接池简介

  • 数据库连接 — 执行完毕 — 释放
  • 连接和释放的过程十分浪费资源
  • 池化技术:准备一些预先的资源,过来就连接已经准备好的
    • 最小链接数:一般是常用的连接数
    • 最大连接数:最高承载上限
    • 等待超时: *** ms
  • 编写连接池实现一个接口 DateSource
  • 开源数据源的实现
    • DBCP
    • C3P0
    • Druid:阿里巴巴
  • 使用了这些数据库连接池之后,我们就不需要编写连接数据库的代码了

5.2 DBCP连接池

  • 需要用到的jar包:
    • commons-dbcp-1.4.jar
    • commons-pool-1.6.jar
    • 将上述包添加到相应项目的lib目录下
package com.zhang.jdbc.sqlhack.solvesqlhack;

import com.zhang.jdbc.utils.JdbcUtils;

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

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

        try {
            conn = JdbcUtils.getConnection();
           // 增加
            String sql = "insert into user (NAME , password) values (?,?)";
            st =  conn.prepareStatement(sql);     // 预编译

            // 手动赋值
            st.setString(1,"zhaoliu");
            st.setString(2,"123456");

            int res = st.executeUpdate();

            if(res >= 0){
                System.out.println("插入成功!");
            }

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

5.3 C3P0连接池

  • 需要用到的jar包:
    • c3p0-0.9.5.5.jar
    • mchange-commons-java-0.2.19.jar
    • 将上述包添加到相应项目的lib目录下

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值