数据库事务、JDBC、连接池

523 阅读5分钟

数据库事务

什么是事务

  • 事务是指 针对一批操作,要么都成功,要么都失败

事务的四大原则 (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数据备份

为什么要备份?

  • 保证重要数据不丢失
  • 可以做数据转移

数据备份的方式

  1. 直接拷贝物理文件

  2. 使用可视化工具手动导出

  3. 使用命令行导出

    # mysqldump -h主机 -u用户名 -p密码 数据库 [表1] [表2] ... > 物理磁盘位置/文件名
    mysqldump -hlocalhost -uroot -padmin school student > d:/a.sql
    
  4. 使用命令行导入

    # mysql -u用户名 -p密码 数据库 < 备份文件
    mysql -uroot -padmin school < d:\a.sql
    或者
    # 登录状态下 使用source 备份文件
    # 如果导入的是表sql,需要切换到对应的数据库
    source a.sql
    

数据库的设计

  • 分析业务和需要处理的需求
  • 设计关系图 :E-R图

数据库的三大范式

  • 第一范式

    原子性 : 需要保证每一列不可再分

  • 第二范式

    前提:满足第一范式

    每张表只描述一件事情

  • 第三范式

    前提:满足第一范式 和 第二范式

    需要确保数据表中每一列数据都跟主键直接相关,而不是间接相关

  • 在实际的商业需求或者业务需求中,过分的遵循三大范式会影响响应速度,所以在实际情况中允许表中存在合理的冗余数据以提高查询效率。

JDBC

  • 操作步骤

    1. 加载数据库驱动

      Class.forName("com.mysql.cj.jdbc.Driver");
      
    2. 获取数据库连接

      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);
      
    3. 获取SQL执行对象 Statement、PrepareStatement

      //普通sql执行对象
      Statement statement = connection.createStatement();
      //预编译sql,防止sql注入
      connection.prepareStatement(sql);
      
    4. 获取返回的结果集

    5. 关闭连接

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    // 最大等待时间,单位是毫秒,	当没有可用连接时,连接池等待连接释放的最大时间,超过该时间会抛出异常