JDBC 控制事务(MySQL为例)

事务

一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。

对事务的操作

  1. 开启事务
  2. 提交事务
  3. 回滚事务

使用Connection对象来管理事务

java.sql.Connection接口是一个数据库连接对象。它与特定数据库的连接(会话)。 执行SQL语句并在连接的上下文中返回结果。

  • 开启事务

    复制
    setAutoCommit(boolean autoCommit)
    // 调用该方法设置参数为false,即开启事务
  • 提交事务

    复制
    commit()
    // 当所有sql都执行完提交事务
  • 回滚事务

    复制
    rollback()
    // 在catch中回滚事务

Java代码举例

有如下一个MySQL数据表,利用Java程序:把id = 1对应的余额减少500,id = 2对应的余额增加500

复制
CREATE TABLE account (
id INT PRIMARY KEY AUTO_INCREMENT, -- id
NAME VARCHAR(10), -- 名字
balance DOUBLE -- 余额
);
INSERT INTO account (NAME, balance) VALUES ('LeeHua', 1000), ('Tom', 1000);

自定义一个注解,获取连接数据库的信息:

复制
package my.view.util;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE) // 注解能作用于类上
@Retention(RetentionPolicy.RUNTIME) // 当前被描述的注解,会保留到class字节码文件中,并被JVM读取到
public @interface PropertiesAnnotation {
/* URL */
public abstract String url();
/* 用户 */
public abstract String user();
/* 密码 */
public abstract String password();
/* 驱动包 */
public abstract String driver();
}

定义一个工具类,用来注册驱动和获取数据库连接对象:

复制
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
@PropertiesAnnotation(
url = "jdbc:mysql:///Study", user = "账号", password = "密码", driver = "com.mysql.jdbc.Driver"
)
public class JdbcUtils02 {
private static String url;
private static String user;
private static String password;
private static String driver;
/* 文件的读取,只需要读取一次即可拿到这些值。利用反射和注解、使用静态代码块 */
static{
// 读取资源文件,获取值。
try {
// 1. 解析注解
// 1.1 获取JdbcUtils02类的字节码文件对象
Class<JdbcUtils02> jdbcUtils02Class = JdbcUtils02.class;
// 2. 获取上边的注解对象
PropertiesAnnotation annotation = jdbcUtils02Class.getAnnotation(PropertiesAnnotation.class);
// 3. 调用注解中定义的抽象方法,获取返回值,赋值给静态成员变量
url = annotation.url();
user = annotation.user();
password = annotation.password();
driver = annotation.driver();
// 4. 注册驱动
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 获取连接
* @return 连接对象
*/
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, user, password);
}
}

有了以上条件,对数据表进行操作:

  1. 获取数据库连接

    复制
    Connection connection = JdbcUtils02.getConnection();
  2. 获取到数据库连接对象后,开启事务

    复制
    connection.setAutoCommit(false);
  3. 开启事务实际上是创建一个日志文件,将定义的SQL语句的执行结果暂时放到日记中,如果没有错,提交事务,如果出错,那么就回滚事务。接下来定义动态SQL语句

    复制
    String sql1 = "update account set balance = balance - ? where id = ?";
    String sql2 = "update account set balance = balance + ? where id = ?";
  4. 定义好了SQL语句,接下来就要获取执行动态SQL语句的对象

    复制
    PreparedStatement preparedStatement1 = connection.prepareStatement(sql1);
    PreparedStatement preparedStatement2 = connection.prepareStatement(sql2);
  5. 给动态SQL语句传入参数

    复制
    // LeeHua 的账户余额减少500元
    preparedStatement1.setDouble(1,500);
    preparedStatement1.setInt(2,1);
    // Tom 的账户余额增加500元
    preparedStatement2.setDouble(1,500);
    preparedStatement2.setInt(2,2);
  6. 一切准备就绪,这时候就可以执行SQL语句了

    复制
    preparedStatement1.executeUpdate();
    preparedStatement2.executeUpdate();
  7. 执行SQL语句后,如果没有错误,那么就提交事务,这时候的表记录就会更改

    复制
    connection.commit();
  8. 执行SQL语句后,如果有错误,那么就回滚事务,这个时候,会把日记中的记录删除,不会提交到表中,表的记录不会更改

    复制
    connection.rollback();
  9. 无论执行SQL语句,是否存在错误,最后都需要释放资源,调用自定义releaseResources()方法,释放资源

    复制
    releaseResources(preparedStatement2);
    releaseResources(preparedStatement1);
    releaseResources(connection);
  10. releaseResources()方法的定义如下:

    复制
    /**
    * 释放资源
    * @param t 要被释放的资源
    * @param <T> 要被释放的资源对象的类型
    */
    public static <T> void releaseResources (T t){
    if(t != null){
    try {
    // 利用反射,获取class对象
    Class<?> aClass = t.getClass();
    // 获取class对象中的方法对象
    Method close = aClass.getMethod("close");
    // 执行方法
    close.invoke(t);
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    }

对数据表进行操作的实现代码如下:

复制
package my.view.jdbc;
import my.view.util.JdbcUtils02;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class JdbcDemo09 {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement1 = null;
PreparedStatement preparedStatement2 = null;
try {
// 1. 获取连接
connection = JdbcUtils02.getConnection();
// 开启事务
connection.setAutoCommit(false);
// 2. 定义sql
// 2.1 定义减少账户余额的SQL语句
String sql1 = "update account set balance = balance - ? where id = ?";
// 2.2 定义增加账户余额的SQL语句
String sql2 = "update account set balance = balance + ? where id = ?";
// 3.获取执行SQL语句的对象
preparedStatement1 = connection.prepareStatement(sql1);
preparedStatement2 = connection.prepareStatement(sql2);
// 4. 设置参数
// 4.1 LeeHua 的账户余额减少500元
preparedStatement1.setDouble(1,500);
preparedStatement1.setInt(2,1);
// 4.2 Tom 的账户余额增加500元
preparedStatement2.setDouble(1,500);
preparedStatement2.setInt(2,2);
// 5. 执行SQL语句
preparedStatement1.executeUpdate();
preparedStatement2.executeUpdate();
// 6. 提交事务
connection.commit();
} catch (Exception e) {
// 7. 事务回滚
try {
if(connection != null) {
connection.rollback();
}
} catch (SQLException e1) {
e1.printStackTrace();
}
} finally {
// 8. 释放资源
releaseResources(preparedStatement2);
releaseResources(preparedStatement1);
releaseResources(connection);
}
}
/**
* 释放资源
* @param t 要被释放的资源
* @param <T> 要被释放的资源对象的类型
*/
public static <T> void releaseResources (T t){
if(t != null){
try {
// 利用反射,获取class对象
Class<?> aClass = t.getClass();
// 获取class对象中的方法对象
Method close = aClass.getMethod("close");
// 执行方法
close.invoke(t);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

运行程序,查看表中的记录,发现LeeHua的账号余额减少了500,Tom的账户余额增加了500。

posted @   LeeHua  阅读(608)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示