Mysql3jdbc:DriverManager.getConnection(url, user, pwd)

Posted 码农编程录

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mysql3jdbc:DriverManager.getConnection(url, user, pwd)相关的知识,希望对你有一定的参考价值。


1.四个接口:左java.sql包下的DCSR,右com.mysql.jdbc.Driver

在这里插入图片描述
如下jdbc是父类引用。
在这里插入图片描述
如下mchange. .和c3p0. .一起。第一个导入的是mysql-connector…。
在这里插入图片描述
如下代码第一行new Driver()是导入com.mysql.jdbc(用mysql实现好的,就是上面导入的mysql-connector..jar包)而不是java.sql(自己不会重写抽象方法)下,参数是接口类型需要传入接口的实现类对象即new Driver()。

registerDriver相当于set方法,get获取的是mysql.Driver.connect方法返回的Connection类即com.mysql.jdbc.JDBC4Connection(有mysql.的都是导入的jar包)。
在这里插入图片描述
在这里插入图片描述

package com.itheima01.jdbc;
import com.mysql.jdbc.Driver;
import java.sql.*;

public class JdbcDemo { 
    public static void main(String[] args) throws SQLException, ClassNotFoundException, IllegalAccessException, InstantiationException {
        //1. 注册驱动 (注意: 导入的mysql的驱动)
        /*
        *   A. 查看mysql.Driver源码: 点new Driver()中Driver看源码
        *       发现static 代码块里 已经注册了驱动 -> 驱动自注册 相当于set一次就行
        *       带来问题: 外部的注册没有意义(重复注册)
        * 
        *       解决: 保证mysql.Driver类被加载(静态代码块就会执行),如下两种方案:
        *          1. 创建对象
        *          2. 反射:a. 节省内存
        *                  b. 跟驱动包的关联只剩一个字符串:"com.mysql.jdbc.Driver"
        *          待会将字符串写入配置文件,只要改配置文件就行 就会跟 mysql驱动包的彻底解耦 
        */

//111111111111111111111111111111111111111111111111111111111111111111111111111111111111
// DriverManager.registerDriver(new Driver()); //这行重复注册,下行new了就会加载源码里的静态代码块,所以这行=下行

//new Driver(); // Class对象 + 普通实例 //只要用了这个类,这个类就会被加载内存中方法区 //自动导包
        // new Driver()的内存消耗等价于下面两行: 其实只需要calss对象,不需要实例                  
		// Class<?> clazz = Class.forName("com.mysql.jdbc.Driver"); //获取这个类的class对象
		// Object obj = clazz.newInstance(); //利用class对象调用其空参构造来创建一个实例

        Class.forName("com.mysql.jdbc.Driver"); //Class对象,没有普通实例,因为普通实例没有意义 //用反射,com.mysql.jdbc.Driver这个类也会被加载

//111111111111111111111111111111111111111111111111111111111111111111111111111111111111
		 //2. 获取连接
        /*
        *   只要涉及两个软件通信 : 网络三要素(必要非充分:一定要,但是有它们三不一定够如多了资源位置)
        *       1. 协议 :       jdbc:mysql  (主协议:子协议)
        *       2. ip :         数据库所在的计算机(自己:localhost或127.0.0.1)
        *       3. port :       mysql数据库3306
        *       资源位置:   数据仓库的名称
        *       
        *       协议://ip:port/资源位置
        *       https://www.baidu.com:443
        */
//        String url = "jdbc:mysql://localhost:3306/day03";  //day03是数据库
        String url = "jdbc:mysql:///day03"; //ip:localhost port:3306 可以省略
        String user = "root";
        String pwd = "1234";
        Connection conn = DriverManager.getConnection(url, user, pwd);
        System.out.println("conn:" + conn); //引用类型打印地址
        
//1111111111111111111111111111111111111111111111111111111111111111111111111111111111
		 //3. 创建执行sql的语句对象
        /*
        * Connection 接口的一些方法
        *   <1>. Statement createStatement();   创建执行sql的语句对象,相当于创建一个流
        *   <2>. PreparedStatement prepareStatement(sql); 创建一个预编译sql的语句对象
        *   <3>. 事务操作相关
        */
        Statement statement = conn.createStatement();
        System.out.println("statement:" + statement);
        
//11111111111111111111111111111111111111111111111111111111111111111111111111111111111
		  //4. 执行sql,返回结果
		 /*
        * Statetment 接口的api
        *   1. ResultSet statement.executeQuery(sql);
        *           执行的查询语句 : DQL
        *           返回的查询结果: 结果集
        * 
        *   2. int executeUpdate(sql) :
        *           执行的增删改语句: DML
        *           返回的结果: 被影响的行数
        * 
        *   3. boolean execute(sql);  -> 不需要掌握,知道即可
        *               万能 :  DDL等 如create成功或失败是和异常相关,和返回值无关
        *               返回值: 非查询语句返回false,查询语句返回true
        */
        String sql = "select * from emp";
        ResultSet resultSet = statement.executeQuery(sql);
        
//11111111111111111111111111111111111111111111111111111111111111111111111111111111111 
		//5. 处理结果
        while(resultSet.next()){
            String name = resultSet.getString("name");            
// String id = resultSet.getString("id"); //也可以,java程序以外的所有数据对java来说都是字符串
            int id = resultSet.getInt("id"); //底层先调用getString再parse int
            System.out.println(id+ ":" + name);
        }
 
//11111111111111111111111111111111111111111111111111111111111111111111111111111111111
		 //6. 释放资源
        resultSet.close();
        statement.close();
        conn.close();
    }
}

