JDBC回顾

JDBC介绍

百度百科:Java数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。

个人理解:
没有JDBC:因为各个数据库软件都是自成体系,对外提供服务时没有统一标准,不像http接口,因为http协议的存在及约束,对接一个新接口非常方便。且数据库连接本身也非常复杂,当我们需要连接不同数据库时,自己手写连接不现实,使用数据库厂商提供的工具连接自然可以,但开发限制较大,不同数据库的连接,执行,结果集处理均不能保证一致,应用切换数据库代价更是无比巨大,可能换一个数据库,数据库连接查询及结果处理的代码全部需要重写,bug也会更多。
JDBC意义:JAVA提供统一的数据库访问API,仅仅是一套标准,一系列规范化的操作。且不提供具体实现,而是不同数据库开发商根据jdbc标准提供具体实现,如何实现不需要开发者关心。这样可以做到,对数据库的连接,执行,结果集处理使用同一套规范与标准,提高开发效率与容错率,降低开发难度及与数据库的耦合度。

JDBC使用与测试

造数据

建表

CREATE TABLE `t_test`(
  `id` BIGINT(20) NOT NULL AUTO_INCREMENT,
  `code` VARCHAR(32) DEFAULT NULL COMMENT '编码',
  `name` VARCHAR(64) DEFAULT NULL COMMENT '名称',
  PRIMARY KEY (`id`)
)

插入数据
INSERT INTO t_test(CODE, NAME) VALUES(‘ZS’,‘张三’), (‘LS’,‘李四’), (‘ZL’,‘张龙’), (‘ZH’,‘赵虎’);

查询
在这里插入图片描述

示例代码

public class MainTest {

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

		// 2.创建连接
        Connection mysqlConnection = DriverManager.getConnection(
                "jdbc:mysql://host:port/dbName",
                "username ",
                "password"
        );

		// 3.创建statement,用于执行静态sql
        Statement statement = mysqlConnection.createStatement();

		// 4.执行查询sql,会返回结果集
        String sql = "select * from t_test;";
        ResultSet resultSet = statement.executeQuery(sql);

		// 5.读取结果集
        while (resultSet.next()) {
            System.out.println(resultSet.getString("code")+" : "+resultSet.getString("name"));
        }
    }
}

解读

上述使用jdbc执行一个查询并处理返回值共分五步:

  1. 加载驱动
  2. 创建连接
  3. 创建statement,用于执行静态sql
  4. 执行查询sql,会返回结果集
  5. 读取结果集

为何要加载驱动

Class.forName(“com.mysql.cj.jdbc.Driver”);
这一步根据字面意思,使用Class类,去加载名为“com.mysql.cj.jdbc.Driver”的类,即加载mysql的驱动。乍一看简直是一脸懵逼,这句代码就能加载驱动了?而且为什么要加载驱动?没这么写过代码呀!

试着慢慢分析吧,首先Class.forName !
Java class在没有被需要用到时,是不会被加载到JVM内存中。当我们new一个从没用过的类时,JVM首先会去找这个类有么有在内存中,没有的话会先去加载这个类,然后
com.mysql.cj.jdbc.Driver源码:

package com.mysql.cj.jdbc;
import java.sql.SQLException;
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    //
    // Register ourselves with the DriverManager
    //
    static {
        try {
            java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
            throw new RuntimeException("Can't register driver!");
        }
    }

    /**
     * Construct a new driver and register it with DriverManager
     * 
     * @throws SQLException
     *             if a database error occurs.
     */
    public Driver() throws SQLException {
        // Required for Class.forName().newInstance()
    }
}

static代码块会在类被加载时执行,其他也没了,而static中就一句代码java.sql.DriverManager.registerDriver(new Driver());

注册了一个实现java.sql.Driver的mysql驱动,即把mysql厂商提供的驱动注册到了驱动管理器中,具体作用肯定是供后续使用,这里暂时无法明确用途。

创建连接

Connection mysqlConnection = DriverManager.getConnection(
                "jdbc:mysql://host:port/dbName",
                "username ",
                "password"
        );

创建连接阶段会根据提供的数据库信息进行数据库连接创建,这一步就需要连接具体的mysql数据库了,除了用户名、密码、数据库地址信息,似乎没有看到如何告诉jvm需要连mysql还是oracle或者其他数据库,url中倒是有mysql字样,难道用的这个连的?

先看下创建连接的代码:

//  Worker method called by the public getConnection() methods.
private static Connection getConnection(
    String url, java.util.Properties info, Class<?> caller) throws SQLException {
    /*
     * When callerCl is null, we should check the application's
     * (which is invoking this class indirectly)
     * classloader, so that the JDBC driver class outside rt.jar
     * can be loaded from here.
     */
    ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
    synchronized(DriverManager.class) {
        // synchronize loading of the correct classloader.
        if (callerCL == null) {
            callerCL = Thread.currentThread().getContextClassLoader();
        }
    }

    if(url == null) {
        throw new SQLException("The url cannot be null", "08001");
    }

    println("DriverManager.getConnection(\"" + url + "\")");

    // Walk through the loaded registeredDrivers attempting to make a connection.
    // Remember the first exception that gets raised so we can reraise it.
    SQLException reason = null;

    for(DriverInfo aDriver : registeredDrivers) {
        // If the caller does not have permission to load the driver then
        // skip it.
        if(isDriverAllowed(aDriver.driver, callerCL)) {
            try {
                println("    trying " + aDriver.driver.getClass().getName());
                Connection con = aDriver.driver.connect(url, info);
                if (con != null) {
                    // Success!
                    println("getConnection returning " + aDriver.driver.getClass().getName());
                    return (con);
                }
            } catch (SQLException ex) {
                if (reason == null) {
                    reason = ex;
                }
            }

        } else {
            println("    skipping: " + aDriver.getClass().getName());
        }

    }

    // if we got here nobody could connect.
    if (reason != null)    {
        println("getConnection failed: " + reason);
        throw reason;
    }

    println("getConnection: no suitable driver found for "+ url);
    throw new SQLException("No suitable driver found for "+ url, "08001");
}

Connection con = aDriver.driver.connect(url, info);

这里可以看到,遍历已注册的驱动,挨个调用驱动创建连接,这里java只提供了接口,即Driver.connect.并没有提供具体实现,而是各个数据库厂商自己提供实现,提供如何去连接他们的数据库,返回一个可用的连接。

而这个驱动注册就是第一步加载驱动的意义:需要主动把厂商的驱动注册到jdbc的驱动管理器中,这样用户创建数据库连接时,jdbc的驱动管理器就使用已注册的驱动去创建对应数据库的连接。

如果项目中同时连接多种数据库,如果区分需要连哪个呢?
Jdbc不做决策,而是遍历所有驱动,挨个去创建连接,谁先创建成功了,就返回谁的连接。

注意

当前jdbc已经不需要手动加载驱动了,新的驱动管理器的静态代码块中已经自动进行了驱动加载。

public class DriverManager {static {
    loadInitialDrivers();
    println("JDBC DriverManager initialized");
}}

方式为遍历寻找所有java.sql.Driver接口的实现类,然后挨个执行Class.forName(XXX);

增删改查

private static void test_query() throws Exception {
	String sql = "select * from t_test;";
	ResultSet resultSet = statement.executeQuery(sql);

	while (resultSet.next()) {
		System.out.println(resultSet.getString("code")+" : "+resultSet.getString("name"));
	}
}

private static void test_insert() throws Exception {
	String sql = "INSERT INTO t_test(CODE, NAME) VALUES('ZS','张三'), ('LS','李四'), ('ZL','张龙'), ('ZH','赵虎');";
	boolean result = statement.execute(sql);
	System.out.println(result);
}

private static void test_update() throws Exception {
	transaction(false);
	String sql = "UPDATE t_test set name='张66' where code='ZS'";
	boolean result = statement.execute(sql);
	System.out.println(result);
	commit();
}

private static void test_delete() throws Exception {
	String sql = "DELETE FROM t_test WHERE code IN ('ZS', 'LS', 'ZL', 'ZH');";
	boolean result = statement.execute(sql);
	System.out.println(result);
}

事务控制

事务控制在connection层,默认是自动提交的,如果需要进行事务控制及业务回滚,需要将自动提交事务设置为false,然后可以在发生异常或者业务错误的情况下手动执行rollback回滚事务,或者在执行完成后手动执行commit提交事务。

// 将自动提交事务设置为false
mysqlConnection.setAutoCommit(false);

try{
	// do something
} catch (SQLException e) {
	e.printStackTrace();
	//手动执行rollback回滚事务
	mysqlConnection.rollback();
}

//手动执行commit提交事务
mysqlConnection.commit();

后续待补充

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值