JDBC中DriverManage、Connection、Statement、Result、PrepareStatement等类和接口的详解

5 篇文章 0 订阅
2 篇文章 0 订阅

本文章以MySQL8.0为标准

第一节 JDBC入门
1.1.什么是JDBC
1.1.1.概念:

JDBC 是 Java 访问数据库的标准规范,真正怎么操作数据库还需要具体的实现类,也就是数据库驱动。每个 数据库厂商根据自家数据库的通信格式编写好自己数据库的驱动。所以我们只需要会调用 JDBC 接口中的方法即 可,数据库驱动由数据库厂商提供。
程序员操作数据库

1.1.2.快速入门
  • 步骤:
    1. 导入驱动jar包 mysql-connector-java-8.0.12.jar到项目的libs目录下,右键–>Add As Library
    2. 注册驱动
    3. 获取数据库连接对象 Connection
    4. 定义sql
    5. 获取执行sql语句的对象 Statement
    6. 执行sql,接受返回结果
    7. 处理结果
    8. 释放资源

  • 代码实现

package cn.JDBC;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;

public class JDBCDemo1 {
    public static void main(String[] args)throws Exception {
//   1. 导入驱动jar包 mysql-connector-java-8.0.12.jar
//   2. 注册驱动
        //方法一:
//      DriverManager.registerDriver(new com.mysql.jdbc.Driver());
        //方法二:
        Class.forName("com.mysql.cj.jdbc.Driver");
//    3. 获取数据库连接对象 Connection
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db3?serverTimezone=UTC", "root", "0826");
//    4. 定义sql
        String sql = "Update account set balance = 2000";
//    5. 获取执行sql语句的对象 Statement
        Statement stmt = conn.createStatement();
//    6. 执行sql,接受返回结果
        int count = stmt.executeUpdate(sql);
//    7. 处理结果
        System.out.println("影响的行数为:" + count);
//    8. 释放资源
        stmt.close();
        conn.close();
    }
}
1.2.JDBC核心API
接口或类作用
DriverManager类(1) 管理和注册数据库驱动 (2) 得到数据库连接对象
Connection接口一个连接对象,可用于创建 Statement 和 PreparedStatement 对象
Statement接口一个 SQL 语句对象,用于将 SQL 语句发送给数据库服务器
PrepareStatement接口一个 SQL 语句对象,是 Statement 的子接口
Result接口用于封装数据库查询的结果集,返回给客户端 Java 程序
1.3.导入驱动jar包
  • 导入驱动jar包 mysql-connector-java-8.0.12.jar到项目的libs目录下,右键–>Add As Library
    在这里插入图片描述
1.4.加载和注册驱动
加载和注册驱动的方法描述
Class.forName(“数据库驱动实现类”)加载和注册数据库驱动,数据库驱动由MySQL厂商实现"com.mysql.cj.jdbc.Driver"
  • 为什么可以这样注册驱动

Class.forName(“com.mysql.cj.jdbc.Driver”);

  • com.mysql.cj.mysql.cj.Driver源码:
    Driver 接口,所有数据库厂商必须实现的接口,表示这是一个驱动类。
public class Driver implements java.sql.Driver {     
	public Driver() throws SQLException {    
	} 
     static {        
      			try {             
      					DriverManager.registerDriver(new Driver());  //注册数据库驱动        
      			 } catch (SQLException var1) {
      			        throw new RuntimeException("Can't register driver!");         
      			  }     
      } 
}

注: 从 JDBC3 开始,目前已经普遍使用的版本。可以不用注册驱动而直接使用。Class.forName 这句话可以省略。

第二节 DriverManager:驱动管理对象
2.1.DriverManager的作用
  1. 管理和注册驱动
  2. 创建数据库的连接
2.2.类中的方法
DriverManager类中的静态方法描述
Connection getConnection(String url,String user,String password)通过连接字符串,用户名,密码来得到数据 库的连接对象
Connection getConnection(String url,Properties info)通过连接字符串,属性对象来得到连接对象
2.3.连接数据库的URL格式:

协议名:子协议://服务器名或 IP 地址:端口号/数据库名?参数=参数值

  • msyql中可以简写:
    前提必须是本地服务器、端口号为3306

