事务连接池

一、事务概述

(一)事务的定义

事务是数据库提供的一种特性,用于确保数据操作的完整性和一致性。事务将多个数据操作组合成一个逻辑单元,这些操作要么全部成功,要么全部失败。

(二)事务的特性(ACID)

  1. 原子性(Atomicity):事务中的所有操作要么全部成功,要么全部失败。

  2. 一致性(Consistency):事务执行前后,数据库的状态必须保持一致。

  3. 隔离性(Isolation):多个事务并发执行时,每个事务都好像在独立运行,互不干扰。

  4. 持久性(Durability):事务一旦提交,其对数据库的更改就是永久性的。

二、MySQL中的事务操作

(一)转账的例子

假设冠希给美美转1000元钱,这个操作需要确保以下两个步骤要么全部成功,要么全部失败:

  1. 从冠希的账户中扣除1000元。

  2. 给美美的账户加上1000元。

(二)数据库表结构和初始数据

复制代码
CREATE TABLE t_account (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(20),
    money DOUBLE
);

INSERT INTO t_account VALUES (NULL, '美美', 10000);
INSERT INTO t_account VALUES (NULL, '冠希', 10000);
INSERT INTO t_account VALUES (NULL, '小凤', 10000);
INSERT INTO t_account VALUES (NULL, '熊大', 10000);
INSERT INTO t_account VALUES (NULL, '熊二', 10000);

(三)使用事务实现转账

在MySQL中,可以通过以下步骤使用事务实现转账操作:

复制代码
-- 开启事务
START TRANSACTION;

-- 从冠希的账户中扣除1000元
UPDATE t_account SET money = money - 1000 WHERE username = '冠希';

-- 给美美的账户加上1000元
UPDATE t_account SET money = money + 1000 WHERE username = '美美';

-- 提交事务
COMMIT;

如果在执行过程中发生任何错误,可以回滚事务,撤销所有更改:

复制代码
-- 开启事务
START TRANSACTION;

-- 从冠希的账户中扣除1000元
UPDATE t_account SET money = money - 1000 WHERE username = '冠希';

-- 给美美的账户加上1000元
UPDATE t_account SET money = money + 1000 WHERE username = '美美';

-- 如果发生错误,回滚事务
ROLLBACK;

三、事务的隔离级别

(一)隔离级别概述

事务的隔离级别用于控制事务之间的隔离程度,以解决并发操作中可能出现的问题,如脏读、不可重复读和幻读。

(二)隔离级别分类

  1. Read Uncommitted:最低的隔离级别,允许脏读。

  2. Read Committed:避免脏读,但可能出现不可重复读。

  3. Repeatable Read(默认级别):避免脏读和不可重复读,但可能出现幻读。

  4. Serializable:最高的隔离级别,避免所有并发问题,但性能开销最大。

(三)设置隔离级别

复制代码
SET SESSION TRANSACTION ISOLATION LEVEL [隔离级别];

四、在JDBC中操作事务

(一)操作事务的方法

在JDBC中,可以通过Connection接口操作事务:

  • void setAutoCommit(boolean autoCommit):设置事务是否自动提交。

  • void commit():提交事务。

  • void rollback():回滚事务。

(二)示例代码

