一:JDBC 概述

    一、简介

       1. JDBC(Java DataBase Connection,Java 数据库连接)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。

2. JDBC 是一个标准 SQL(Structured Query Language,结构化查询语言)数据库访问接口,可以为多种关系数据库提供统一访问。也提供一种基准,据此可以构建更高级的工具和接口。

3. JDK(Java Development Kit,Java 开发工具包)软件捆绑包括 JDBC 和 JDBC-ODBC(Open DataBase Connection,开放式数据库连接)桥。

          

    二、API

     

二:JDBC 开发步骤

    一、配置依赖 jar 包

1. 下载

1. MySQL

2. Oracle

2. 配置

1. 导入 jar 包

2. Maven 配置

 <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.20</version>
</dependency> <!-- https://mvnrepository.com/artifact/com.oracle.database.jdbc/ojdbc10 -->
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc10</artifactId>
<version>19.3.0.0</version>
</dependency>

    二、注册驱动

 public class DriverTest {
/**
* 通过反射机制,加载数据库驱动,类初始化的时候执行静态代码块
* 优点1:此方式由于参数为字符串,因此很容易修改,移植性强。
* 优点2:不依赖特定的Driver库,很容易改造成从配置文件读取JDBC配置,从而可以在运行时动态更换数据库连接驱动。
*/
static {
try {
/**
* MySQL:8.0版本,5.0版本为:com.mysql.jdbc.Driver
*/
Class.forName("com.mysql.cj.jdbc.Driver"); /**
* Oracle
*/
Class.forName("oracle.jdbc.driver.OracleDriver");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} // 8版本
}
}

    三、获取连接

 public class ConnectionTest {
/**
* MySQL
*/
public Connection getMysqlConnection() {
// 本地连接URL:jdbc:mysql:///student?useUnicode=true&characterEnocding=utf-8&useSSL=false&serverTimezone=UTC
// 远程连接URL:jdbc:mysql://<host>:<port>/<database>?useUnicode=true&characterEnocding=utf-8&useSSL=false&serverTimezone=UTC
final String url = "jdbc:mysql:///student?useUnicode=true&characterEnocding=utf-8&useSSL=false&serverTimezone=UTC";
// 连接用户名
final String user = "root";
// 连接密码
final String password = "000000";
Connection conn = null;
if (conn == null) {
try {
conn = DriverManager.getConnection(url, user, password);
} catch (SQLException e) {
// TODO Auto-generated catch block
System.err.println("Oracle数据库连接出错");
e.printStackTrace();
}
}
return conn;
} /**
* Oracle
*/
public Connection getOracleConnection() {
/**
* 1. 使用thin连接:jdbc:oracle:thin:@<host>:<port>:<database>
* 优点:thin完全由Java代码编写,与平台无关,不需要Oracle客户端。
* 缺点:thin性能一般,达不到如OCI方式的企业级的要求,一般适合一台主机连接。
*
* 2. 使用oci连接:jdbc:oracle:oci:@<host>:<port>:<database>
* 优点:用OCI连接数据库是企业级的做法,适应于单个数据库和集群数据库,性能优越,尤其是连接池功能大大提高了应用程序的性能和并发量。
* 缺点:若想使用OCI必须要安装Oracle客户端。
*/
final String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";
// 连接用户名
final String user = "scott";
// 连接密码
final String password = "tiger";
// 连接对象
Connection conn = null;
if (conn == null) {
try {
conn = DriverManager.getConnection(url, user, password);
} catch (SQLException e) {
// TODO Auto-generated catch block
System.err.println("Oracle数据库连接出错");
e.printStackTrace();
}
}
return conn;
}
}

    四、创建Statement、PreparedStatement、CallableStatement接口,执行SQL语句

 package pers.mj.test;

 import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types; public class MysqJDBClTest {
/**
* Statement 的作用:用于执行静态 SQL 语句并返回它所生成结果的对象,完成对数据库的增删改查。
* Statement 的优点:语法简单,对于只执行一次的 SQL 语句,使用 Statement 比 PreparedStatement 对象的开销更小。
* Statement 的缺点:每次执行时相似SQL都会进行编译 ,采用硬编码效率低,安全性较差,字符串拼接方式的 SQL 语句是非常繁琐的,中间有很多的单引号和双引号的混用,极易出错。
* Statement 的适用场景:普通的不带参的查询SQL
*/
public void testStatement() {
try {
// 获取数据库连接
Connection conn = DBUtil.getMysqlConnection();
// 创建 Statement 对象
Statement st = conn.createStatement();
// 定义SQL语句
String sql = "insert into student(stu_id, stu_name) values(20200626, " + " '张三')"; // 字符串拼接麻烦
/**
* 演示SQL注入问题:如果此时传递给字段的值为:or 1 = 1,那么不论如何条件都成立,导致结果都成功,这就是SQL注入
*/
String SQL = "select * from student where stu_name="+"'张三' and stu_id= "+"'or 1 = 1' ";
// 执行SQL语句
if (st.execute(sql)) {
System.out.println("信息插入成功");
}
} catch (SQLException e) {
System.err.println("插入语句执行失败");
e.printStackTrace();
}
} /**
* PreparedStatement 的作用:用于执行动态 SQL 语句并返回它所生成结果的对象,完成对数据库的增删改查。继承Statement
* PreparedStatement 的优点:相似SQL只编译一次,减少编译次数,代码的可读性和可维护性更高,提高了安全性(阻止了SQL注入)。
* PreparedStatement 的缺点:执行非相似SQL语句时,速度较慢。
* PreparedStatement 的适用场景:支持可变参数的SQL
*/
public void testPreparedStatement() {
try {
// 获取数据库连接
Connection conn = DBUtil.getMysqlConnection();
// 定义SQL语句
String sql = "insert into student(stu_id, stu_name) values(?, ?)";
/**
* 解决SQL注入问题:PreparedStatement不是将参数简单拼凑成sql,而是做了一些预处理,将参数转换为string,两端加单引号,将参数内的一些特殊字符(换行,单双引号,斜杠等)做转义处理,这样就很大限度的避免了sql注入。
*/
String SQL = "select * from student where stu_name=? and stu_id= ? ";
// 预编译SQL语句,防止SQL注入
PreparedStatement ps = conn.prepareStatement(sql);
// 给占位符(?)赋值:索引从1开始,数据类型需要相对应
ps.setInt(1, 20180627);
ps.setString(2, "李四");
// 执行SQL语句
if (ps.execute()) {
System.out.println("信息插入成功");
}
} catch (SQLException e) {
System.err.println("插入语句执行失败");
e.printStackTrace();
}
} /**
* CallableStatement 的作用:实现了存储过程函数调用的方法以及对于输出的处理。继承PreparedStatement
* CallableStatement 的使用场景:支持调用存储过程,提供了对输出和输入/输出参数(INOUT)的支持
*/
public void testCallableStatement(){
try {
// 获取数据库连接
Connection conn = DBUtil.getMysqlConnection();
// 定义SQL语句
String sql = "call p3(?,?)";
// 预编译SQL
CallableStatement cs = conn.prepareCall(sql);
// 给站位符赋值
cs.setString(1, "王五");
cs.registerOutParameter(2, Types.INTEGER); // 注册一个输入参数
// 执行SQL
cs.execute();
// 获取结果集对象
ResultSet resultSet = cs.getResultSet();
while (resultSet.next()) {
System.out.println(resultSet.getString("name")+" ");
}
// 获取输出参数
System.out.println(cs.getInt(2));
} catch (Exception e) {
// TODO: handle exception
}
}
}

    五、execute、executeQuery和executeUpdate详解

 public class ExecuteTest {
// 数据库连接对象
Connection conn = null;
// 预处理对象
PreparedStatement ps = null;
// 结果集对象
ResultSet rs = null; /**
* executeQuery()
* 作用:只能执行DQL(SELECT语句),是使用最多的查询语句。
* 返回值:单个结果及对象(ResultSet)
*/
public void testExecuteQuery() {
try {
// 获取数据库连接
conn = DBUtil.getMysqlConnection();
// 定义SQL语句
String sql = "SELECT stu_id,stu_name FROM student WHERE stu_id=? ";
// 预编译SQL
ps = conn.prepareStatement(sql);
// 给占位符赋值
ps.setInt(1, 20200626);
// 执行SQL语句
rs = ps.executeQuery();
while (rs.next()) {
System.out.println("学号:" + rs.getInt("stu_id") + " 姓名:" + rs.getString("stu_name"));
}
} catch (Exception e) {
// TODO: handle exception
}
} /**
* executeUpdate()
* 作用:执行DML(除去SELECT语句)和DDL,修改表中零行或多行中的一列或多列。
* 返回值:受影响的行数(整数)
*/
@Test
public void testExecuteUpdate() {
try {
// 获取数据库连接
conn = DBUtil.getMysqlConnection();
// 定义SQL语句
String sql = "UPDATE student SET stu_name=? WHERE stu_id=?";
// 预编译SQL
ps = conn.prepareStatement(sql);
// 给占位符赋值
ps.setString(1, "王五");
ps.setInt(2, 20200626);
// 执行SQL语句
if (ps.executeUpdate() != 0) {
System.out.println("信息修改成功");
}
} catch (Exception e) {
// TODO: handle exception
}
} /**
* execute()
* 作用:用于执行返回多个结果集、多个更新计数或二者组合的语句。例如:执行某个已存储过程或动态执行未知 SQL 字符串。
* 返回值:多个ResultSet对象、多个更新计数或ResultSet对象与更新计数。
* 使用
* 多个结果集
* 1. 执行完execute()方法后,使用CallableStatement对象调用getResultSet()方法获取第一个结果集,调用适当的getXXX方法获取值
* 2. 如果存在第二个结果集,则必须调用getMoreResults()方法,然后再调用getResultSet()方法来获取结果集,依次类推。
* 多个更新计数
* 1. 执行完execute()方法后,则首先调用方法 getUpdateCount,然后调用 getMoreResults,并再次调用 getUpdateCount,依次类推。
*
*/
public void testExecute() {
List<List<Map<String, Object>>> resultList = new ArrayList<>();
try {
// 获取数据库连接
conn = DBUtil.getMysqlConnection();
// 定义SQL语句
String sql = "sp_help 'test.student'";
// 预编译SQL
CallableStatement cs = conn.prepareCall(sql);
// 外循环获取结果集的个数
boolean oprFlg = cs.execute(sql);
while (oprFlg) {
List<Map<String, Object>> result = new ArrayList<>();
// 获取第一个结果集
rs = cs.getResultSet();
// 内循环获取每个结果集的记录
while (rs.next()) {
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
Map<String, Object> map = new HashMap<String, Object>();
for (int i = 0; i < columnCount; i++) {
map.put(rsmd.getColumnName(i + 1).toLowerCase(), rs.getObject(i + 1));
}
result.add(map);
}
resultList.add(result);
// 获取更多的结果集
oprFlg = cs.getMoreResults();
}
} catch (Exception e) {
// TODO: handle exception
}
}

    六、处理结果集

1. ResultSet:在线

 public class ResultSetTest {
// 数据库连接对象
Connection conn = null;
// 预处理对象
PreparedStatement ps = null;
// 结果集对象
ResultSet rs = null; /**
* 可滚动,可更新
* ResultSet.TYPE_FORWARD_ONLY:该常量控制ResultSet记录指针只能向前移动(默认)。
* ResultSet.TYPE_SCROLL_INSENSITIVE:该常量控制ResultSet记录指针可以自由移动(可滚动结果集),但底层数据的改变不会受ResultSet的内容。
* ResultSet.TYPE_SCROLL_SENSITIVE:该常量控制ResultSet记录指针可以自由移动(可滚动结果集),并且底层数据的改变会影响ResultSet的内容。
* ResultSet.CONCUR_READ_ONLY:该常量指示ResultSet是只读的并发模式(默认)。
* ResultSet.CONCUR_UPDATABLE: 该常量指示ResultSet是可更新的并发默认。
*
*/
public void testScrollAndUpdate() {
try {
// 获取数据库连接
conn = DBUtil.getMysqlConnection();
// 定义SQL语句
String sql = "SELECT stu_id,stu_name FROM student";
// 预编译SQL
ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
// 执行SQL语句
rs = ps.executeQuery();
// 处理结果集
while (rs.next()) {
System.out.println("学号:" + rs.getInt("stu_id") + " 姓名:" + rs.getString("stu_name"));
}
} catch (Exception e) {
// TODO: handle exception
}
} /**
* ResultSetMetaData:分析结果集,当不清楚该ResultSet里包含哪些数据列,以及每个数据列的数据类型,那么可以通过ResultSetMetaData来获取关于ResultSet的描述信息。
* getMetaData():获取ResultSetMetaData对象。
* int getColumnCount():返回该ResultSet的列数量。
* String getColumnName(int columnIndex):返回对应列的名称。
* int getColumnType(int columnIdex):返回对应列的数据类型。
*/
public void testResultSetMetaData() {
try {
// 获取数据库连接
conn = DBUtil.getMysqlConnection();
// 定义SQL语句
String sql = "SELECT stu_id,stu_name FROM student";
// 预编译SQL
ps = conn.prepareStatement(sql);
// 执行SQL语句
rs = ps.executeQuery();
// 处理结果集
while (rs.next()) {
// 获取结果集元数据对象
ResultSetMetaData rsmd = rs.getMetaData();
// 获取结果集列数
int columnCount = rsmd.getColumnCount();
for (int i = 0; i < columnCount; i++) {
// 获取结果集对应列名称
System.out.println(rsmd.getColumnName(i + 1));
// 获取结果集对应数据类型
System.out.println(rsmd.getColumnType(i + 1));
}
}
} catch (Exception e) {
// TODO: handle exception
}
}
}

2. RowSet:离线

 public class RowSetTest {
// 数据库连接对象
Connection conn = null;
// 预处理对象
PreparedStatement ps = null;
// 结果集对象
ResultSet rs = null; /**
* RowSet:实现了ResultSet接口,并且有子接口CachedRowSet(离线查询)
* 概念:离线查询:在本地搞一个结果集的副本,关闭结果集、数据库连接,使用本地的这个副本。
* 作用:RowSet默认是可滚动,可更新,可序列化的结果集,并且作为对JavaBean使用,因此能方便地在网络上传输,用于同步两端的数据。
* 优点:程序在创建RowSet时已把底层数据读取到了内存中,因此可以充分利用计算机的内存,从而减低数据库的负载,提高程序的性能。
*/
@Test
public void testRowSetOffline() {
try {
// 获取数据库连接
conn = DBUtil.getMysqlConnection();
// 定义SQL语句
String sql = "SELECT stu_id,stu_name FROM student";
// 预编译SQL
ps = conn.prepareStatement(sql);
// 执行SQL语句
rs = ps.executeQuery();
/**
* 离线查询
*/
// 通过RowSetProvider的静态方法创建RowSetFactory对象
RowSetFactory rsf = RowSetProvider.newFactory();
// 创建CachedRowSet对象
CachedRowSet crs = rsf.createCachedRowSet();
// 使用结果集填充CachedRowSet
crs.populate(rs); // 使用给定的ResultSet装填RowSet,从ResultSet的第startRow条记录开始装填。
/**
* 关闭数据库资源
*/
rs.close();
ps.close();
conn.close();
// 离线处理结果集:CachedRowSet是ResultSet的孙接口,使用的方法都相同。
while (crs.next()) {
System.out.println("学号:" + crs.getInt("stu_id") + " 姓名:" + crs.getString("stu_name"));
}
} catch (Exception e) {
// TODO: handle exception
}
} /**
* 分页:不推荐使用每个数据库特有的分页,追求跨数据库,代码可用性更高
* 1. 使用游标实现
* 2. 使用离线查询实现
*/
public void pagination() {
try {
/**
* 使用游标实现
*/
// 获取数据库连接
conn = DBUtil.getMysqlConnection();
// 定义SQL语句
String sql = "SELECT stu_id,stu_name FROM student";
// 预编译SQL
ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
// 执行SQL语句
rs = ps.executeQuery();
// 定义分页
int start = 0; // 起始页
int pageSize = 10; // 分页大小
// 定义游标
rs.absolute(start); // 游标指向起始位
while (rs.next()) {
// ......
if (rs.getRow() == pageSize) { // getRow()是获取当前记录是结果集中的第几条记录,第一条就是1。也可以设置计数器来判断
break;
}
} /**
* 使用离线查询实现
*/
// 创建RowSetFactory对象
RowSetFactory rsf = RowSetProvider.newFactory();
// 创建CachedRowSet对象
CachedRowSet crs = rsf.createCachedRowSet();
// 设置分页大小
crs.setPageSize(10);
// 使用结果集填充CachedRowSet
crs.populate(rs);
// 释放资源
rs.close();
ps.close();
conn.close();
while (crs.next()) {
// ......
}
} catch (Exception e) {
// TODO: handle exception
}
}
}

JDBC知识点总结的更多相关文章

  1. jdbc知识点(连接mysql)

    jdbc连接mysql 1.JDBC简介 JDBC: 指 Java 数据库连接,是一种标准Java应用编程接口( JAVA API),用来连接 Java 编程语言和广泛的数据库.从根本上来说,JDBC ...

  2. JavaSE_XMind总结

    1 JDBC知识点总结

  3. java用JDBC连接MySQL数据库的详细知识点

    想实现java用JDBC连接MySQL数据库.需要有几个准备工作: 1.下载Connector/J的库文件,下载Connector/J的官网地址:http://www.mysql.com/downlo ...

  4. Spring知识点总结(五)Spring整合JDBC

     1. 回顾JDBC        a. java操作关系型数据的API.导入相关数据库的驱动包后可以通过JDBC提供的接口来操作数据库.        b. 实现JDBC的六个步骤          ...

  5. 一个基础又很重要的知识点:JDBC原理(基本案例和面试知识点)

    JDBC全称又叫做Java DataBase Connectivity,就是Java数据库连接,说白了就是用Java语言来操作数据库.这篇文章主要是对JDBC的原理进行讲解.不会专注于其使用.主要是理 ...

  6. JDBC面试知识点整理(温习用)

    要面试,所以把之前的笔记整理一遍,嘻嘻,加油 JDBC编程 使用JDBC,java程序可以轻松地操作各种主流数据库,Oracle,MySQL,等,使用JDBC编写的程序不仅可以实现跨数据库,还具有跨平 ...

  7. JDBC 详解(转载)

    原文链接:http://blog.csdn.net/cai_xingyun/article/details/41482835 什么是JDBC? Java语言访问数据库的一种规范,是一套API JDBC ...

  8. JDBC详解(转)

    原文链接:http://blog.csdn.net/cai_xingyun/article/details/41482835 什么是JDBC? Java语言访问数据库的一种规范,是一套API JDBC ...

  9. JDBC代码示例

    package test; import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;imp ...

随机推荐

  1. PAT 1032 Sharing (25分) 从自信到自闭

    题目 To store English words, one method is to use linked lists and store a word letter by letter. To s ...

  2. [JavaWeb基础] 011.Struts2 配置拦截器

    在网页开发中有一个很重要的东西就是拦截器,就是在请求接收到的时候先到拦截器中进行一些逻辑处理,例如会话是否过期的验证等.在Struts2中我们可以编写一个拦截器的类,然后在struts.xml中简单配 ...

  3. Vue拖拽交换数据(非插件)

    HelloWorld.vue 文件 <template> <div class="hello"> <h1>{{ msg }}</h1> ...

  4. sqlmap tamper脚本备忘录与tamper脚本编写

    查看sqlmap全部脚本 $ python sqlmap.py --list-tampers 使用方法 --tamper=TAMPER 2019.9更新后翻译 * apostrophemask.py- ...

  5. 基于Basys2开发板的简易电子琴和音乐播放器设计

    背景:华中科技大学 电测综合实验 主要功能:Basys2开发板外接一个扬声器(或无源蜂鸣器也可)实现电子琴和音乐播放器的功能.其中由于开发板上只有4个按键,所以电子琴功能只做了4个音调,分别对应于4个 ...

  6. 【zookeeper】安装教程文档需下载

    请查看文件https://download.csdn.net/download/qq_42158942/11846847 zookeeper的作用 • ZooKeeper 是一个开源的分布式协调服务, ...

  7. Java实现 LeetCode 786 第 K 个最小的素数分数(大小堆)

    786. 第 K 个最小的素数分数 一个已排序好的表 A,其包含 1 和其他一些素数. 当列表中的每一个 p<q 时,我们可以构造一个分数 p/q . 那么第 k 个最小的分数是多少呢? 以整数 ...

  8. Java实现 蓝桥杯VIP 基础练习 回形取数

    问题描述 回形取数就是沿矩阵的边取数,若当前方向上无数可取或已经取过,则左转90度.一开始位于矩阵左上角,方向向下. 输入格式 输入第一行是两个不超过200的正整数m, n,表示矩阵的行和列.接下来m ...

  9. Java实现 蓝桥杯VIP 算法训练 友好数

    有两个整数,如果每个整数的约数和(除了它本身以外)等于对方,我们就称这对数是友好的.例如: 9的约数和有:1+3=4 4的约数和有:1+2=3 所以9和4不是友好的. 220的约数和有:1 2 4 5 ...

  10. Java实现第九届蓝桥杯小朋友崇拜圈

    小朋友崇拜圈 题目描述 班里N个小朋友,每个人都有自己最崇拜的一个小朋友(也可以是自己). 在一个游戏中,需要小朋友坐一个圈, 每个小朋友都有自己最崇拜的小朋友在他的右手边. 求满足条件的圈最大多少人 ...