JDBC连接数据库 --- JDBC编程6步【Java】

JDBC初步学习笔记

内容导航

  • JDBC java database connectivity
    • JDBC介绍
    • JDBC环境配置
    • JDBC编程6步
      • 注册驱动
      • 获取数据库连接
      • 获取数据库操作对象
      • 执行SQL语句 execute
      • 处理查询结果集
      • 资源释放
    • 编程实现

Java养成计划77天


jdbc连接数据库


现在先将表面的知识学习完成之后,才会进一步来深入学习,比如计组,JDK源码,计网,数据库原理;现在的初期目标是能够熟练操作java相关,初步完成一个完整简单的项目;包括数据库表,java编程;涉猎一下web编程;全栈操作,重在后端

昨天已经完成数据库表的学习,包括索引和视图,当然非常浅显,但是目的是为了拓宽知识面,先能够熟练的运用,运用熟练之后学习底层应该会容易一些

JDBC java database connectivity

学习数据库的目的就是为了更好的管理数据,管理数据的目的是为了让应用得到更好的实现,那么既已经初步学习了数据库,接下来就应该是考虑数据库如何在程序中使用,java中要使用数据库,就离不开JDBC,那么什么是JDBC呢?

JDBC介绍

想到jdbc,就会想到很多缩略词比如CRUD,ACID,这些都是对应的英语单词取首字母形成的,这里的JDBC就是java dababase connectivity java数据库连接工具 ;

  • JDBC本质 : 是SUN公司制定的一套接口【interface】 接口按照之前的知识分为调用者和实现者;面向接口调用、面向接口写实现类;适配器,抽象类;

面向接口编程的目的 :解耦合,提高程序的可扩展性 主要是理解什么是耦合,耦合就是模块间的关联程度,关联程度越高,那么耦合度越高;比如new 对象的时候,对象不存在,编译出错,无法运行,这个时候就是耦合度提高的;还有比如实现图书的格式多种html,xml之类;设计的时候不能放在一个类中,这样修改的时候会很麻烦,耦合度太高,实际上各种格式之间的耦合度应该很低,这个时候就使用strategy pattern,面向接口编程来降低耦合,俗称解耦

面向具体编程,会导致程序过僵,耦合度太高,扩展性很低 【所以面向接口编程】

  • SUN指定了一套JDBC接口,这时因为每一个数据库的地城实现原理都不一样,Oracle,MySQL等各个数据库的底层原理都不一样,每一个数据库产品都有自己独特的实现原理 -------- 各个数据库厂家都去实现JDBC接口的实现类,就是一套.class文件;

    而Programmer就是面向JDBC一套接口,我们可以进入JAVA 的帮助文档中,可以发现一java.sql包中的接口就有一个connection接口,这个接口就是连接数据库的超级接口,各个数据库都对其进行了实现

而MySQL对其的实现就是可以看到几个.class文件,包括Driver.class;SocketFactory.class,SocketFactorWrapper.class等Java文件; 各个数据库对于jdbc的实现称为驱动driver,比如我下载的就是MySQL驱动

  • 驱动: 所有的数据库的驱动都是以jar包的形式存在,jar包中有很多.class文件,这些.class文件就是对JDBC接口的实现

驱动不是SUN公司提供,而是各个数据库厂家去下载jar包才可以

关于数据库的模拟可以看一下之前的博客,之前分享反射的时候就是以数据库迁移来分享的,这里使用了配置文件properties文件,创建文件,利用class类的forname方法获取类的对象,之后创建实例,利用newInstance方法创建对象,这里使用上转型就可以了,上转型可以强转或者不转;下转型使用instanceof判断之后再强制类型转换;

当然除了Properties类,也可以使用ResourceBundle 绑定类来获取文件中的数据

JDBC环境配置

jdbc的.class文件都是从网上下载的,这些文件没有在java bin中,所以需要配置classpath变量

classpath没有配置文件的情况下,默认从当前路径下加载class,calsspath如果配置死了,比如 classpath = D:\abc ,则表示只从abc下找class;但是我们自己写的class也要进行类加载,之前运行java程序的时候就是在当前路径下,因为指明了.java文件,路径明了;

那么路径就要配置为.:\…… .代表的当前路径下 ;代表的是该变量的另外一种值

