当前位置: 首页 > news >正文

JDBC内容整理

什么是JDBC?

JDBC全称是Java Database Connection,它是一套Java用于连接数据库的Database的接口,具体的接口实现由各大数据库厂家完成。这样Java程序员只需要编写一套代码就可以操作不同的数据库。

如何使用JDBC?

jar包的获取

以MySQL为例,首先我需要得到MySQL关于JDBC接口的具体实现。相关资源可以通过MySQL官网找到对应版本的jar包,比如我使用的Mysql5.x版本,就需要5.x版本的jar包。
Mysql下载资源列表
在这里插入图片描述
在Mysql的资源列表中可以找到各个程序语言用来连接数据库的代码,我们选择Java。
在这里插入图片描述
版本选择以后找到一个zip类型的压缩包,下载即可。

配置

获取了资源以后,还不能使用这些接口实现。如果你是使用文本编辑器进行编写,需要将jar包路径添加到环境变量CLASSPATH中。
而如果是使用IDEA工具进行编程,需要在module settings中添加相关library
在这里插入图片描述
找到jar包所在路径进行添加
在这里插入图片描述

利用JDBC来操作数据库

步骤概览

  1. 注册驱动对象
  2. 建立与数据库之间的连接
  3. 获取操作数据库的对象
  4. 执行SQL语句
  5. 如果是查询语句,需要操纵查询集对象
  6. 释放相关资源

注册驱动对象

这里的驱动对象可以理解为jdbc的具体实现,我们需要告知现在操作的数据库是什么,并进行全局注册。

import java.io.Driver;
import java.io.DriverManager;
Dirver driver = new com.mysql.jdbc.Driver();
DriverManager.registerDriver(driver);

在这里插入图片描述
进入到com.mysql.jdbc.Driver这个类中可以看到它的静态代码块中已经有了驱动注册这一步,所以事实上我们只需要加载这个类,注册这一步不需要客户端程序员来完成。
将注册的两行代码替换成下面的一行代码,Class.forName调用时会对相应的类进行加载,它的静态代码块自然就执行了。

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

与数据库建立连接

下载数据库这块内容就不赘述,完成这一步的前提是你可以连接到具体的数据库中。

import java.sql.Connection;
import java.sql.DriverManager;
try{
	Class.forName("com.mysql.jdbc.Driver");
	String url = "jdbc:mysql://localhost:3306/test_db?useSSL=false";
	String user = "root";
	String passwd = "1234";
	Connection conn = DriverManager.getConnection(url, user, passwd);
}catch (Exception e){
	e.printStackTrace();
}

通过DriverManager.getConnection接口返回connection对象,这个接口接受三个参数,第一个数据库进程所在url地址,jadc::mysql是MySQL和Java之间通信的协议,localhost是本地主机的ip地址,你可以替换成服务器所在的ip地址,3306是MySQL进程默认所在的端口号,test_db是连接到的数据库名称,这里是我进行测试的数据库名称。?后面拼接的是参数,关于需要拼接哪些参数,后面有坑会提。这里我如果不拼接useSSL=false会报错,每个人具体软件环境不同,你可以根据测试结果来判断拼不拼接。

获得操作数据库的对象

import java.sql.Statement;
Statement stat = conn.createStatement();

Statement对象就是我们后面用来执行SQL语句的媒介,它有SQL注入的风险,后面会进行总结。

执行SQL语句

String sql = "create table t_user if not exists(id int, passwd varchar(20))";
int count = stat.executeUpdate(sql);

executeUpdate(String sql)用来DML和DDL语句,具体使用可以根据自身情况进行测试.
返回值是个int类型,用来表示成功影响的记录条数。

处理查询结果集

String sql = "select * from t_user";
ResultSet rs = stat.excuteQuery(sql);
while(rs.next()){
	int id = rs.getInt("id");
	String passwd = rs.getString("passwd");
	System.out.println("id: " + id + " passwd: " + passwd);
}

executeQuery可以用来执行DSL语句, 返回类型是ResultSet,是个查询结果集。它的next方法有两个功能,返回布尔类型,查询结果是否还有数据,每调用一次,数据记录”指针“就会向下移动一条。
通过getType(列名)的方法可以取得本条记录的列数据,Type是你想接受的数据类型。

关闭资源

关闭资源的准则是从小到大依次释放 ResultSet < Statement < Connection, 每个资源释放时调用close方法即可,且每一个都需要try catch

