IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 你真的会JDBC吗? -> 正文阅读

[Java知识库]你真的会JDBC吗?

市面上很多人建议都是简单的学习jdbc,因为后面都会使用mybatis相关框架进行封装。虽然确实在实际开发中很少小关于jdbc的代码。但是对于一个代码热爱者来说,我们还是有必要进一步学习jdbc,首先在学习mybatis、spring等框架源码时,我们必不可少地会接触到jdbc的源码;再者,我们可以在jdbc中学习到很多知识和思维:工厂模式、装饰者模式、反射、集合框架等。

首先我们来看看本文章的思维导图:

JDBC
JDBC概述
JDBC 环境依赖相关以及快速案例
依赖引入
数据库搭建
JDBC里面各种API详解
Driver
DriverManger
Connection
PreparedStatment and Statement
ResultSet
ResultSetMetaData
JDBC 自定义封装工具类及方法
getConnction
close
update
select
JDBC事务相关
JDBC连接池
DBUtils工具类介绍及源码分析

一.JDBC概述

  • JDBC是java中的一个接口,各种数据库如mysql、sqlserver等数据都需要实现这个接口,才能够使得java能够使用相关产品的数据库,如果哪一个数据库不提供相关的JDBC实现类,就会被“踢出”java生态。
  • JDBC的目标是使Java程序员使用JDBC可以连接任何提供了JDBC驱动程序的数据库系统,这样就使得程序员无需对特定的数据库系统的特点有过多的了解,从而大大简化和加快了开发过程。
  • 目前我们使用的框架如mybatis其底层就是使用的JDBC写的,所以我们现在学习JDBC也是为了以后学习mybatis源码打好基础。(当然像反射中的动态代理、设计模式等同样很重要)

能看到本文章的可能都会对JDBC有一定的了解,接下来我们直接进入正题吧!

二.JDBC 环境依赖相关以及快速案例

1.依赖引入:

这里我们使用maven来管理项目:

<dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.25</version>
</dependency>

2.数据库环境介绍:

这里我们使用mysql数据库,并建立一张表供我们后续操作持续使用:
我们建立一个学生表
在这里插入图片描述

下面是建立表和插入的测试数据,

/*Table structure for table `student` */

DROP TABLE IF EXISTS `student`;

CREATE TABLE `student` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(225) NOT NULL,
  `age` int DEFAULT NULL,
  `sex` varchar(225) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=102 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

/*Data for the table `student` */

insert  into `student`(`id`,`username`,`age`,`sex`) values (1,'以某',22,'男'),(2,'小二',19,'男'),(3,'张三',12,'男'),(4,'李四',12,'男'),(5,'王五',22,'男');

3.快速使用JDBC

 @Test
    public  void demo1() throws SQLException {
        Driver driver = new Driver();    //获取Driver驱动

        //填写数据源相关信息
        String url="jdbc:mysql://localhost:3306/zjdata";
        String user="root";
        String password="12345678";
        DriverManager.registerDriver(driver);

        //获取连接
        Connection connection = DriverManager.getConnection(url, user, password);
        Statement statement = connection.createStatement();
        String sql="delete from student where id="+5;
        statement.execute("delete from student where id=5");

        //关闭连接
        connection.close();

    }

以上通过JDBC实现了数据库中id为5的数据的删除,当然这只是初级的使用,后面还有更高级的用法。

三.JDBC相关API详解

1.Driver类

一个是java.sql包下的Driver抽象类,里面给出了Driver的各种规定方法,各种数据库厂商需要根据此抽象类编写相关的数据库驱动,我们程序员不需要面向该接口进行编程。
另一个则是相关的数据库厂商编写出来的Driver实现类,就拿mysql的驱动包举例:

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()
    }
}

这个类就是mysql方法给我们提供的驱动类,平时我们在写jdbc时,就必须把这个类加载到内存中并注册。在我的快速案例中写的代码是:

 Driver driver = new Driver();
 DriverManager.registerDriver(driver);

首先这个 DriverManager.registerDriver(driver); 我们可以省略不写,同样可以成功,因为在Driver中有static代码块:

static {
        try {
        //static代码块中实现驱动的注册,即当Driver类加载到内存的过程中自动实现了驱动的注册
            java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
            throw new RuntimeException("Can't register driver!");
        }
    }

该静态代码块在加载时就会为我们执行Driver的注册操作。

另外对于new Driver() 其实写其的主要目的是将Driver这个驱动类加载到内存当中,我们在学习反射时,知道常用的三种方式将类加载到内存中:

Driver driver = new Driver();    //获取Driver驱动

Class.forName("com.mysql.jdbc.Driver");

ClassLoader.getSystemClassLoader().loadClass("com.mysql.jdbc.Driver");

上面这三种加载方式中,我们最常用的就是 Class.forName(“com.mysql.jdbc.Driver”); 以后我们加载驱动时就用该代码。

2.DriverManager类

该类主要用于管理驱动的类,我们通过该类调用getConnection()方法来获得相关的数据库连接。当然在我们注册驱动(加载Driver时自动注册)之后、获取连接之前需要获取连接mysql的相关信息,这里的getConnection参数就提示了我们要填写的信息:

@CallerSensitive
    public static Connection getConnection(String url,
        String user, String password) throws SQLException {
        java.util.Properties info = new java.util.Properties();

        if (user != null) {
            info.put("user", user);
        }
        if (password != null) {
            info.put("password", password);
        }

        return (getConnection(url, info, Reflection.getCallerClass()));
    }