jar包不需要解压,类加载器可以自动找到文件

JDBC编程6步

  1. 注册驱动 : 通知java程序即将连接那种数据库
  2. 获取数据库连接 : java和mysql进程之间的连接通道开启了
  3. 获取数据库操作对象 :数据库操作对象可以执行SQL语句
  4. 执行SQL语句 : 执行CRUD语句
  5. 处理查询结果集 : 如果第四步是SELECT语句,才有第五步
  6. 释放资源 : jdbc是进程之间的通信,需要关闭以减少资源的耗费

注册驱动

驱动在数据库方面就是Driver,那么注册驱动就是告诉Java程序需要连接的是哪个品牌的数据库;

上面提到SUN公司提供了一套接口JDBC,当然就有接口和相关的类负责驱动注册了

在java程序中,分管sql的是java.sql包,该包中有一个类为Driver

  • Driver : 每一各驱动程序都必须要实现的接口,java SQL允许多种数据库,DriverManager会试着尽可能多加载可以找到的驱动程序,依次尝试连接URL : 简单一点,这个接口就是为了方便导入各种不同的数据库驱动 com.mysql.jdbc.Driver是mysql数据库实现Driver接口
  • DriverManager :驱动的注册使用到java.sql包中的DriverManager类 : 该类的作用就是管理一组JDBC驱动,应用程序不再需要使用 Class.forName() 显式地加载 JDBC 驱动程序。当前使用 Class.forName() 加载 JDBC 驱动程序的现有程序将在不作修改的情况下继续工作

需要注意的是加载驱动不是在com.mysql.jdbc.Driver下了,而是在com.mysql.cj.jdbc.Driver,还要注意修改时间

java中因为各个数据库公司实现了SUN公司提供的接口,但是名称是一样的,这个时候就不能两边都省略了,因为JVM是识别不了到底谁是谁,这个时候一个导入import,另外一个直接加上包名就可以不用导入了

一般注册驱动就两步

  1. 创建一个具体的Driver对象
  2. 利用DriverManager的类方法registerDriver 注册给定的驱动 ,利用Manager管理 【会抛出SQLException,因为数据库可能连接失败】
Driver  driver = new com.mysql.jdbc.Driver();
//Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
DriverManager.registerDriver(driver);

获取数据库连接

上面第一步注册驱动只是引入Mysql驱动程序 ---- 可以允许mysql数据库了,但是还没有获取到mysql中的数据库,那么接下来还是要使用DriverManager中的类方法getConnections ---- 都会抛SQLException,这种方法重载了,因为可以使用配置文件来书写密码和用户,还可以直接写密码和用户【String】 String – URL

建立到给定数据库URL(uniform resource locator统一资源定位符)的连接,DriverManager则从已经注册的驱动程序中选择一个合适的【因为是一组不是一个】

  • getConnections(String url,String user, String password) throws SQLException 【返回的Connection对象】 Connection接口和Driver接口一样都是sql包下的,Connection表示的是java程序和数据库之间的连接关系【之前说过可以使用singleton pattern】

这里的user和password就是用户和密码,和mysql中的-u -p 相同,都是String类型的就可

要注意数据库的url的写法:

url之前在计网中介绍过,就不再介绍了,url包括 协议 ip 端口 路径 用户etc protocol分层,垂直service

  • jdbc:mysql:// 这是java和mysql通信的协议 就类似htttps://
  • localhost 本机ip地址 127.0.0.1
  • 端口号 3306
  • cfengtest 数据库名称
  • ?serverTimezone=GMT%2B8 时间【低版本可以不加】

Oracle : oracle:jdbc:thin:@localhost:3306:cfengtest

String user = "cfeng";
			String password = "*********";
			String url = "jdbc:mysql://localhost:3306/cfengtest?serverTimezone=GMT%2B8";
			Connection conn = DriverManager.getConnection(url, user, password);//取得一个数据库连接对象
			System.out.println(conn);


//com.mysql.cj.jdbc.ConnectionImpl@f0c8a99  这里其实可以看出来就是创建一个mysql的连接对象;当然不同的数据库是不同的对象  都是实现的sun的接口Connection

获取数据库操作对象