复制代码
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class TransactionExample {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/mydb";
        String user = "root";
        String password = "password";

        try (Connection connection = DriverManager.getConnection(url, user, password)) {
            // 关闭自动提交模式
            connection.setAutoCommit(false);

            // 开启事务
            String sql1 = "UPDATE t_account SET money = money - 1000 WHERE username = '冠希'";
            String sql2 = "UPDATE t_account SET money = money + 1000 WHERE username = '美美'";

            try (PreparedStatement stmt1 = connection.prepareStatement(sql1);
                 PreparedStatement stmt2 = connection.prepareStatement(sql2)) {

                // 执行事务中的SQL语句
                stmt1.executeUpdate();
                stmt2.executeUpdate();

                // 提交事务
                connection.commit();
            } catch (SQLException e) {
                // 回滚事务
                connection.rollback();
                e.printStackTrace();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

五、数据库连接池

(一)连接池概述

数据库连接池是一种资源管理技术,用于高效管理和复用数据库连接。连接池预先创建一定数量的数据库连接,并在需要时将这些连接分配给请求者,使用完毕后归还到池中。

(二)连接池的优势

  1. 节省资源:避免频繁创建和销毁连接的开销。

  2. 提高性能:快速获取和释放连接,提高系统性能。

  3. 资源限制:限制同时打开的连接数量,避免过多的连接消耗过多的系统资源。

(三)常见的连接池

  1. DBCP连接池:Apache开源组织提供的连接池。

  2. C3P0连接池:开源的连接池。

  3. Druid连接池:阿里巴巴提供的连接池,功能强大,性能优越。

(四)Druid连接池的使用

1. 导入Druid的jar包
复制代码
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.10</version>
</dependency>
2. 编写测试程序
复制代码
import com.alibaba.druid.pool.DruidDataSource;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class DruidTest {
    public static void main(String[] args) {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/mydb");
        dataSource.setUsername("root");
        dataSource.setPassword("password");

        // 设置连接池参数
        dataSource.setInitialSize(5);
        dataSource.setMaxActive(10);
        dataSource.setMaxWait(2000);
        dataSource.setMaxIdle(12);
        dataSource.setMinIdle(3);

        Connection conn = null;
        PreparedStatement stmt = null;

        try {
            conn = dataSource.getConnection();
            String sql = "INSERT INTO t_user VALUES (NULL, ?, ?, ?)";
            stmt = conn.prepareStatement(sql);
            stmt.setString(1, "eee");
            stmt.setString(2, "eee");
            stmt.setString(3, "eee");
            stmt.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
3. 编写工具类
复制代码
import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

public class JdbcUtils {
    private static DataSource dataSource;

    static {
        Properties props = new Properties();
        try (InputStream in = JdbcUtils.class.getResourceAsStream("/druid.properties")) {
            props.load(in);
            dataSource = DruidDataSourceFactory.createDataSource(props);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    public static void close(Connection conn, Statement stmt, ResultSet rs) {
        try {
            if (rs != null) rs.close();
            if (stmt != null) stmt.close();
            if (conn != null) conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
4. 配置文件druid.properties
复制代码
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mydb
username=root
password=password
initialSize=5
maxActive=10
maxWait=3000
maxIdle=6
minIdle=3

六、总结

通过使用事务,可以确保数据操作的完整性和一致性。在MySQL中,可以通过START TRANSACTIONCOMMITROLLBACK命令操作事务。事务的隔离级别可以控制并发操作中的隔离程度,以解决脏读、不可重复读和幻读等问题。

相关推荐
冰箱上的笑话1 小时前
MySQL 数据库故障排查指南
数据库·mysql·adb
wuli玉shell2 小时前
spark-Schema 定义字段强类型和弱类型
android·java·spark
东风西巷3 小时前
BLURRR剪辑软件免费版:创意剪辑,轻松上手,打造个性视频
android·智能手机·音视频·生活·软件需求
JhonKI3 小时前
【MySQL】行结构详解:InnoDb支持格式、如何存储、头信息区域、Null列表、变长字段以及与其他格式的对比
android·数据库·mysql
ab_dg_dp4 小时前
Android 位掩码操作(&和~和|的二进制运算)
android
吻等离子14 小时前
解决 MySQL 数据库无法远程连接的问题
数据库·mysql·adb
潜龙952716 小时前
第3.2.3节 Android动态调用链路的获取
android·调用链路
追随远方16 小时前
Android平台FFmpeg音视频开发深度指南
android·ffmpeg·音视频
撰卢18 小时前
MySQL 1366 - Incorrect string value:错误
android·数据库·mysql
恋猫de小郭18 小时前
Flutter 合并 ‘dot-shorthands‘ 语法糖,Dart 开始支持交叉编译
android·flutter·ios