熬夜总结学了一半的JDBC
文章目录
- 一、 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相关推荐
- 实战:第十三章:工作中熬夜加班学到的
2020年8月到9月这段时间,我不停的在反思,我适不适合继续在这家公司待下去,我是不反对为了项目赶进度公司加班的,但是长期的通宵熬夜,让我感觉到身体吃不消,记忆力下降,掉发,暴躁,抗拒通宵加班,为什么 ...
- 熬夜帮学姐用Python完成词云图,没想到我好兄弟竟然...
真实事件发生在我身上!注意这不是演习!! 事情经过(心塞历程) 事情发生在5月28日晚上十一点二十八分,学姐找到计算机专业的我,问我会不会使用Python做个词云图,本已眼皮打架的我正打算去睡觉了
- 网友:我30多岁了,现在转行学编程来得及吗?
这些年,互联网行业的变化发展很快,很多公司也是借助互联网发展的大趋势发展的非常好. 水涨船高,行业好,意味着互联网行业的从业者的工资也就跟着高,很多互联网行业刚入门的月薪基本都已经过万了,一些传统行业 ...
- 螃蟹学PHP设计模式之解释器模式
2019独角兽企业重金招聘Python工程师标准>>> 8.解释器模式 今天又迟到了一个小时,不过现在基本任务都做完了,螃蟹的效率还是挺高的.昨天一天跑各个工商局,发现大学生创业的扶 ...
- 看漫画就能学SQL,简直太cool了
对于SQl, 很多人学不会的原因是从一开始就没明白,学这东西能干啥,学会了能有什么用.甚至有些人不知道'SQL'应该怎么读,以至于一开始兴致勃勃,但是学到一半放弃了. 注意:'sql'真的不能读成'烧 ...
- dj打碟怎么学_南京学DJ打碟
南京学DJ打碟,前期是要满意才行,虽说现在能学DJ打碟的地方有不少,但也要靠谱一下自己到底满不满意,因为只有这样才能对得起自己花的钱.无论是在南京,还是在其他的城市,起码要知道自己到底能学到多少东西是 ...
- 学java语言之前学什么利于学习?
想学Java的同学不在少数,其中有少部分同学可以通过大学科班进行学习,大多数同学只能通过自学或者系统学习入行,自学的同学都想知道在学习之前要不要学什么其他知识,今天小千就来给大家介绍一下. 学Java ...
- 学嵌入式有两个诀窍:勤奋刻苦+不要脸
"最近看到很多学生朋友和我当年一样没有方向,所以把我的经历写出来与大家共勉,希望能给刚入行的朋友们一点点帮助." 一转眼我在IT行业学习工作已经七年多了,这期间我做过网页,写过MI ...
- 计算机能学设计吗,计算机平面设计难学吗
计算机平面设计难学吗?对于学习平面设计,初学者往往不知从何下手,特别是零基础的伙伴们,选择自学,都会遇到很多小问题. 计算机平面设计难学吗?往往许多有兴趣的人都在一开始就退出了,没有进一步的去想知道这 ...
- 想学游戏建模要从哪里开始?,外包私活怎么接?
对于零基础,入门难这个问题,有顾虑的人很多.但是细细想来,很多行业大佬在入行之初都是从不懂到精通(至于我捏,大佬说不算,从业七年,各种高模也还算是顺手拈来,求轻喷).我们身处一个学习型的时代,学习的机 ...
最新文章
- android 中的常用组件
- 50条超精辟的经典语录:哗众,可以取宠,也可以失宠!
- Java线程:保留的内存分析
- JavaFX 2 GameTutorial第4部分
- docker+MySQL+读写分离
- 远程注入利用远程线程直接注入
- SVN+MAVEN项目打包
- ERP:“造势”,还是“做事”
- Python多线程好玩弹窗代码
- python中文版下载-python3.8.1汉化版
- WPF UI框架界面开发教程(一)
- 基于matlab的紧急疏散模型仿真的代码,基于matlab的疏散仿真程序简介.pdf
- 青年与计算机比赛,我市首届青少年电脑机器人竞赛精彩上演
- 2021阿里淘系工程师推荐书单
- TAGE Branch Predictor/分支预测
- POJ2367 家谱树
- linux中利用k键杀死进程号,linux下杀死进程的若干方法
- 计算机与软件开发法则
- 毕业论文Word格式订正技巧
- mysql 对账语句_关于对账的一些理解
热门文章
- Android UI组件----ListView列表控件详解
- ubuntu系统VNC服务器安装配置
- Lucene多字段排序备忘(Sorting by multiple fields)
- 4.Jenkins 2 权威指南 --- 通知与报告
- 55. 时间服务器 : NTP 服务器
- 创建数据库company写出语句_MySQL中最实用的SQL语句
- html5中的input(type=file)的multiple属性,实现多文件上传,并用js控制文件大小,数量
- 安全运维 - Windows系统攻击回溯
- 2019年 iPad无法充电
- ~~~~练习~~~~用户登录(三次机会重试)