上面第二步已经获取到了数据库连接对象了,那么要想操作数据库中的数据,必须要有数据库操作对象,数据库操作对象的获取可以使用==Connection接口中的createStatement()方法

该方法可以创建一个statement对象来讲SQL语句发送到数据库

连接对象只是管连接的,可以操作连接状态;Statement【也是sun的一个总接口】对象是在连接的基础上传送语句的

通过一个连接对象Connection是可以创建多个Statement对象的

Statement state = conn.createStatement(); //这里就简单获取一个对象就可以了
System.out.println(state);

//com.mysql.cj.jdbc.StatementImpl@7674f035

执行SQL语句 execute

【execute 执行】

这里要使用Statement中的方法就可以了,比如executeUpdate 语句就是DML语句都可,可以返回int型的修改了多少rows的记录

  • excute(String sql) sql语句也是String类型的
String sql = "INSERT INTO emp (empno,ename) VALUES (15,'ROBIT')";
int count = state.executeUpdate(sql);
System.out.println(count);

//1     代表影响了数据库中的一行记录,可以去数据库中看一下效果

mysql> SELECT * FROM emp;
+-------+--------+-----------+------+------------+---------+---------+--------+
| empno | ename  | job       | mgr  | hiredate   | sal     | comm    | deptno |
+-------+--------+-----------+------+------------+---------+---------+--------+
|    15 | ROBIT  | NULL      | NULL | NULL       |    NULL |    NULL |   NULL |
|  7369 | SMITH  | CLERK     | 7902 | 1980-12-17 |  800.00 |    NULL |     20 |
|  7499 | ALLEN  | SALESMAN  | 7698 | 1981-02-20 | 1600.00 |  300.00 |     30 |
|  7521 | WARD   | SALESMAN  | 7698 | 1981-02-22 | 1250.00 |  500.00 |     30 |
|  7566 | JONES  | MANAGER   | 7839 | 1981-04-02 | 2975.00 |    NULL |     20 |
|  7654 | MARTIN | SALESMAN  | 7698 | 1981-09-28 | 1250.00 | 1400.00 |     30 |
|  7698 | BLANK  | MANAGER   | 7839 | 1981-05-01 | 2850.00 |    NULL |     30 |
|  7782 | CLARK  | MANAGER   | 7839 | 1981-06-09 | 2450.00 |    NULL |     10 |
|  7788 | SCOTT  | ANALYST   | 7566 | 1987-04-19 | 3000.00 |    NULL |     20 |
|  7839 | KING   | PRESIDENT | NULL | 1981-11-17 | 5000.00 |    NULL |     10 |
|  7844 | TURNER | SALESMAN  | 7698 | 1981-09-08 | 1500.00 |    0.00 |     30 |
|  7876 | ADAMS  | CLERK     | 7788 | 1987-05-23 | 1100.00 |    NULL |     20 |
|  7900 | JAMES  | CLERK     | 7698 | 1981-12-03 |  950.00 |    NULL |     30 |
|  7902 | FORD   | ANALYST   | 7566 | 1981-12-03 | 3000.00 |    NULL |     20 |
|  7934 | MILIER | CLERK     | 7782 | 1982-01-23 | 1300.00 |    NULL |     10 |
+-------+--------+-----------+------+------------+---------+---------+--------+

可以看到是成功插入了数据的

再来多实验几次,DELETE语句和UPDATE语句

String sql = "UPDATE emp SET ename = 'Cfeng' WHERE empno = 15";
int count = state.executeUpdate(sql);
System.out.println(count);

//1

mysql> SELECT * FROM emp;
+-------+--------+-----------+------+------------+---------+---------+--------+
| empno | ename  | job       | mgr  | hiredate   | sal     | comm    | deptno |
+-------+--------+-----------+------+------------+---------+---------+--------+
|    15 | Cfeng  | NULL      | NULL | NULL       |    NULL |    NULL |   NULL

再来看一下DELETE

String sql = "DELETE FROM emp WHERE empno = 15";
int count = state.executeUpdate(sql);
System.out.println(count);

//1

mysql> SELECT * FROM emp;
|  7934 | MILIER | CLERK     | 7782 | 1982-01-23 | 1300.00 |    NULL |     10 |
+-------+--------+-----------+------+------------+---------+---------+--------+
14 rows in set (0.01 sec)

