数据库事务
什么是事务
- 事务是指 针对一批操作,要么都成功,要么都失败
事务的四大原则 (ACID)
-
原子性(Atomicity)
同一个事务内的一批操作要么同时成功,要么同时失败
-
一致性(Consistency)
指事务前后的数据完整性要保持一致
-
持久性(Durability)
事务一旦提交,数据就会被持久化到数据库中
-
隔离性(Isolation)
事务的隔离性是指当多线程并发访问数据库时,数据库会给每个线程开启一个单独的事务,每个事务之间不会相互干扰。
隔离所导致的问题
-
脏读 :
是指一个事务读取到了另一个事物未提交的数据。
-
不可重复读:
是指在一个事务中读取某一条数据,由于其他事务对此条数据进行修改,导致多次读取的数据不一致
-
虚读(幻读)
是指在一个事务内读取到了其他事务插入的数据,导致前后读取的数据量不一致
-
索引
什么是索引
索引就是一种可以高效获取数据的数据结构
索引的分类
索引 | 描述 |
---|---|
主键索引(PRIMARY KEY) | 提供唯一性和非空约束,快速查询。可设为自动增长。 |
唯一索引(UNIQUE KEY) | 提供唯一性约束。快速查询 |
常规索引(KEY / INDEX) | 提供快速查询 |
全文索引(FULLTEXT) | 提高全文搜索的查询效率,快速定位到指定数据。 |
创建索引的方式
- 1、创建表时指定索引
create table table_name(
primary key(主键) -- 主键索引
[unique index_name (字段)] -- 唯一索引
[key | index index_name (字段)] -- 普通索引
[fullText index_name (字段)] -- 全文索引
)
- 2、修改表时添加索引
ALTER TABLE table_name ADD PRIMARY KEY (主键) -- 主键索引
ALTER TABLE table_name ADD UNIQUE index_name (字段) -- 唯一索引
ALTER TABLE table_name ADD INDEX index_name (字段) -- 普通索引
ALTER TABLE table_name ADD FULLTEXT index_name (字段) -- 全文索引
- 直接添加索引
CREATE INDEX index_name ON table_name (字段) -- 普通索引
CREATE UNIQUE INDEX index_name ON table_name (字段) -- 唯一索引
CREATE FULLTEXT INDEX index_name ON table_name (字段) -- 全文索引
索引原则
- 索引不是越多越好
- 不要对经常变动的数据加索引
- 小数据量的表不需要加索引
- 索引一般加在经常用作查询条件的字段上
MySQL数据备份
为什么要备份?
- 保证重要数据不丢失
- 可以做数据转移
数据备份的方式
-
直接拷贝物理文件
-
使用可视化工具手动导出
-
使用命令行导出
# mysqldump -h主机 -u用户名 -p密码 数据库 [表1] [表2] ... > 物理磁盘位置/文件名 mysqldump -hlocalhost -uroot -padmin school student > d:/a.sql
-
使用命令行导入
# mysql -u用户名 -p密码 数据库 < 备份文件 mysql -uroot -padmin school < d:\a.sql 或者 # 登录状态下 使用source 备份文件 # 如果导入的是表sql,需要切换到对应的数据库 source a.sql
数据库的设计
- 分析业务和需要处理的需求
- 设计关系图 :E-R图
数据库的三大范式
-
第一范式
原子性 : 需要保证每一列不可再分
-
第二范式
前提:满足第一范式
每张表只描述一件事情
-
第三范式
前提:满足第一范式 和 第二范式
需要确保数据表中每一列数据都跟主键直接相关,而不是间接相关
-
在实际的商业需求或者业务需求中,过分的遵循三大范式会影响响应速度,所以在实际情况中允许表中存在合理的冗余数据以提高查询效率。
JDBC
-
操作步骤
-
加载数据库驱动
Class.forName("com.mysql.cj.jdbc.Driver");
-
获取数据库连接
String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC"; String username = "root"; String password = "password"; // 3.获取连接 Connection connection = DriverManager.getConnection(url, username, password);
-
获取SQL执行对象 Statement、PrepareStatement
//普通sql执行对象 Statement statement = connection.createStatement(); //预编译sql,防止sql注入 connection.prepareStatement(sql);
-
获取返回的结果集
-
关闭连接
-
SQL注入
本质是字符串的拼接导致SQL语句可以正确的执行,从而导致数据库的数据泄露问题
防止SQL注入推荐使用PrepareStatement对象来执行sql操作。
JDBC操作事务
-
关闭自动提交就是默认开启事务
//关闭自动提交,默认就是开启事务 conn.setAutoCommit(false);
-
如果出现异常,事务会自动回滚,也可以手动回滚事务
// 事务回滚 conn.rollback();
package com.vecal.lesson04;
import com.vecal.lesson02.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) {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
// 1.获取连接
conn = JdbcUtils.getConnection();
//关闭自动提交,默认就是开启事务
conn.setAutoCommit(false);
String sql1 = "update account set money = money - 100 where name = ? ";
st = conn.prepareStatement(sql1);
st.setString(1,"A");
st.executeUpdate();
// int x = 2 / 0; 模拟异常
String sql2 = "update account set money = money + 100 where name = ? ";
st = conn.prepareStatement(sql2);
st.setString(1,"B");
st.executeUpdate();
// 提交事务
conn.commit();
} catch (Exception e) {
try {
// 回滚
conn.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
e.printStackTrace();
}finally {
JdbcUtils.release(conn, st, rs);
}
}
}
数据库连接池
-
问题
频繁的创建和释放数据库连接是非常消耗系统资源的
如何解决这个问题
-
使用数据库连接池
-
池化技术:
-
我们将一些连接预先准备好,当一个线程要连接数据库时,直接拿来使用就好;当连接使用完成时,不会直接释放连接,而是将连接重新放回数据库连接池中,当下一个线程需要使用连接时,直接从数据库连接池中获取连接使用。
-
基本配置参数
initialSize=10 // 连接池启动时创建的初始化连接数(默认为0) maxTotal=20 // 最大连接数 maxIdle=10 // 最大空闲连接数,超过空闲的连接将被释放 minIdle=5 // 最小空闲连接数,低于这个数量会创建新的连接 maxWaitMillis=60000 // 最大等待时间,单位是毫秒, 当没有可用连接时,连接池等待连接释放的最大时间,超过该时间会抛出异常
-