文章目录

  • 一、 JDBC概述
    • 1、JDBC定义
    • 2、数据的持久化储存
    • 3、JDBC体系结构
    • 4、JDBC程序编写步骤
  • 二、数据库连接
    • 1、数据库连接的三要素
    • 2、连接方式
      • 1、不使用配置文件
      • 2、使用配置文件
  • 三、JDBC的使用
    • 1、Statement的不安全性与sql注入问题
    • 2、使用PreparedStatement实现增删改查
      • 1、增
      • 2、删
      • 3、改
      • 4、查
    • 3、操作数据库的方法总结

一、 JDBC概述

1、JDBC定义

1、JDBC 是一种可用于,执行 SQL 语句的, JavaAPI。它由 Java 语言编写的一些类和界面组成。
2、JDBC为数据库,应用开发人员,提供了一种标准的应用程序设计接口,使开发人员可以用纯 Java 语言,编写完整的数据库应用程序。
3、 通过使用 JDBC,开发人员可以很方便地将 SQL 语句,传送给几乎任何一种数据库。
4、JDBC 是一种底层 API,这意味着它将直接调用 SQL 命令。
5、JDBC 还扩展了 Java 的功能。例如,用 Java 和 JDBC API 可以发布含有 applet 的网页。

2、数据的持久化储存

持久化(persistence):把数据保存到可掉电式存储设备中以供之后使用

3、JDBC体系结构

JDBC接口(API)包括两个层次:

  • 面向应用的API:Java API,抽象接口,供应用程序开发人员使用(连接数据库,执行SQL语句,获得结果)。
  • 面向数据库的API:Java Driver API,供开发商开发数据库驱动程序用。

4、JDBC程序编写步骤

二、数据库连接

1、数据库连接的三要素

1、Driver接口实现类
java.sql.Driver 接口是所有 JDBC 驱动程序需要实现的接口
mySql的驱动:com.mysql.jdbc.Driver




2、URL

  • DBC URL 用于标识一个被注册的驱动程序,驱动程序管理器通过这个 URL 选择正确的驱动程序,从而建立到数据库的连接。

  • JDBC URL的标准由三部分组成,各部分间用冒号分隔。

    • jdbc:子协议:子名称
    • 协议:JDBC URL中的协议总是jdbc
    • 子协议:子协议用于标识一个数据库驱动程序
    • 子名称:一种标识数据库的方法。子名称可以依不同的子协议而变化,用子名称的目的是为了定位数据库提供足够的信息。包含主机名(对应服务端的ip地址),端口号,数据库名

    例子:jdbc:mysql://localhost:3306/test_1?useUnicode=true&characterEncoding=utf8&usessl=true"

3、用户名和密码
user=root
password=123456

2、连接方式

1、不使用配置文件

public class TestConnection {@Testpublic void getConnection() {try {//1、连接数据库的4个基本要素String url = "jdbc:mysql://localhost:3306/test_1?useUnicode=true&characterEncoding=utf8&usessl=true";String user = "root";String password = "123456";String driverName = "com.mysql.jdbc.Driver";//2、实例化DriverClass clazz = Class.forName(driverName);Driver driver = (Driver) clazz.newInstance();//3.注册驱动DriverManager.registerDriver(driver);//连接数据库Connection connection = DriverManager.getConnection(url, user, password);System.out.println(connection);} catch (Exception e) {e.printStackTrace();}}
}

实际上,我们可以省略这一步,或者说成简化,因为,在Driver类的源码中有这样一段代码

static {try {DriverManager.registerDriver(new Driver());} catch (SQLException var1) {throw new RuntimeException("Can't register driver!");}}

静态代码块,随着类的加载而执行,在Class.forName(driverName)中,我们就已经将Driver加载进了内存。
所以,我们还可以将代码,进行简化。

