当前位置:网站首页>JDBC操作数据库详解
JDBC操作数据库详解
2022-07-25 09:25:00 【Zero摄氏度】
十、JDBC
10.1、数据库驱动
- 驱动:声卡、显卡、数据库
- 我们的程序会通过数据库驱动,再和数据库连接
10.2、JDBC
SUN公司为了简化开发人员的(对数据库的统一)操作,提供了一个java操作数据库的规范,俗称JDBC
这些规范的实现由具体的厂商去做,对于开发人员来说,我们只需要掌握JDBC接口的操作即可
jdbc需要的jar包
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java 数据库驱动包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.mchange/mchange-commons-java -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>mchange-commons-java</artifactId>
<version>0.2.19</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-pool/commons-pool -->
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-dbcp/commons-dbcp -->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.5</version>
</dependency>
10.3、第一个JDBC程序
- 创建一个数据库,导入数据
CREATE DATABASE `jdbcStudy` CHARACTER SET utf8 COLLATE utf8_general_ci;
USE `jdbcStudy`;
CREATE TABLE `users`(
`id` INT PRIMARY KEY,
`NAME` VARCHAR(40),
`PASSWORD` VARCHAR(40),
`email` VARCHAR(60),
birthday DATE
);
INSERT INTO `users`(`id`,`NAME`,`PASSWORD`,`email`,`birthday`)
VALUES(1,'zhangsan','123456','[email protected]','1980-12-04'),
(2,'lisi','123456','[email protected]','1981-12-04'),
(3,'wangwu','123456','[email protected]','1979-12-04')
- 创建一个普通项目,导入jar包
- 编写java代码(和sql yog中的可视化操作是一一对应的)
package com.qian.jdbc;
import java.sql.*;
//我的第一个jdbc程序
public class jdbcFirst {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver"); // 固定写法,加载驱动
//2.用户信息和url
String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
String username="root";
String password="123456";
//3.连接成功,数据库对象 connection代表数据库
Connection connection = DriverManager.getConnection(url, username, password);
//4.执行SQL对象 Statement 执行SQL的对象
Statement statement = connection.createStatement();
//5.用执行SQL的对象执行SQL,可能存在结果,查看返回结果
String sql = "SELECT *FROM users";
ResultSet resultSet = statement.executeQuery(sql);//返回的结果集,结果集中封装了我们全部查询出来的结果
while (resultSet.next()){
System.out.println("id="+resultSet.getObject("id"));
System.out.println("name="+resultSet.getObject("NAME"));
System.out.println("pwd="+resultSet.getObject("PASSWORD"));
System.out.println("email="+resultSet.getObject("email"));
System.out.println("birth="+resultSet.getObject("birthday"));
System.out.println("====================================================");
}
//6.释放连接
resultSet.close();
statement.close();
connection.close();
}
}
运行,拿到数据
步骤总结:
- 加载驱动
- 连接数据库 DriveManager
- 获取执行sql的对象 statement
- 获得返回的结果集 resultset
- 释放连接
10.4、JDBC中对象的解释
- DriverManager
Class.forName("com.mysql.jdbc.Driver"); // 固定写法,加载驱动
Connection connection = DriverManager.getConnection(url, username, password); //连接到数据库
//connection --数据库
connection.rollback(); // 事务回滚
connection.commit(); //事务提交
connection.setAutoCommit(); // 数据库设置自动提交
- URL
String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
//jdbc:mysql://主机地址:3306/数据库名?参数1&参数2&参数3
//mysql--3306
//oralce --1521
- Statement
// 执行SQL的对象 ,preparestatement也是执行sql的对象
String sql = "SELECT *FROM users";//编写SQL
statement.executeQuery();//查询操作返回 resultset
statement.execute();//执行任何SQL
statement.executeUpdate();//更新、插入、删除,都是用这个,返回一个受影响的行数
4.ResultSet
//只有查询才会返回的结果集,封装了所有查询出来的数据
resultSet.getObject(); //不知道列类型的情况下使用
resultSet.getInt(); //知道列的类型就使用指定的类型
resultSet.getBoolean();
resultSet.getFloat();
resultSet.getDate();
resultSet.beforeFirst();//移动到最前面
resultSet.afterLast();//移动到最后面
resultSet.next(); //移动到下一个数据
resultSet.previous();//移动到前一行
resultSet.absolute(row);//移动到指定行
- 释放资源
//6.释放连接
resultSet.close();
statement.close();
connection.close();
10.5、Statement对象
- JDBC中的statement对象用于向数据库发送SQL语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可
- statement对象的executeUpdate方法,用于向数据库发送增删改的sql语句,执行完成后,会返回一个整数(即增删改语句导致了数据库几行数据发生了变化);executeQuery方法用于向数据库发送查询语句,执行完毕返回查询出来的全部数据结果ResultSet
- 使用executeUpdate方法进行增删改
- 添加
Statement st = conn.createStatement();
String sql = "insert into user()values()";
int num = st.excuteUpdate(sql);
if(num>0){
system.out.println("插入成功");
} // 只要影响的数据发生变化则插入成功
- 删除
Statement st = conn.createStatement();
String sql = "delete from user where id=1";
int num = st.excuteUpdate(sql);
if(num>0){
system.out.println("删除成功");
}
- 修改
Statement st = conn.createStatement();
String sql = "update user set name=''where name=''";
int num = st.excuteUpdate(sql);
if(num>0){
system.out.println("修改成功");
}
- 使用excuteQuery查询
Statement st = conn.createStatement();
String sql = "SELECT *FROM users";
ResultSet resultSet = st.executeQuery(sql)
while (resultSet.next()){
System.out.println("id="+resultSet.getObject("id"));}
10.6、 SQL注入问题
- 例如我后台的sql语句为
"select * from s_student where loginName = '"+loginName+"' and loginPwd = '"+loginPwd+"'";
1
然后我随便输入一个用户名,但是只要密码输入的有讲究点
loginName = fasd;
loginPwd = fasd' or '1'='1;
12
因为1=1这条语句是一个永真式,且逻辑连接词使用的or,这样一来无论前面是什么loginPwd这个值一定为1,这样就将前面select语句的where条件恒为1,就相当于将前面的select语句给废了。
String Sql="select * from s_student where loginName = '"+fasd+"' and loginPwd = '"+fasd' or '1'='1+"'";
1
这样子我们可以绕过登录,去做一些危害网站的事情。
- SQL注入的根本原因
其实发生SQL注入的根本原因并非 是我们编写了loginPwd = fasd’ or ‘1’=‘1这条语句,究其根本是因为fasd’ or ‘1’='1这条语句被当作了sql语句的一部分被编译进去了
rs = stam.executeQuery(sql);
1
程序在执行到上面这行语句时,会将sql语句发送给DBMS(数据库管理系统),然后DBMS会将sql语句进行编译,但此时已经晚了,因为此时用户已经将一些非法语句拼接进了sql语句当中去,这样就会发生SQL注入。
10.7、 PreparedStatement对象(解决SQL注入问题)
PreparedStatement可以防止SQL注入,效率更好
- 在JDBC中,使用Statement的子类PreparedStatement进行预编译
我们可以事先将sql语句传入PreparedStatement中,将要传入到sql语句中的参数使用?(占位符)来代替,那么该sql语句就会进行预编译,之后将获取的参数通过PreparedStatement中的set(类型)方法传入编译后的sql语句中,这样sql语句就会先被编译再进行传值,用户输入的信息不会直接参与到sql语句的编译当中,就防止了sql注入的问题。
ps = conn.prepareStatement("select * from s_student where name = ? and password = ?");//先预编译
//一个问号表示一个占位符将来接收一个值
ps.setString(1,loginName);
ps.setString(2,loginPwd);
rs = ps.executeQuery(); // 执行查询
- 插入
//把配置以及关闭资源放在一个java类里utils.jdbcUtils
private static String url="jdbc:mysql://localhost:3306/test";
private static String username="root";
private static String password="root";
static{
Class.forName("com.mysql.jdbc.Driver");
}
public static Connection getConn(){
Connection connection=DriverManager.getConnection(url,username,password);
return connection;
}
//关闭资源
public static void close(ResultSet rs,Perparedstment perparedstment,Connection conn){
if(!Objects.isNull(rs)){
rs.close();}
if(!Objects.isNull(perparedstment)){
perparedstment.close()}
if(!Objects.isNull(conn)){
conn.close();}
}
}
//插入操作
package com.qian;
import com.qian.utils.jdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Test01 {
public static void main(String[] args) throws SQLException {
Connection connection= null;
PreparedStatement pstm=null;
try {
connection = jdbcUtils.getConnection();
//区别
//使用问好占位符代替参数
String sql = "insert into users(id,`NAME`) values(?,?)";
pstm = connection.prepareStatement(sql);//预编译sql,先写sql然后不执行
//手动赋值
pstm.setInt(1,6);
pstm.setString(2,"SANJIN");
//执行
int i = pstm.executeUpdate();
if (i>0){
System.out.println("插入成功");
}
} catch (Exception e) {
e.printStackTrace();
}finally {
jdbcUtils.release(connection,pstm,null);
}
}
}
10.8、 使用IDEA连接数据库
- 在数据库中添加mysql
- 和使用可视化工具一样
- 也可以编写执行sql
10.9、 JDBC操作事务
- ACID原则
原子性、一致性、隔离性、持久性
- 隔离性的问题:
- 脏读:一个事务读取了另一个没有提交的事务
- 不可重复读:在同一个事务内,重复读取表中的数据,表数据发生了改变
- 虚读:在同一个事务内,读取到了别人插入的数据,导致前后读出来结果不一致
- 代码
package com.qian.jdbc;
import com.qian.utils.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestTransaction {
public static void main(String[] args) throws SQLException {
Connection conn1 =null;
PreparedStatement st=null;
ResultSet rs = null;
try {
conn1 = JdbcUtils.getConn();
//关闭数据库的自动提交功能,自动会开启事务
conn1.setAutoCommit(false);
//
String sql1 ="update account set money-100 where name ='A'";
st = conn1.prepareStatement(sql1);
st.executeUpdate();
String sql2 ="update account set money+100 where name ='B'";
st = conn1.prepareStatement(sql2);
st.executeUpdate();
//业务完毕,提交事务
conn1.commit();
System.out.println("成功");
} catch (SQLException e) {
try {
conn1.rollback();//如果失败则回滚事务
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally {
JdbcUtils.close(rs,st, conn1);
}
}
}
10.10、 数据库连接池
- 数据库连接—执行完毕—释放
- 连接–释放 十分浪费系统资源
- 池化技术 :准备一些预先的资源,过来就连接预先准备好的
-----开门–业务员:等待 – 服务—
常用连接数 10个
最小连接数:10
最大连接数 15 业务最高承载上限
排队等候,等待超时:…
编写连接池,实现一个接口 DataSource
- 开源数据源实现
- DBCP
- C3P0
- Druid:阿里巴巴
使用了这些数据库连接池之后,我们在项目开发中就不需要编写连接数据库的代码了!
- DBCP 连接池
- 需要的jar包(Maven依赖导入jar包)
<!-- https://mvnrepository.com/artifact/commons-pool/commons-pool -->
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-dbcp/commons-dbcp -->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
- C3P0连接池
- 需要的jar包(用maven依赖导入jar包)
<!-- https://mvnrepository.com/artifact/com.mchange/mchange-commons-java -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>mchange-commons-java</artifactId>
<version>0.2.19</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.5</version>
</dependency>
- 结论
- 无论使用什么数据源,本质还是一样的,DataSource接口不会变,方法就不会变
边栏推荐
- Creation of adjacency table of undirected connected graph output breadth depth traversal
- 【建议收藏】靠着这些学习方法,我入职了世界五百强——互联网时代的“奇技淫巧”
- C函数不加括号的教训
- 概率机器人学习笔记第二章
- Development history of convolutional neural network (part)
- Exciting method and voltage of vibrating wire sensor by hand-held vibrating wire acquisition instrument
- 低功耗和UPF介绍
- FPGA基础进阶
- Excel导入导出源码分析
- CCF 201604-2 Tetris
猜你喜欢

ESP32连接阿里云MQTT物联网平台

Data viewing and parameter modification of multi-channel vibrating wire, temperature and analog sensing signal acquisition instrument

CCF 201509-4 Expressway

【机器翻译】SCONES——用多标签任务做机器翻译

Download and installation of QT 6.2

BSP3 电力监控仪(功率监控仪)端子定义和接线

VScode配置ROS开发环境:修改代码不生效问题原因及解决方法

js利用requestAnimationFrame实时检测当前动画的FPS帧率

CDA Level1知识点总结之业务分析报告与数据可视化报表

小程序调起微信支付
随机推荐
Mlx90640 infrared thermal imaging sensor temperature measurement module development notes (III)
SOC芯片内部结构
FPGA基础进阶
Solve the Chinese garbled code error of qtcreator compiling with vs
Yolov5 realizes target detection of small data sets -- kolektor defect data set
小程序调起微信支付
canal实现mysql数据同步
Store to-do items locally (improve on to-do items)
js利用requestAnimationFrame实时检测当前动画的FPS帧率
Exciting method and voltage of vibrating wire sensor by hand-held vibrating wire acquisition instrument
ROS分布式操作--launch文件启动多个机器上的节点
FLASH read / write operation and flash upload file of esp8266
Arm preliminaries
ECO简介
关闭brew执行命令时的自动更新
CCF 201503-3 节日
【近万字干货】别让你的简历配不上你的才华——手把手教你制作最适合你的简历
入住阿里云MQTT物联网平台
ADC简介
TM1637带秒点四位LED显示器模块ARDUINO驱动程序