这里需要我们填写的分别是:

  • url:
    填写要连接的数据库地址 jdbc:mysql://localhost:3306/zjdata
    其中jdbc:mysql代表协议字段,localhost:3306代表自己数据库连接地址,这里指的是本机数据库,zjdata是要连接的数据库名称
  • user:数据库登录名
  • password:数据库登录密码

我们将这些参数设置过后,就能正常获得我们的连接对象connection了!!

另外提一下:我们现在写的Driver路径、url、user、password都高度耦合在代码当中,这样其实是非常不好的,我们如果要修改就会很麻烦,所以建议通过properties文件来写这些需要手动输入的东西。
在resource目录下建立jdbc.xml:

url=jdbc:mysql://localhost:3306/zjdata
driverClassName=com.mysql.jdbc.Driver
username=root
password=12345678

在java代码中,我们通过properties类来读取properties文件来加载相关信息:

InputStream resourceAsStream = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
        Properties properties = new Properties();
        properties.load(resourceAsStream);
		//从properties文件中获取信息
        String username = properties.getProperty("username");
        String password = properties.getProperty("password");
        String driverClassName = properties.getProperty("driverClassName");
        String url = properties.getProperty("url");
        
        Class.forName(driverClassName);
        Connection connection = DriverManager.getConnection(url, username, password);

以上通过文件的方式减少了代码耦合性。

3.Connection

该连接对象其实表示的是mysql客户端与mysql服务端的一个连接,通常只有我们只有我们获取了对象后才能真正的使用sql相关语句和事务相关操作。获取该对象主要通过DriverManager获取或者通过数据库连接池对象(后面介绍)来获取

4.statement与PreparedStatement的区别

当我们获取了连接对象后,我们就可以通过connection调用方法来获取statement对象:

  • statement:不支持预编译,只能通过拼串的方式来解决占位问题,例如:
public void insert delete(String id,Statement statement){
	String sql="delete from studen where id="+id;
	statement.execute(sql);
	
}

其中进行了拼串操作,也会有一定的开销。
另外statement也会出现sql注入问题:

public void insert delete(String id,Statement statement){
	String sql="select id,name,age,sex from studen where id="+id;
	statement.execute(sql);
	//本来查询出来的应该是一条数据。但是如果数据库攻击者将id的值设为“1 or id>-100”,
	//这样实际语句就是select id,name,age,sex from studen where id=1 or id>-100,查询出来的就不是一条语句,而是所有语句。其原因就是mysql误将id中的语句or等看成了关键字,从而引起了sql注入问题。
}

所以在我们平时的开发中,不会使用statement二而是使用preparedStatement,其采用了预编译的机制,可以有效解决预编译的问题:

//通过连接对象connection获取预编译对象preparedStatement对象:
PreparedStatement ps=connection.prepareStatement("delete from student where id=?");
//sql字符串语句中,占位通过?进行占位操作
ps.setObject(1,3);  //设置sql语句中?的值,最小从1开始,这里我们删除id为3的学生。

//执行:
boolean flag= ps.excute();   

上面我们看到了PreparedStatement的两个方法:

  • setObject(int parameterIndex, Object x) 用于设置占位符的值
  • excute() 执行预编译的语句,返回true则表示使用select返回了结果集,返回false则表示返回了影响行数。

接下来我们详细介绍更改数据库和查询数据库的具体操作以及相关Api:

3.1 更改操作

更改操作包括增删改:
我们调用预编译对象的excuteupdate()方法来返回影响行数。

int i=ps.excuteupde()  //返回更新的影响的行数。

3.2 查询语句

其实更改操作都是比较简单的,下面介绍一下相对较为复杂的查询语句:
调用预编译对象的excuteQuery() 方法,返回的结果集 ResultSet:

ResultSet resultSet = preparedStatement.executeQuery();

这个结果集对象可能包含了多行数据,我们怎么在java中通过ResultSet获取所有的查询信息呢?
首先我们要创建一个实体类对象来接受我们要查询的数据:

//		创建一个列表用于存储查询到的实体集
 		List<Student> list=new ArrayList<Student>();
//      创建一个元数据对象,该元数据对象可以获取查询出来结果的列的数量,列的名称,列的别名等,列的数据类型等
        ResultSetMetaData metaData = resultSet.getMetaData();
//     获取有多少列
        int len=metaData.getColumnCount();
        while(resultSet.next()){
            Student student = new Student();
            for (int i = 0; i < len; i++) {
                Object object = resultSet.getObject(i + 1);
                //获取列别名,没有别名就列原名
                String columnLabel = metaData.getColumnLabel(i + 1);
                
//                使用反射
                Field declaredField = student.getClass().getDeclaredField(columnLabel);
                declaredField.setAccessible(true);
                declaredField.set(student,object);
                list.add(student);
            }
        }

上面代码的思路就是首先由一个实体类Student来接受数据(注意该实体类必须对象表的各个字段类型和名称要相等),之后通过结果集获得元数据对象metadata,该对象主要是封装了返回数据的各个字段信息,包括列名、列数量等,我们获取了列名后,就可以结果集获取相应的列的数据,然后通过反射机制,强制修改student对象中的属性(即赋值),这样循环下去,我们就可以获取多个对象对应的多个数据!

5.ResultSet

6.ResultSetMetaData

四.JDBC 自定义封装工具类及方法

----------------------------分割线-------------------------------------------------------------
2021/12/16 剩下文章后续继续更新,后面我们将自己建立一个工具类来封装之前的代码,增加可用性

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-12-18 15:50:19  更:2021-12-18 15:52:09 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/13 8:56:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码