事务连接池
一、事务概述
(一)事务的定义
事务是数据库提供的一种特性,用于确保数据操作的完整性和一致性。事务将多个数据操作组合成一个逻辑单元,这些操作要么全部成功,要么全部失败。
(二)事务的特性(ACID)
-
原子性(Atomicity):事务中的所有操作要么全部成功,要么全部失败。
-
一致性(Consistency):事务执行前后,数据库的状态必须保持一致。
-
隔离性(Isolation):多个事务并发执行时,每个事务都好像在独立运行,互不干扰。
-
持久性(Durability):事务一旦提交,其对数据库的更改就是永久性的。
二、MySQL中的事务操作
(一)转账的例子
假设冠希给美美转1000元钱,这个操作需要确保以下两个步骤要么全部成功,要么全部失败:
-
从冠希的账户中扣除1000元。
-
给美美的账户加上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;
三、事务的隔离级别
(一)隔离级别概述
事务的隔离级别用于控制事务之间的隔离程度,以解决并发操作中可能出现的问题,如脏读、不可重复读和幻读。
(二)隔离级别分类
-
Read Uncommitted:最低的隔离级别,允许脏读。
-
Read Committed:避免脏读,但可能出现不可重复读。
-
Repeatable Read(默认级别):避免脏读和不可重复读,但可能出现幻读。
-
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();}}
}
五、数据库连接池
(一)连接池概述
数据库连接池是一种资源管理技术,用于高效管理和复用数据库连接。连接池预先创建一定数量的数据库连接,并在需要时将这些连接分配给请求者,使用完毕后归还到池中。
(二)连接池的优势
-
节省资源:避免频繁创建和销毁连接的开销。
-
提高性能:快速获取和释放连接,提高系统性能。
-
资源限制:限制同时打开的连接数量,避免过多的连接消耗过多的系统资源。
(三)常见的连接池
-
DBCP连接池:Apache开源组织提供的连接池。
-
C3P0连接池:开源的连接池。
-
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 TRANSACTION
、COMMIT
和ROLLBACK
命令操作事务。事务的隔离级别可以控制并发操作中的隔离程度,以解决脏读、不可重复读和幻读等问题。