一: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. MySQL死锁系列-常见加锁场景分析

    在上一篇文章<锁的类型以及加锁原理>主要总结了 MySQL 锁的类型和模式以及基本的加锁原理,今天我们就从原理走向实战,分析常见 SQL 语句的加锁场景.了解了这几种场景,相信小伙伴们也能 ...

  2. 获取元素节点 & 操作属性节点

    1.html 文档编写 js 代码的位置: window.onload事件在整个html文档被完全加载完再执行,    所以可以获取html文档的任何节点 js-window-onload.html ...

  3. 用TensorFlow搭建一个万能的神经网络框架(持续更新)

    我一直觉得TensorFlow的深度神经网络代码非常困难且繁琐,对TensorFlow搭建模型也十分困惑,所以我近期阅读了大量的神经网络代码,终于找到了搭建神经网络的规律,各位要是觉得我的文章对你有帮 ...

  4. Chisel3 - 模块

    https://mp.weixin.qq.com/s/2vjM-gcauvHnn6KJzlOm4g   Chisel的模块和Verilog的模块很相似,都用来定义模块结构(hierarchical s ...

  5. MethodHandle(方法句柄)系列之二:方法句柄的简单使用

     二话不说,上代码 /** * * @author LiuYeFeng<897908343@qq.com> * @date 2015年4月8日 下午10:41:13 * @CopyRigh ...

  6. Java实现 LeetCode 788 旋转数字(暴力)

    788. 旋转数字 我们称一个数 X 为好数, 如果它的每位数字逐个地被旋转 180 度后,我们仍可以得到一个有效的,且和 X 不同的数.要求每位数字都要被旋转. 如果一个数的每位数字被旋转以后仍然还 ...

  7. Java实现 LeetCode 535 TinyURL 的加密与解密(位运算加密)

    535. TinyURL 的加密与解密 TinyURL是一种URL简化服务, 比如:当你输入一个URL https://leetcode.com/problems/design-tinyurl 时,它 ...

  8. Java实现 LeetCode 405 数字转换为十六进制数

    405. 数字转换为十六进制数 给定一个整数,编写一个算法将这个数转换为十六进制数.对于负整数,我们通常使用 补码运算 方法. 注意: 十六进制中所有字母(a-f)都必须是小写. 十六进制字符串中不能 ...

  9. Java实现 蓝桥杯VIP 算法提高 最长公共子序列

    算法提高 最长公共子序列 时间限制:1.0s 内存限制:256.0MB 问题描述 给定两个字符串,寻找这两个字串之间的最长公共子序列. 输入格式 输入两行,分别包含一个字符串,仅含有小写字母. 输出格 ...

  10. Java实现第十届蓝桥杯外卖店优先级

    试题 G: 外卖店优先级 时间限制: 1.0s 内存限制: 512.0MB 本题总分:20 分 [问题描述] "饱了么"外卖系统中维护着 N 家外卖店,编号 1 ∼ N.每家外卖店 ...