在这里插入图片描述
resultset不是返回一行数据,而是带有id=…。因为返回一行数据如 11孙悟空男,不知道怎么解析。
在这里插入图片描述
在这里插入图片描述

2.释放资源:finally

package com.itheima04.release;
import com.itheima05.utils.JdbcUtil;
import java.io.Closeable;
import java.io.IOException;
import java.sql.*;

public class ReleaseDemo {
    public static void main(String[] args)  {
        ResultSet resultSet = null;
        Statement statement = null;
        Connection conn = null;
        try {
            /*Class.forName("com.mysql.jdbc.Driver");
            String url = "jdbc:mysql://localhost:3306/day03";
            String user = "root";
            String pwd = "1234";
            conn = DriverManager.getConnection(url, user, pwd);*/
            
            conn = JdbcUtil.getConnection(); //查询要获取连接,getConnection方法调用多遍,所以getConnection方法不写try catch,查询提示 查询失败,删除提示 删除失败,封装时不知道是查询还是删除,不好提示,所以往外抛。
            conn = JdbcUtil.getConnection(); //增删改也要获取连接

//111111111111111111111111111111111111111111111111111111111111111111111111            
            statement = conn.createStatement();
            String sql = "select * from emp"; 
                                   
            resultSet = statement.executeQuery(sql);            
            while(resultSet.next()){
                String name = resultSet.getString("name");
                System.out.println(name);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally{
           /* if(resultSet != null){
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(statement != null){
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(conn != null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }*/
            
		   // closeIo(resultSet,statement,conn);
            JdbcUtil.release(conn,statement,resultSet);
        }
    }

//1111111111111111111111111111111111111111111111111111111111111111111111
    private static void closeIo(AutoCloseable... ios) { //AutoCloseable接口位于java.lang包下,不用导包
        for (AutoCloseable io : ios) {
            if(io != null){
                try {
                    io.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

3.工具类封装:new Properties()

package com.itheima05.utils;
import java.sql.*;
/**
*   工具类:
*       0. 拥有很多 工具方法(重复的代码封装) 的类
*           命名规范: utils 包 -> xxUtil 类 (xx : 某个模块的名称)
*           Objects,Arrays,Collections...(JDK提供的)
* 
*       1. 一般工具类中方法是静态的,不用实例化,节省内存
* 
*       2. 封装方法的步骤
*           1. 先把要把封装的代码写出来
*           2. 观察不断重复的部分
*           3. 定义方法,然后直接复制过来
*           4. 设置参数和返回值
* 
*       注意点:
*           1. 扩展性 : 不要导入mysql包中的类, 要导入java包中的类(因为换成oracle也可用)
*           2. 工具类中的异常一般是往外抛 : 一般异常是要在业务中处理
*/
public class JdbcUtil {
    static{
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

//1111111111111111111111111111111111111111111111111111111111111111111111111111111
    public static Connection getConnection() throws SQLException {
        //此方法会被多次调用,注册驱动只需要一次 -> 所以用静态代码块 如上
//        Class.forName("com.mysql.jdbc.Driver");
        String url = "jdbc:mysql://localhost:3306/day03";
        String user = "root";
        String pwd = "1234";
        Connection conn = DriverManager.getConnection(url, user, pwd);
        return conn;
    }
    
//1111111111111111111111111111111111111111111111111111111111111111111111111111111
    /**
     * 文档注释:
     *    a. 写在类上面 : 描述类的用途
     *    b. 写在方法上面 : 描述方法的用途 (返回值,参数)
     */
   public static void release(Connection conn, Statement statement, ResultSet resultSet){
   	   //java.sql.Connection
       if(resultSet != null){
           try {
               resultSet.close();
           } catch (SQLException e) {
               e.printStackTrace();
           }
       }
       if(statement != null){
           try {
               statement.close();
           } catch (SQLException e) {
               e.printStackTrace();
           }
       }
       if(conn != null){
           try {
               conn.close();
           } catch (SQLException e) {
               e.printStackTrace();
           }
       }
   }
}

如下改进上面工具类。

/*
*   问题: 驱动,url,用户名和密码等信息 是有可能会变的, 变动频率比较低
*       1. 如果不变,直接写死在代码中
*       2. 变,但是频率高 : 一般设置成参数
*       3. 变,但是频率不高: 放在配置文件
*           1. 解耦 : 信息要改变的话,只要改配置文件,代码不用改,程序不需要重新编译和部署
*           2. 代码简化 : 无需调用的时候传参了
*/
//jdbc.properties文件,每个月改一次 //文件里没有关键字,也没有双引号,本来就是字符串
driverName = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/day03
user = root
pwd = 1234
package com.itheima05.utils;
import java.io.FileInputStream;
import java.sql.*;
import java.util.Properties;

public class JdbcUtil02 {
    static String driverName;
    static String url;
    static String user;
    static String pwd;
    static{
        try {
            Properties p = new Properties();
            p.load(new FileInputStream("src/jdbc.properties"));
                        
            driverName = p.getProperty("driverName");
            url = p.getProperty("url");
            user = p.getProperty("user");
            pwd = p.getProperty("pwd");
            
            Class.forName(driverName);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

//1111111111111111111111111111111111111111111111111111111111111111111111111111111111
    public static Connection getConnection() throws SQLException {
        Connection conn = DriverManager.getConnection(url, user, pwd);
        return conn;
    }

//11111111111111111111111111111111111111111111111111111111111111111111111111111111111 
   public static void release(Connection conn, Statement statement, ResultSet resultSet){
       if(resultSet != null){
           try {
               resultSet.close();
           } catch (SQLException e) {
               e.printStackTrace();
           }
       }
       if(statement != null){
           try {
               statement.close();
           } catch (SQLException e) {
               e.printStackTrace();
           }
       }
       if(conn != null){
           try {
               conn.close();
           } catch (SQLException e) {
               e.printStackTrace();
           }
       }
   }
}

4.总结: SPI (Service Provider Interface), API (Application Programming Interface)

JDBC是java的数据库连接规范,里面有两个重要的接口:Driver接口定义了一个connect方法,也就是说你通过一个第三方数据库的Driver,运行它的connect方法(输入连接的字符串)就能得到一个Connection类型的对象。

Connection本身也是一个接口,Connection中定义了许多具体的执行sql方法,也就是我们真正操作数据库最核心的接口类就是Connection接口。它的方式就是各家的数据库分别去实现一系列JDBC定义的接口中的方法。
在这里插入图片描述
如下是接口的开发模式即没有涉及到打破双亲委派和SPI,是jdbc早期的开发方式。
在这里插入图片描述
如下.getConnection方法中有registerDriver(通过类加载器),还是要实体的数据库jar包,但不需要程序import。
在这里插入图片描述
如下SPI配置:文件名就是需要实现的接口的全限定名即java.sql.Driver 。第一个java.sql.Driver文件里写的是org.h3.Driver(org.h3.Driver这个类实现java.sql.Driver接口),第二个java.sql.Driver写的是com.mysql.cg.jdbc.Driver。
在这里插入图片描述
打破双亲类加载机制:DriverManager是jdk自带的类,DriverManager类使用的是bootstrap引用类加载器,数据库是用户类用bootstrap加载不合适,所以DriverManager去加载h2的Driver需要把当前引用类加载器替换为当前系统或当前线程的应用app类加载器
在这里插入图片描述

以上是关于Mysql3jdbc:DriverManager.getConnection(url, user, pwd)的主要内容,如果未能解决你的问题,请参考以下文章

DriverManager

UnsupportedOperationException 与 Android 上的 DriverManager.getConnection()

使用 DriverManager 注册 JDBC 驱动程序都有哪些不同的方法

javaWeb_JDBC_DriverManager接口

JDBC-DriverManager细节

ServiceLoader和DriverManager的前世今生