  @Testpublic void getConnection2(){try {//连接数据库的4个要素String url="jdbc:mysql://localhost:3306/test_1?useUnicode=true&characterEncoding=utf8&usessl=true";String user="root";String password="123456";String driverName="com.mysql.jdbc.Driver";//加载驱动Class.forName(driverName);//数据库连接Connection connection = DriverManager.getConnection(url, user, password);System.out.println(connection);} catch (Exception e) {e.printStackTrace();}}

2、使用配置文件


user=root
password=123456
url=jdbc:mysql://localhost:3306/test_1?useUnicode=true&characterEncoding=utf8&usessl=true
driverClass=com.mysql.jdbc.Driver
    @Testpublic void getConnection3() {try {//加载配置文件InputStream is = TestConnection.class.getClassLoader().getResourceAsStream("jdbc.properties");Properties ps = new Properties();ps.load(is);//读取配置信息String url=ps.getProperty("url");String user=ps.getProperty("user");String password=ps.getProperty("password");String driverName=ps.getProperty("driverClass");//加载驱动Class.forName(driverName);//连接数据库Connection connection = DriverManager.getConnection(url, user, password);System.out.println(connection);} catch (Exception e) {e.printStackTrace();}}

三、JDBC的使用

1、Statement的不安全性与sql注入问题

JDBC Statement 形式的,数据库操作,是将一个组装好的,带有数据的SQL,直接提交给,MySQL服务。是极其不安全的。

举个例子:
数据库与表设计

-- 创建数据库
CREATE DATABASE `calss`;-- 切换到 bank 库
USE `calss`;-- 创建表
CREATE TABLE `user_balance` (`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT ,`name` VARCHAR(45) NOT NULL ,`balance` BIGINT NOT NULL ,PRIMARY KEY (`id`)
)
ENGINE = INNODB
DEFAULT CHARACTER SET = utf8mb4
COLLATE = utf8mb4_general_ci;

插入数据

INSERT INTO `user_balance`(`name`,`balance`)VALUES('张三',100);INSERT INTO `user_balance`(`name`,`balance`)VALUES('李四',101);
package Connection4;
import java.sql.*;
/*** @author shkstart* @create 2021-08-22 15:50*/
public class UnsafeStatement {private static String user = "root";private static String password = "123456";private static String driverClass = "com.mysql.jdbc.Driver";private static String url = "jdbc:mysql://localhost:3306/calss?useUnicode=true&characterEncoding=utf8";public static void select(String name) throws ClassNotFoundException, SQLException {Class.forName(driverClass);Connection conn =  DriverManager.getConnection(url,user, password);Statement stmt = null;try {stmt = conn.createStatement();String sql = String.format("SELECT * FROM user WHERE name='%s'", name);System.out.println(sql);ResultSet resultSet = stmt.executeQuery(sql);while (resultSet.next()) {System.out.printf("id: %s, name: %s, balance: %s\n",resultSet.getLong("id"),resultSet.getString("name"),resultSet.getLong("balance"));}resultSet.close();} finally {if (stmt != null) {stmt.close();}conn.close();}}public static void main(String[] args) throws SQLException, ClassNotFoundException {select("zhangsan' OR '1'='1");}
}

查询结果

在这里,我们只是想通过name查询单条记录,如果黑客通过sql注入暴力破解密码。那那么数据库将毫无保留的,展现在黑客的面前

2、使用PreparedStatement实现增删改查

PreparedStatement,继承自Statement,但比Statement功能强大的多。

优点:

1、PreparedStatement是预编译的,比Statement速度快。
当同时要执行多条相同结构sql语句时使用,这时可以用setObject(),addBatch()和executeBatch()这几个函数。

2、可以防止sql注入。
对JDBC而言,SQL注入攻击只对Statement有效,对PreparedStatement是无效的,这是因为PreparedStatement不允许在插入时改变查询的逻辑结构

1、增

@Testpublic void insertTest(){Connection conn=null;PreparedStatement ps=null;try {// 1.读取配置文件中的4个基本信息InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");Properties pros = new Properties();pros.load(is);String user = pros.getProperty("user");String password = pros.getProperty("password");String url = pros.getProperty("url");String driverClass = pros.getProperty("driverClass");// 2.加载驱动Class.forName(driverClass);// 3.获取连接conn = DriverManager.getConnection(url, user, password);//4、预编译sql,返回preparedStatement实例String sql="insert into customers(name,email,birth) values(?,?,?)";ps = conn.prepareStatement(sql);//5、填充占位符ps.setObject(1,"张国荣");ps.setObject(2,"2399526055@qq.com");SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");Date date = sdf.parse("1000-01-01");ps.setDate(3,new java.sql.Date(date.getTime()));//6、执行操作ps.execute();} catch (Exception e) {e.printStackTrace();} finally {//7、资源的关闭if(ps!=null){try {ps.close();} catch (SQLException throwables) {throwables.printStackTrace();}}if(conn!=null){try {conn.close();} catch (SQLException throwables) {throwables.printStackTrace();}}}}

运行前

运行后

2、删

   @Testpublic void testCommonUpdate() {String sql="delete from customers where id>?";update(sql,8);}public void update(String sql, Object... args) {//sql中占位符的个数与可变形参的长度相同!Connection conn = null;PreparedStatement ps = null;try {//1.获取数据库的连接conn = JDBCUtils.getConnection();//2.预编译sql语句,返回PreparedStatement的实例ps = conn.prepareStatement(sql);//3.填充占位符for (int i = 0; i < args.length; i++) {ps.setObject(i + 1, args[i]);//小心参数声明错误!!}//4.执行ps.execute();} catch (Exception e) {e.printStackTrace();} finally {//5.资源的关闭JDBCUtils.closeResouce(conn, ps);}}

删除前

删除后

3、改

  @Testpublic void updatetest() throws SQLException, IOException, ClassNotFoundException {Connection conn=null;PreparedStatement ps=null;try {//1、获取数据库连接conn = JDBCUtils.getConnection();//2、预编译sql,返回prearedStatement实例String sql="update customers set name=? where id =?";ps = conn.prepareStatement(sql);//3、填充占位符ps.setObject(1,"欢子");ps.setObject(2,8);//4、执行ps.execute();} catch (IOException e) {e.printStackTrace();} finally {//5、关闭资源JDBCUtils.closeResouce(conn,ps);}}

运行前

运行后

4、查

public class PreparedStatementList {@Testpublic void getList(){String sql="select id,name,email,birth from customers where id<?";List<Customer> allList = getAllList(Customer.class, sql, 8);allList.forEach(System.out::println);}public <T> List<T> getAllList(Class<T> clazz, String sql, Object...args){Connection conn=null;PreparedStatement ps=null;ResultSet rs=null;try {//1、读取配置文件conn = JDBCUtils.getConnection();ps = conn.prepareStatement(sql);for (int i = 0; i <args.length ; i++) {ps.setObject(i+1,args[i]);}rs = ps.executeQuery();//获取结果集的元数据ResultSetMetaData rsmd = rs.getMetaData();//获取结果集中的列数int columnCount = rsmd.getColumnCount();//创建集合,存放数据ArrayList<T> list = new ArrayList<T>();if(rs.next()){T t = clazz.newInstance();//处理结果集的每一列for (int i = 0; i <columnCount ; i++) {//获取列值Object columValue = rs.getObject(i + 1);//获取列名String columnname = rsmd.getColumnLabel(i+1);//给t对象指定columnname属性Field field = clazz.getDeclaredField(columnname);field.setAccessible(true);field.set(t,columValue);}list.add(t);}return list;} catch (Exception e) {e.printStackTrace();} finally {//关闭资源JDBCUtils.closeResource(conn,ps,rs);}return null;}
}

3、操作数据库的方法总结

方法名 功能描述
java.sql.Driver JDBC 驱动程序需要实现的接口
Properties 配置文件所使用的类
forname 返回一个类
DriverManager 管理驱动
Connection 与特定数据库的连接(会话)。 执行SQL语句并在连接的上下文中返回结果
Statement 用于执行静态SQL语句并返回其生成的结果的对象
PreparedStatement 表示预编译的SQL语句的对象
ResultSet 表示数据库结果集的数据表,通常通过执行查询数据库的语句生成。 ResultSet对象保持一个光标指向其当前的数据行。 最初,光标
getMetaData 检索一个ResultSetMetaData对象,其中包含有关执行此PreparedStatement对象时将返回的ResultSet对象的列的信息

熬夜总结学了一半的JDBC相关推荐

  1. 实战:第十三章:工作中熬夜加班学到的

    2020年8月到9月这段时间,我不停的在反思,我适不适合继续在这家公司待下去,我是不反对为了项目赶进度公司加班的,但是长期的通宵熬夜,让我感觉到身体吃不消,记忆力下降,掉发,暴躁,抗拒通宵加班,为什么 ...

  2. 熬夜帮学姐用Python完成词云图,没想到我好兄弟竟然...

    真实事件发生在我身上!注意这不是演习!! 事情经过(心塞历程) 事情发生在5月28日晚上十一点二十八分,学姐找到计算机专业的我,问我会不会使用Python做个词云图,本已眼皮打架的我正打算去睡觉了

  3. 网友:我30多岁了,现在转行学编程来得及吗?

    这些年,互联网行业的变化发展很快,很多公司也是借助互联网发展的大趋势发展的非常好. 水涨船高,行业好,意味着互联网行业的从业者的工资也就跟着高,很多互联网行业刚入门的月薪基本都已经过万了,一些传统行业 ...

  4. 螃蟹学PHP设计模式之解释器模式

    2019独角兽企业重金招聘Python工程师标准>>> 8.解释器模式 今天又迟到了一个小时,不过现在基本任务都做完了,螃蟹的效率还是挺高的.昨天一天跑各个工商局,发现大学生创业的扶 ...

  5. 看漫画就能学SQL,简直太cool了

    对于SQl, 很多人学不会的原因是从一开始就没明白,学这东西能干啥,学会了能有什么用.甚至有些人不知道'SQL'应该怎么读,以至于一开始兴致勃勃,但是学到一半放弃了. 注意:'sql'真的不能读成'烧 ...

  6. dj打碟怎么学_南京学DJ打碟

    南京学DJ打碟,前期是要满意才行,虽说现在能学DJ打碟的地方有不少,但也要靠谱一下自己到底满不满意,因为只有这样才能对得起自己花的钱.无论是在南京,还是在其他的城市,起码要知道自己到底能学到多少东西是 ...

  7. 学java语言之前学什么利于学习?

    想学Java的同学不在少数,其中有少部分同学可以通过大学科班进行学习,大多数同学只能通过自学或者系统学习入行,自学的同学都想知道在学习之前要不要学什么其他知识,今天小千就来给大家介绍一下. 学Java ...

  8. 学嵌入式有两个诀窍:勤奋刻苦+不要脸

    "最近看到很多学生朋友和我当年一样没有方向,所以把我的经历写出来与大家共勉,希望能给刚入行的朋友们一点点帮助." 一转眼我在IT行业学习工作已经七年多了,这期间我做过网页,写过MI ...

  9. 计算机能学设计吗,计算机平面设计难学吗

    计算机平面设计难学吗?对于学习平面设计,初学者往往不知从何下手,特别是零基础的伙伴们,选择自学,都会遇到很多小问题. 计算机平面设计难学吗?往往许多有兴趣的人都在一开始就退出了,没有进一步的去想知道这 ...

  10. 想学游戏建模要从哪里开始?,外包私活怎么接?

    对于零基础,入门难这个问题,有顾虑的人很多.但是细细想来,很多行业大佬在入行之初都是从不懂到精通(至于我捏,大佬说不算,从业七年,各种高模也还算是顺手拈来,求轻喷).我们身处一个学习型的时代,学习的机 ...

最新文章

  1. android 中的常用组件
  2. 50条超精辟的经典语录:哗众,可以取宠,也可以失宠!
  3. Java线程:保留的内存分析
  4. JavaFX 2 GameTutorial第4部分
  5. docker+MySQL+读写分离
  6. 远程注入利用远程线程直接注入
  7. SVN+MAVEN项目打包
  8. ERP:“造势”,还是“做事”
  9. Python多线程好玩弹窗代码
  10. python中文版下载-python3.8.1汉化版
  11. WPF UI框架界面开发教程(一)
  12. 基于matlab的紧急疏散模型仿真的代码,基于matlab的疏散仿真程序简介.pdf
  13. 青年与计算机比赛,我市首届青少年电脑机器人竞赛精彩上演
  14. 2021阿里淘系工程师推荐书单
  15. TAGE Branch Predictor/分支预测
  16. POJ2367 家谱树
  17. linux中利用k键杀死进程号,linux下杀死进程的若干方法
  18. 计算机与软件开发法则
  19. 毕业论文Word格式订正技巧
  20. mysql 对账语句_关于对账的一些理解

热门文章

  1. Android UI组件----ListView列表控件详解
  2. ubuntu系统VNC服务器安装配置
  3. Lucene多字段排序备忘(Sorting by multiple fields)
  4. 4.Jenkins 2 权威指南 --- 通知与报告
  5. 55. 时间服务器 : NTP 服务器
  6. 创建数据库company写出语句_MySQL中最实用的SQL语句
  7. html5中的input(type=file)的multiple属性,实现多文件上传,并用js控制文件大小,数量
  8. 安全运维 - Windows系统攻击回溯
  9. 2019年 iPad无法充电
  10. ~~~~练习~~~~用户登录(三次机会重试)