jdbc:mysql:///数据库名

2.4.案例:得到MySQL数据库连接对象

1.使用用户名,密码,url得到数据库连接对象

package cn.JDBC; 
import java.sql.Connection; 
import java.sql.DriverManager; 
import java.sql.SQLException; 
/**  
* 得到连接对象
*/ 
public class Demo2 {     
	public static void main(String[] args) throws SQLException {         
		String url = "jdbc:mysql://localhost:3306/day24";         
		// 使用用户名、密码、 URL 得到连接对象
         Connection connection = DriverManager.getConnection(url, "root", "root");              
          System.out.println(connection);     
    } 
}

2.使用url和属性文件得到MySQL连接对象

package cn.JDBC; 
import java.sql.Connection; 
import java.sql.DriverManager; 
import java.sql.SQLException; 
import java.util.Properties; 
 public class Demo3 {     
 		public static void main(String[] args) throws SQLException {         
				//url连接字符串         
				String url = "jdbc:mysql://localhost:3306/day24";         
				//属性对象         
				Properties info = new Properties();         
				//把用户名和密码放在info对象中 
		        info.setProperty("user","root");         
		        info.setProperty("password","root");         
		        Connection connection = DriverManager.getConnection(url, info);         
		        System.out.println(connection);     
 		 } 
}
第三节 Connection接口:数据库连接对象
3.1.Connection的功能:
  • 获取执行SQL的对象
    Statement createStatement();
    PreparedStatement prepareStatement(String sql);
  • 管理事务
    开启事务:setAutoCommit(boolean autoCommit):调用该方法设置参数为false,即开启事务
    提交事务:commit
    回滚事务:rollback
第四节 Statement接口:执行SQL对象
4.1.Statement的作用:

代表一条执行对象,用于发送一条SQL语句给服务器,用于执行静态SQL语句并返回它所生成结果的对象。

4.2.Statement中的方法:
  • int executeUpdate(Srting sql):执行DML(insert、update、delete)语句、DDL(create,alter、drop)语句,返回值为对数据库影响的行数。
  • ResultSet executeQuery(String sql):用于发送 DQL 语句,执行查询的操作(select),返回值为查询的结果集。
4.3 释放资源

4.3.1.需要释放的对象:ResultSet 结果集,Statement 语句,Connection 连接
4.3.2.释放原则:先开的后关,后开的先关。ResultSet > Statement > Connection
4.3.3.放在哪个代码块中:finally 块

4.4.执行DDL操作
4.4.1.需求:使用JDBC在MySQL的数据库中创建一张学生表

在这里插入图片描述

4.4.2.代码
package cn.itcast.JDBC;

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

/**
 * 执行DDL
 * 创建一张表
 */
public class JDBCDemo6 {
    public static void main(String[] args) {
        Statement stmt = null;
        Connection conn = null;
        try {
            //注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            //获取数据库连接对象
            conn = DriverManager.getConnection("jdbc:mysql:///db3?serverTimezone=UTC", "root", "0826");
            //定义执行sql语句
            String sql = "create table student(id int PRIMARY key auto_increment,name varchar(20) not null, gender boolean, birthday date)";
            //获取获取执行sql对象 Statement
            stmt = conn.createStatement();
            //执行sql语句
            int count = stmt.executeUpdate(sql);
            //打印结果
            System.out.println("影响的行数为:"+count);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //关闭资源
            if (stmt != null){
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn != null){
                try {
                    stmt.close();
                }catch (SQLException e){
                    e.printStackTrace();
                }
            }
        }
    }
}
4.5.执行DQL操作
4.5.1.ResultSet接口
  • 作用:封装数据库查询的结果集,对结果集进行遍历,取出每一条记录。
    在这里插入图片描述
4.5.2.代码
package cn.itcast.JDBC;
import java.sql.*;
/**
 * 执行DDL
 * 查询表中的内容
 */