finally {
            if(rs != null){
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(stat != null){
                try {
                    stat.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(conn != null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }

完整的流程演示

import java.sql.*;
import java.util.*;
public class JDBCTest{
	public static void main(String[] args){
		Connection conn = null;
		Statement stat = null;
		ResultSet rs = null
		try{
			Class.forName("com.mysql.jdbc.Driver");
			String url = "jdbc:mysql://localhost:3306/test_db?useSSL=false";
			String user = "root";
			String passwd = "1234"
			conn = DriverManager.getConnection(url, user ,passwd);
			stat = conn.createStatement();
			String sql = "xxxx";
			stat.executeUpdate(sql);
		}
		catch(){
		}finally{
			if(rs != null)
				try{
					rs.close();
				}
				catch(Exception e){
					e.printStackTrace();
				}
			if(stat!= null)
				try{
					stat.close();
				}
				catch(Exception e){
					e.printStackTrace();
				}
			if(conn!= null)
				try{
					conn.close();
				}
				catch(Exception e){
					e.printStackTrace();
				}
				
		}

	}

}

Statement与PreparedStatement

Statement对象有个致命的缺陷,它可能收到SQL注入攻击。在上面的示例中,传入executeUpdate或者executeQuery中的是一个字符串,这个字符串的内容是SQL语句。
而这有什么潜在的隐患呢?

String sql = "select * from t_user where username = '" + username +"' and passwd = '" + passwd + "'";

username和passwd一般是用户通过输入框输入得到的,然后将输入的内容进行拼接。如果用户有意的干扰该SQL语句可能会发生意料之外的后果。
根本原因是用户输入的内容参与到了SQL语句的编译中,那么这就存在一定的风险。
PreparedStatement是Statement的子类,它采用预编译的方法来防止SQL注入。

String sql = "selec * from t_user where username = ? and passwd = ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, "xxx");
ps.setString(2, "xxx");
ps.executeQuery();

sql语句直接传入到了构造器中,?代表占位符,后面的setType方法对占位符赋值,第一个参数代表占位符的序号,数字从1开始。
PreparedStatement的优势,可以方法SQL注入,也可以做到SQL语句一次编译,多次使用,Statement是编译一次使用一次,传值时会进行类型检查。setString就设置String类型,setInt就设置int类型。

JDBC对事务机制的控制

默认情况下,Statement对象每执行一句SQL语句就会提交事务 (对数据库内容进行修改),这在绝大多数情况是不合理的。事务往往包括多条SQL语句,如转账系统,只有所有语句执行成功,事务才会被提交,否则回滚事务。

conn.setAutoCommit(false); //将自动提交事务修改为false
/*
	执行若干SQL语句
*/
conn.commit()

//try..catch语句中加入回滚事务的逻辑
conn.rollback();

行级锁的概念

在select语句后面加入for update就能锁住行级记录,只有当前事务提交了,其它进程的事务才能访问。

致谢

本篇Blog记录的内容动力节点相关的网课内容,内容有所简略,感兴趣的朋友可以在B站寻找相关资源。

相关文章:

  • SPD5详解
  • Python 教程之控制流(3)Python 中的循环和控制语句(继续、中断和通过)
  • 神仙级别Kafka架构笔记,阿里架构师看到都感慨怎么没早看到
  • Django 使用VScode 创建工程
  • mysql进阶:canal实现跨机房数据同步|主从数据同步
  • 交换机与路由技术-31-扩展ACL
  • 【JAVA数据结构】二叉树的常用方法(你想要的这里都有)
  • vue实战-轮播图的最佳方案/swiper的使用
  • spring-cloud-netflix 组件概述
  • 【MICCAI 2022】PHTrans:并行聚合全局和局部表示以进行医学图像分割
  • 渗透学习-靶场篇-XSS-labs(持续更新中)
  • 【SpringCloud】三、 分布式系统的延迟和容错
  • Ultra Fast Deep Lane Detection with HybridAnchor Driven Ordinal Classification
  • CodeChef 补题
  • k8s 污点和容忍
  • 《Java编程思想》读书笔记-对象导论
  • 【JavaScript】通过闭包创建具有私有属性的实例对象
  • 【跃迁之路】【641天】程序员高效学习方法论探索系列(实验阶段398-2018.11.14)...
  • 【跃迁之路】【699天】程序员高效学习方法论探索系列(实验阶段456-2019.1.19)...
  • gops —— Go 程序诊断分析工具
  • k8s 面向应用开发者的基础命令
  • React-redux的原理以及使用
  • spring boot下thymeleaf全局静态变量配置
  • SpringBoot几种定时任务的实现方式
  • Synchronized 关键字使用、底层原理、JDK1.6 之后的底层优化以及 和ReenTrantLock 的对比...
  • webgl (原生)基础入门指南【一】
  • win10下安装mysql5.7
  • 模仿 Go Sort 排序接口实现的自定义排序
  • 腾讯视频格式如何转换成mp4 将下载的qlv文件转换成mp4的方法
  • 没有任何编程基础可以直接学习python语言吗?学会后能够做什么? ...
  • 如何用纯 CSS 创作一个菱形 loader 动画
  • ​​​​​​​GitLab 之 GitLab-Runner 安装,配置与问题汇总
  • ​Kaggle X光肺炎检测比赛第二名方案解析 | CVPR 2020 Workshop
  • ​LeetCode解法汇总2670. 找出不同元素数目差数组
  • ​TypeScript都不会用,也敢说会前端?
  • # MySQL server 层和存储引擎层是怎么交互数据的?
  • #define,static,const,三种常量的区别
  • $.extend({},旧的,新的);合并对象,后面的覆盖前面的
  • (2009.11版)《网络管理员考试 考前冲刺预测卷及考点解析》复习重点
  • (android 地图实战开发)3 在地图上显示当前位置和自定义银行位置
  • (Arcgis)Python编程批量将HDF5文件转换为TIFF格式并应用地理转换和投影信息
  • (C语言)求出1,2,5三个数不同个数组合为100的组合个数
  • (Redis使用系列) Springboot 使用redis实现接口Api限流 十
  • (二)什么是Vite——Vite 和 Webpack 区别(冷启动)
  • (论文阅读32/100)Flowing convnets for human pose estimation in videos
  • (免费领源码)Java#Springboot#mysql农产品销售管理系统47627-计算机毕业设计项目选题推荐
  • (原)本想说脏话,奈何已放下
  • (转)Android中使用ormlite实现持久化(一)--HelloOrmLite
  • .Net mvc总结
  • .net 调用php,php 调用.net com组件 --
  • .NET 指南:抽象化实现的基类
  • .NET开源快速、强大、免费的电子表格组件
  • @RestControllerAdvice异常统一处理类失效原因
  • [ vulhub漏洞复现篇 ] Apache Flink目录遍历(CVE-2020-17519)
  • [ 云计算 | AWS ] 对比分析:Amazon SNS 与 SQS 消息服务的异同与选择