目录
一、事务-简介&四大特征
①事务简介
- 数据库的事务(Transaction)是一种机制、操作序列,包含了一组数据库操作命令。
- 事务把所有命令当做一个整体一起向系统提交或撤销操作请求,即这一组数据库命令要么同时成功,要么同时失败。
- 事务是一个不可分割的工作逻辑单元
# 开启事务
START TRANSACTION
或者 BEGIN;
# 提交事务
COMMIT;
# 回滚事务
ROLLBACK;
②事务四大特征
事务是由一组SQL语句组成的逻辑处理单元,事务具有以下4个特征,通常简称为事务的ACID属性:
- 原子性(Atominity):事务是不可分割的最小操作单位,要么同时成功,要么同时失败。
- 一致性(Consistent):在事务开始或完成时,数据必须保持一致状态。举个转账的例子,假设用户A与用户B各有1000元,则不管A、B间如何转账、转几次账,事务结束后两者的钱的总和依然是2000元。
- 隔离性(Isolation):数据库提供一定的隔离机制,保证事务在不受外部并发操作影响的独立环境执行。即事务处理过程的中间状态对外部是不可见的。
- 持久性(Durabilty):事务完成后,对数据的修改是永久性的,即使数据库系统遇到故障也能保持。
Mysql事务默认自动提交
# 查看事务默认提交方式
SELECT @@autocommit;
# 1 : 自动提交 0 :手动提交
# 修改事务提交方式
set @@autocommit = 0;
二、JDBC简介
JDBC概念:
- JDBC就是使用Java语言操作关系数据库的一套API
- 全称(Java DataBase Connectivity)Java数据库连接
JDBC本质:
- 官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口
- 各个数据库厂商实现这套接口,提供数据库驱动jar包
- 开发者使用这套接口编程,真正执行代码的是驱动jar包中的实现类
JDBC优势:
- 各数据库厂商使用相同接口,Java代码不需要针对不同数据库分别开发
- 可随时更换底层数据库,访问数据库的Java代码可拓展性强
三、JDBC操作步骤
JDBC操作步骤主要代码
// 1. 注册驱动
Class.forName("com.mysql.jdbc.Driver");
/*
url语法:
jdbc:mysql://IP地址(域名):端口号/数据库名称??参数键值对1&参数键值对2...
细节:
·如果连接本机数据库,并且nysql服务默认端口四3306,则url可简写为:jdbc:mysql:///数据库名称...
·配置 useSSL = lase,禁用安全连接方式,解决警告提示
*/
String url = "jdbc:mysql://localhost:3306/数据库名称?参数键值对1&参数键值对2...";
String username = "root";
String password = "*******";
// 2. 获取连接
Connection connection = DriverManager.getConnection(url, username, password);
// 3. 定义 sql
String sql = "";
// 4. 获取执行sql的对象
Statement stmt = connection.createStatement();
// 5. 执行sql
stmt.executeUpdate(sql); // INSERT、UPDATE、DELETE 以及 DDL语句
stmt.executeQuery(sql); // SELECT 查询语句
stmt.execute(); // 执行返回多个结果集、更新计数或二者组合的语句
// 6. 释放资源
stmt.close();
connection.close();
①注册驱动(DriverManager API)
连接数据库前,首先需要加载数据库驱动到 JVM,通过java.lang.Class类的静态方法
forName(String className)实现。成功加载后,会将Driver类的实例注册到DriverManager类中
Class.forName("com.mysql.jdbc.Driver");
②创建数据库连接并获取执行对象(Connection API)
- Connection(数据库连接对象)作用:
- 获取连接数据库的对象
- 获取执行sql的对象
- 管理事务
1. 连接数据库,获取的 connection 对象就代表一个数据库的连接
Connection connection = DriverManager.getConnection(url, username, password);
2. 获取执行sql的对象
- 普通执行 sql 对象
Statement stmt = connection.createStatement();
- 预编译 sql 的执行 sql 对象,防止 sql 注入
PreparedStatement stmt = connection.prepareStatement(sql);
sql 注入
- sql注入通过操作输入来修改事先定义好的sql语句,用以达到执行代码对服务器进行攻击的方法。
举个例子:加入某网站判断用户输入的账号与密码是否有效使用的代码语句如下:
此处如何使用 sql 注入?
只需将 pwd 赋值 为' or '1' = '1
,name任意,即可完成 sql 注入。
观察使用sql注入后的sql语句,or 条件一定成立,因此上述中的resultSet.next()
一定成立。
PreparedStatement的作用: 预编译 sql 执行 sql 语句
①获取PreparedStatement对象
// 使用 ? 占位符 替代 sql 语句中的参数值
String sql = "select * from tb_user where username = ? and password = ?
// 通过 Connection 对象获取,并传入对应的 sql 语句
PreparedStatement pstmt = connection.preparedStatement(sql);
②设置参数值
PreparedStatement对象:
setXxx(参数1,参数2)
给 ? 赋值
Xxx:数据类型。如setInt(参数1,参数2)
参数:
- 参数1:? 的位置编号,从 1 开始
- 参数2:? 的值
③执行sql
executeUpdate(); / executeQuery(); 不需要传送sql
PreparedStatement优势
- 预编译sql,性能更高
- 防止sql注入:将敏感字符进行转义
回到刚才的例子,将代码改成下方即可避免sql注入
- 执行存储过程的对象
CallableStatement stmt = connection.prepareCall(sql);
3. 管理事务
- Mysql 事务管理
开启事务:BEGIN; / START TRANSACTION;
提交事务:COMMIT;
回滚事务:ROLLBACK;
Mysql 默认自动提交事务
- JDBC事务管理:Connection接口定义了3个对应方法
// autoCommit = true->自动提交事务 ; false->手动提交事务,即开启事务
开启事务:setAutoCommit(boolean autoCommit);
提交事务:commit();
回滚事务:rollback();
③执行sql语句(Statment API & PreparedStatement API)
- 执行sql语句
int executeUpdate(sql); // 执行 DML 以及 DDL语句
// 返回值:(1)DML语句影响的行数 (2)DDL执行成功也可能返回 0
ResultSet executeQuery(sql); // 执行 DQL 语句
// 返回值:ResultSet 结果集对象
- ResultSet(结果集对象)作用: 封装 DQL 查询语句的结果
- 获取查询结果
boolean next(): (1)将光标从当前位置向前移动一行 (2)判断当前行是否为有效行
返回值:
- true:有效行,当前行有数据
- false:无效行,当前行无数据
xxx getXxx(参数):获取数据
参数:
- int:列的编号,从 1 开始
- String:列的名称
ResultSet使用步骤
- 游标向下移动一行,并判断该行是否有数据
- 获取数据:getXxx(参数)
// 循环判断游标是否是最后一行末尾
while(resutSet.next()){
// 获取数据
resultSet.getXxx(参数);
}
e.g
数据库 test 中的 students 表如下
// 完成常规注册以及连接
// 1. 注册驱动
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/test?useSSL=false";
String username = "root";
String password = "****";
// 2. 获取连接
Connection connection = DriverManager.getConnection(url, username, password);
- int executeUpdate() 使用
// 3.定义 sql
String sql = "UPDATE students set age = 20 WHERE name = '小唐'";
// 4.获取执行sql的对象 Statement
Statement stmt = connection.createStatement();
// 5. 执行sql, 返回受影响行数
int count = stmt.executeUpdate(sql);
// 6. 处理结果
System.out.println(count);
// 7. 释放资源
stmt.close();
connection.close();
事务完成后,数据库内容已经发生变化
- ResultSet executeQuery(sql) 使用
// 3.定义 sql
String sql = "select * from students";
// 4.获取执行sql的对象 Statement
Statement stmt = connection.createStatement();
try {
ResultSet resultSet = stmt.executeQuery(sql);
while(resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
String gender = resultSet.getString("gender");
int age = resultSet.getInt("age");
System.out.format("id: %-2d name: %-6s gender: %-2s age: %-2d\n", id , name, gender, age);
}
/*
效果同上
while(resultSet.next()) {
int id = resultSet.getInt(1);
String name = resultSet.getString(2);
String gender = resultSet.getString(3);
int age = resultSet.getInt(4);
System.out.format("id: %-2d name: %-6s gender: %-2s age: %-2d\n", id , name, gender, age);
}
*/
resultSet.close();
stmt.close();
connection.close();
} catch (SQLException var12) {
connection.rollback();
var12.printStackTrace();
} catch (Exception var13) {
var13.printStackTrace();
}
事务完成后查询结果如下
④关闭资源
操作完成后要将所有使用的JDBC对象关闭,以释放JDBC资源。
关闭顺序与声明顺序相反:
- 先关闭RequestSet对象
- 再关闭Statement对象
- 最后关闭Connection对象
四、数据库连接池简介
-
数据库连接池是个容器,负责分配、管理数据库连接(Connection)
-
它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个
-
释放空闲空间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏
好处
- 资源重用
- 提升系统响应速度
- 避免数据库连接遗漏
数据库连接池实现
标准接口:DataSource
- 官方(sun公司)提供的数据库连接池标准接口,由第三方组织实现此接口
- 功能:获取连接
Druid(德鲁伊)
- Druid连接池是阿里巴巴开源的数据库连接池项目
- 功能强大,性能优秀,是Java语言最好的数据库连接池之一
五、Druid使用步骤
①定义配置文件
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?useSSL=false
username=root
password=tangyitao273169.
# 初始化连接池数量
initialSize=5
# 最大连接池
maxActive=10
# 最长等待时间 (ms)
maxWait=3000
定义配置,并将文件命名为 xxx.properties。
②加载配置文件
Properties prop = new Properties();
prop.load(new FileInputStream(①配置文件所在路径));
③获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
④获取数据库连接
Connection connection = dataSource.getConnection();
Properties prop = new Properties();
prop.load(new FileInputStream(①配置文件所在路径));
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
Connection connection = dataSource.getConnection();