public class JDBCDemo7 {
    public static void main(String[] args) {
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            //注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            //定义sql语句
            String sql = "select * from account";
            //获取连接数据库的对象 Connection
            conn = DriverManager.getConnection("jdbc:mysql:///db3?serverTimezone=UTC", "root", "0826");
            //获取执行sql对象 Statement
            stmt = conn.createStatement();
            //执行sql
            rs = stmt.executeQuery(sql);
            //循环遍历输出结果
            while (rs.next()){
                int id = rs.getInt(1);
                String name = rs.getString(2);
                double balance = rs.getDouble(3);
                System.out.println(id+"---------"+name+"--------"+balance);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //关闭资源
            if (rs != null){
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (stmt != null){
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn != null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
第五节 数据库工具类JDBCUtils
  • 什么时候自己创建工具类?
    如果一个功能经常使用到,我们建议把这个功能做成一个工具类,可以在不同的时候重用。
5.1.需求

上面写的代码中有很多重复的代码,可以把这些公共的代码抽取出来。

5.2.JDBCUtils包含三个方法
  • 可以把几个字符串定义成常量:用户名,密码,URL,驱动类
  • 得到数据库连接:getConnection()
  • 关闭所有打开的资源:close(Connection conn, Statement stmt),close(Connection conn, Statement stmt, ResultSet rs)
5.3.代码

1、配置文件:jdbc.properties

url=jdbc:mysql://localhost:3306/db3?serverTimezone=UTC
user=root
password=0826
driver=com.mysql.cj.jdbc.Driver

2、工具类JDBCUtils.java

package cn.itcast.JDBCUtils;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.sql.*;
import java.util.Properties;
/**
 * JDBC工具类
 */
public class JDBCUtils {
    private static String url;
    private static String root;
    private static String password;
    private static String driver;
    //文件的读取,只要读取一次即可以拿到这些值。用静态代码块
    static {
        try {
            //创建properties集合类
            Properties pro = new Properties();
            //获取src路径下的文件方式---------->ClassLoader 类加载器
            ClassLoader classLoader = JDBCUtils.class.getClassLoader();
            URL res = classLoader.getResource("jdbc.properties");
            //获取path,为相对路径
            String path = res.getPath();
            // System.out.println(path); /C:/IdeaProjects/project01/out/production/JDBC/jdbc.properties
            pro.load(new FileReader(path));
            //获取数据,贬值
            url = pro.getProperty("url");
            root = pro.getProperty("user");
            password = pro.getProperty("password");
            driver = pro.getProperty("driver");
            //注册驱动
            Class.forName(driver);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url, root, password);
    }
    public static void close(Statement stmt, Connection conn){
        if (stmt != null){
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    public static void close(ResultSet rs,Statement stmt,Connection conn){
        if (rs != null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        close(stmt,conn);
    }
}

ClassLoader getClassLoader(): 返回类的类加载器。
url getResource(String name): 找到具有给定名称的资源。

第六节 PrepareStatement接口
6.1.SQL注入问题
  • 当我们输入以下密码,我们发现我们账号和密码都不对竟然登录成功了

请输入用户名:
newboy
请输入密码:
a’ or ‘1’='1 select * from user where name=‘newboy’ and password=‘a’ or ‘1’=‘1’
登录成功,欢迎您:newboy

  • 问题分析:

select * from user where name=‘newboy’ and password=‘a’ or ‘1’=‘1’
name=‘newboy’ and password=‘a’ 为假
‘1’=‘1’ 为真
相当于 select * from user where true; 查询了所有记录

我们让用户输入的密码和 SQL 语句进行字符串拼接。用户输入的内容作为了 SQL 语句语法的一部分,改变了 原有 SQL 真正的意义,以上问题称为 SQL 注入。要解决 SQL 注入就不能让用户输入的密码和我们的 SQL 语句进 行简单的字符串拼接

6.2.继承结构与作用

PrepareStatement是Statement接口的子接口,继承于父类中所用的方法,它是预编译的SQL语句。

6.3.PrepareStatement的执行原理

1.因为有预先编译的功能,提高 SQL 的执行效率。
2.可以有效的防止 SQL 注入的问题,安全性更高。

6.4.使用PreparedStatement的步骤:
  1. 编写 SQL 语句,未知内容使用?占位:“SELECT * FROM user WHERE name=? AND password=?”;
  2. 获得 PreparedStatement 对象
  3. 设置实际参数:setXxx(占位符的位置, 真实的值)
  4. 执行参数化 SQL 语句
  5. 关闭资源
6.5.对比Statement和PrepareStatement
package cn.itcast.JDBC;
import cn.itcast.JDBCUtils.JDBCUtils;
import java.sql.*;
import java.util.Scanner;
/**
 * 		* 需求:
 * 			1. 通过键盘录入用户名和密码
 * 			2. 判断用户是否登录成功
 */
public class JDBCDemo9 {
    public static void main(String[] args) {
        //键盘录入,接收用户名和密码
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String username = sc.nextLine();
        System.out.println("请输入密码:");
        String password = sc.nextLine();
        boolean flag = new JDBCDemo9().login2(username, password);
        if (flag){
            System.out.println("登录成功!");
        }else{
            System.out.println("用户名或密码错误");
        }
    }
    /**
     * 登录方式:使用Statement实现
     */
    public boolean login(String name,String password){
        if (name == null || password == null){
            return false;
        }
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;

        try {
            //获取连接对象connection
            conn = JDBCUtils.getConnection();
            String sql = "select * from user where name = '"+name+"' and password = '"+password+"'";
            System.out.println(sql);
            //创建执行sql语句对象statement
            stmt = conn.createStatement();
            //执行sql
            rs = stmt.executeQuery(sql);
           /* if(rs.next()){
                return true;
            }else{
                return false;
            }*/
           return rs.next();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            JDBCUtils.close(rs,stmt,conn);
        }
        return false;
    }
    /**
     * 登录方式:使用PrepareStatement
     * 解决了sql注入问题,开发中应用
     */
    public boolean login2(String name,String password){
        if (name == null || password == null){
            return false;
        }
        Connection conn = null;
        PreparedStatement prep = null;
        ResultSet rs = null;
        try {
            conn = JDBCUtils.getConnection();
            String sql = "select * from user where name = ? and password = ?";
            //执行sql对象
            prep = conn.prepareStatement(sql);
            //贬值
            prep.setString(1,name);
            prep.setString(2,password);
            rs = prep.executeQuery();
            System.out.println(sql);
            return rs.next();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JDBCUtils.close(rs,prep,conn);
        }

        return false;
    }
}
第七节 JDBC事务的处理

之前我们是使用 MySQL 的命令来操作事务。接下来我们使用 JDBC 来操作银行转账的事务。

7.1.准备数据
CREATE TABLE account (  
	id INT PRIMARY KEY AUTO_INCREMENT,  
	NAME VARCHAR(10),  balance DOUBLE 
); 
-- 添加数据 
INSERT INTO account (NAME, balance) VALUES ('Jack', 1000), ('Rose', 1000);
7.2.开发步骤

1.获取连接
2.开启事务
3.获取到PrepareStatement
4.使用PrepareStatement执行两次更新步骤
5.正常情况下提交事务
6.出现异常回滚事务
7.最后关闭资源

7.2.1.案例代码(已省略工具类JDBCUtils代码)
package cn.itcast.JDBC;
import cn.itcast.JDBCUtils.JDBCUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class JDBCDemo10 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement prep1 = null;
        PreparedStatement prep2 = null;
        try {
            //获取连接
            conn = JDBCUtils.getConnection();
            //开启事务
            conn.setAutoCommit(false); //false关闭自动提交
            //设置sql1为张三减去500
            String sql1 = "update account set balance = balance - ? where id = ?";
            //设置sql2为李四加上500
            String sql2 = "update account set balance = balance + ? where id = ?";
            //创建执行sql对象,PrepareStatement
            prep1 = conn.prepareStatement(sql1);
            prep2 = conn.prepareStatement(sql2);
            //设置参数
            prep1.setInt(1,500);
            prep1.setInt(2,1);
            prep2.setInt(1,500);
            prep2.setInt(2,2);
            //执行 sql 语句
            prep1.executeUpdate();
            //手动制造异常
            //int i = 3/0;
            prep2.executeUpdate();
            //提交事务
            conn.commit();

        } catch (SQLException e) {
            try {
                if (conn !=null){
                    conn.rollback();
                }
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
            e.printStackTrace();
        }finally{
            JDBCUtils.close(prep1,conn);
            JDBCUtils.close(prep2,null);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值