可以看到和之前单独使用dos窗口操作时一样的效果,只是要注意SQL语句的正确性

处理查询结果集

当上面的SQL语句为DQL的时候,这个时候就要调用数据库操作对象的executeQuery()方法,这个方法返回的是一个ResultSet对象

  • ResultSet是一个接口,超级接口为Wrapper,表示的是数据库结果集的数据表
    • ResultSet对象有一个光标指向当前数据行,最初光标放置在第一行前面,next方法可以将其移动到下一行,如果没有下一行返回false,所以可以用while迭代结果集
    • ResultSet对象也需要释放,不然会占用资源,但是释放不会关闭创建的blob或者clob对象,需要使用free才会消失
    • 这个对象中存储了查询出的数据,所以要看到数据就是对ResultSet的操作,可以遍历输出,遍历操作,取出数据get
    • 光标指向的是第一行的数据,next移动就是指向的是每一row;----这里就通过这个光标取出该row的第一个数据 JDBC中所有的下标都是从1开始的,通过getString(columindex)方法取得第index位置的数据【不管是什么类型都是以String类型返回
rset = state.executeQuery(sql);
while(rset.next()) {
	String emp = rset.getString(1) + "  " + rset.getString(2) + "  " + rset.getString(3);//上面的SQL语句查询的每一行的记录是3col,所以从1到3
	System.out.println(emp);
}
  • 上面是取出的都是String类型的,其实也可以用特定类型的,比如getInt,getDouble ……
  • 除了根据columindex查询,还可以根据名称查询,注意 : 这里的名称不是表中字段的名字,而是查询结果的名称,如果起别名了就不是了,因为存储的是查询结果那张表的数据,直接getString(“col_name”)字段下标不健壮,因为一旦修改之后,位置可能变化,但是字段名称很少变化

资源释放

因为维护进程通信连接是需要资源的,还有statement也需要维护,所以要释放掉资源不用的时候

这里的释放因为上面的try catch,所以直接在finally中释放,关于finally的考点比如return,exit之类的就不再赘述,因为try形成了语句块,又变量的作用域和生命周期,所以这里变量声明放在try的外面,方便在finnally中释放

  • 那或许会疑惑: 放在里面不是更省事吗?这样就不用再写try catch了

这个问题主要是应对一些其他的情况,finally除了强制关闭jvm都是可以执行的,所以放在finally中或许更好一些

//先关闭ResultSet,关闭state,再关闭connection
 if(state != null) {
			  state.close();
}
  if(conn != null) {
		conn.close();
}

//放在finally中要分别try catch

编程实现

这里已经知道编程6步,那么就要实践一下,看一下如何运用

package test;

import java.sql.*;

public class JdbcTest {
	public static void main(String[] args) {
		//注册驱动
		Connection conn = null;
		Statement state = null;
		ResultSet rset = null;
		try {
			DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
		//获取数据库连接对象
			String url = "jdbc:mysql://localhost:3306/cfengtest?servertimezone=GMT%2B8";
			String user = "cfeng";
			String password = "************";
			conn = DriverManager.getConnection(url, user, password);
		//获取数据库操作对象
			state = conn.createStatement();//直接再连接的基础上来创建对象
		//执行SQL语句
			String sql = "SELECT empno,ename,sal FROM emp LIMIT 5";
			rset = state.executeQuery(sql);
			while(rset.next()) {
				String emp = rset.getString(1) + "  " + rset.getString(2) + "  " + rset.getString(3);//上面的SQL语句查询的每一行的记录是3col,所以从1到3
				System.out.println(emp);
			}
		//获取数据库查询结果集
			
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
		//释放资源
			if(rset != null) {
				try {
					rset.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			if(state != null) {
				try {
					state.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			if(conn != null) {
				try {
					conn.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			}
		}
 
	}
}
}
//建议获取数据使用名称,比下标健壮


/*
7369  SMITH  800.0
7499  ALLEN  1600.0
7521  WARD  1250.0
7566  JONES  2975.0
7654  MARTIN  1250.0
*/

你可能感兴趣的:(数据库养成,mysql,分类,数据库)