JDBC事务管理


如果还不清楚什么是事务,可以先看一下MySQL事务管理(初步了解)这篇文章



cd4356
JDBC是Java数据库连接相关的API,所以Java的事务管理也是在通过该API进行的。JDBC的核心是Connection接口,JDBC的事务管理是基于Connection接口来实现的,通过Connection对象进行事务管理。

JDBC对事务的处理规则,必须是基于同一个Connection对象的

JDBC提供了3个方法来进行事务管理

  • setAutoCommit() 设置自动提交,方法中需要传入一个boolean类型的参数,true为自动提交,false为手动提交

  • commit() 提交事务

  • rollback() 回滚事务

JDBC默认的事务处理行为是自动提交。所以JDBC在进行事务管理时,首先要通过Connection对象调用setAutoCommit(false) 方法, 将SQL语句的提交(commit)由驱动程序转交给应用程序负责。并且调用setAutoCommit(false) 方法后,程序必须调用commit或者rollback方法,否则SQL语句不会被提交或回滚。

con.setAutoCommit();
// SQL语句
// SQL语句
// SQL语句
con.commit();或 con.rollback();


cd4356
JDBC提供了5中事务隔离级别,它们以常量的形式在Connection接口中定义,除了TRANSACTION_NONE外,其它4种隔离级别 与 MySQL的事务隔离级别一样。

  • TRANSACTION_NONE(不支持事务)

  • TRANSACTION_READ_UNCOMMITTED

  • TRANSACTION_READ_COMMITTED

  • TRANSACTION_REPEATABLE_READ

  • TRANSACTION_SERIALIZABLE

JDBC事务隔离级别可通过下面方法设置

  • getTransactionIsolation() 获取当前隔离级别

  • setTransactionIsolation() 设置隔离级别


给出Connection接口中部分关于事务方面的源码

package java.sql;

import java.sql.*;

public interface Connection  extends Wrapper, AutoCloseable {
    
    void setAutoCommit(boolean autoCommit) throws SQLException;
    
    boolean getAutoCommit() throws SQLException;
    
    void commit() throws SQLException;
    
    void rollback() throws SQLException;
    
    int TRANSACTION_NONE             = 0;
    int TRANSACTION_READ_UNCOMMITTED = 1;
    int TRANSACTION_READ_COMMITTED   = 2;
    int TRANSACTION_REPEATABLE_READ  = 4;
    int TRANSACTION_SERIALIZABLE     = 8;
    
    void setTransactionIsolation(int level) throws SQLException;
    
    int getTransactionIsolation() throws SQLException;
}



cd4356
设计数据库表
cd4356

drop database if exists database_transaction;
create database database_transaction;
use database_transaction;

/*===========================================*/

drop table if exists products;
create table products
(
   id	char(6) not null,
   title	varchar(20),
   price	double,
   stock	int,
   status	varchar(10),
   primary key (id)
);

insert into products values('100001','小米8',2699,100,'正常');
insert into products values('100002','小米8SE',1799,100,'正常');
insert into products values('100003','小米MIX2S',3299,100,'正常');
insert into products values('100004','小米手环3',199,100,'正常');

/*==order是MySQL的关键字,所以表名不能为order,应用orders==*/

drop table if exists orders;
create table orders
(
   id	char(6) not null,
   pid	char(6) not null,
   number		int,
   price                double,
   create_time          datetime,
   send_time            datetime,
   confirm_time	datetime,
   consignee	varchar(20),
   consignee_phone		char(11),
   consignee_address		varchar(100),
   status		varchar(10),
   primary key (id)
);

alter table orders add constraint fk_pid foreign key (pid) references products (id);

导入依赖jar包
<dependencies>
	
	<dependency>
	    <groupId>junit</groupId>
	    <artifactId>junit</artifactId>
	    <version>4.12</version>
	</dependency>
	
	<dependency>
	    <groupId>mysql</groupId>
	    <artifactId>mysql-connector-java</artifactId>
	    <version>5.1.47</version>
	</dependency>
</dependencies>


cd4356
不通过事务方式管理SQL语句。此时的SQL语句的提交(commit),是由驱动程序负责管理,在SQL执行完后,就会自动帮我们进行提交,每一条SQL都相当于一个事务。

但执行多条相关联SQL语句,而不通过事务来管理时。如果再某些步骤中中止或操作失误,就会破坏数据库的一致性。如下,由于没有通过事务SQL,若第二条修改商品库存的SQL执行失败,就会导致提交订单了,但商品库存不变。这种感觉就像是有限的商品却永远都卖不完,但这可能吗?

//创建连接
connection= DriverManager.getConnection(url,userName,password);
//创建Statement对象
Statement statement = connection.createStatement();
// 执行SQL
statement.execute("insert into orders values ('10021','100001',5,2699,now(),null ," +
        "null ,'王大傻','13535878996','广州番禺','待发货')");
statement.execute("update products set stock=stock-5 where id='100001'");
//关闭语句
statement.close();


所以,在操作多条相关联SQL时,需要通过事务来管理这些SQL,使它们作为一个原子性的工作单元(整体),要么全部执行,要么全部不执行,保证的数据库中数据的一致性。

//创建连接
connection= DriverManager.getConnection(url,userName,password);
//设置手动提交事务
connection.setAutoCommit(false);
//创建Statement对象
Statement statement = connection.createStatement();
// 执行SQL
statement.execute("insert into orders values ('10021','100001',5,2699,now(),null ," +
        "null ,'王大傻','13535878996','广州番禺','待发货')");
statement.execute("update products set stock=stock-5 where id='100001'");
//关闭语句
statement.close();
//提交事务
connection.commit();


完整代码(原本生成订单等…操作是放在业务层中进行的,但未了方便测试,就全部都简化到一个测试类中进行)

package com.cd4356.jdbc_transaction.dao;
import org.junit.Test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class OrderTest {
    private String driverClass="com.mysql.jdbc.Driver";
    private String url="jdbc:mysql://localhost:3306/database_transaction?useUnicode=true&characterEncoding=UTF8";
    private String userName="root";
    private String password="root";

    @Test
    public void addOrder(){
        try {
            //加载驱动
            Class.forName(driverClass);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        Connection connection=null;
        try {
            //创建连接
            connection= DriverManager.getConnection(url,userName,password);
            //设置手动提交事务
            connection.setAutoCommit(false);
            //创建Statement对象
            Statement statement = connection.createStatement();
            // 执行SQL    //now()表示当前时间
            statement.execute("insert into orders values ('10021','100001',5,2699,now(),null ," +
                    "null ,'王大傻','13535878996','广州番禺','待发货')"); 
            statement.execute("update products set stock=stock-5 where id='100001'");
            //关闭语句
            statement.close();
            //提交事务
            connection.commit();
        } catch (SQLException e) {
            e.printStackTrace();
            try {
                //遇到异常,则回滚事务
                connection.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        }finally {
            try {
                //关闭连接
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}


在运行测试前,先看一下数据库中,商品表和订单表的数据,订单表中暂无订单记录,商品表中有四种商品,且库存量均为100
cd4356

运行测试后,再查看一下数据库中,商品表和订单表的数据。此时,订单表中新增了一条订单记录(订购5件‘100001’号商品),商品表中‘100001’号商品的库存量相应的减少了5。

这就是使用事务管理SQL的好处,它保证的数据库中数据的一致性。避免某些操作失误,导致下了订单后,商品库存未做出相应修改,或者商品库存减少后,没有订单显示。
cd4356



前面的案例中,由于所有SQL语句都是正确的,所以看不出加事务管理不加事务管理的区别!

   将其中的一条SQL语句改错(比如将update products set stock=stock-5 where id='100001' 改成 update productsss set stock=stock-5 where id='100001'),然后分别在用加事务管理不加事务管理环境下进行测试,然后查商品表和订单表的数据,对比它们之间的区别,就可以清晰地看出用事务管理SQL的作用了。

  • 21
    点赞
  • 80
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
Java的JDBC事务是一种机制,用于控制数据库操作的一组相关操作,可以确保数据库的完整性和一致性。 JDBC事务需要通过以下步骤进行管理: 1. 打开数据库连接:在执行任何数据库操作之前,必须首先打开与数据库的连接。可以使用JDBC提供的DriverManager类的getConnection()方法来建立连接。 2. 开始事务:一旦连接成功建立,就可以开始事务。通过将连接的setAutoCommit()方法设置为false来禁用自动提交。 3. 执行数据库操作:在事务中,可以执行多个数据库操作(如插入、更新、删除等)。所有这些操作都将被视为一个原子操作,要么全部成功执行,要么全部回滚。 4. 提交事务:当所有数据库操作都成功执行时,可以通过调用连接的commit()方法来提交事务。这将导致所有在事务中进行的操作永久性地保存到数据库中。 5. 回滚事务:如果在事务中的任何操作失败或出现异常,可以通过调用连接的rollback()方法来回滚事务。这将导致在事务中发生的所有操作被撤消,数据库回到事务开始之前的状态。 6. 关闭连接:无论事务是提交还是回滚,都需要最终关闭与数据库的连接。这可以通过调用连接的close()方法来完成。 JDBC事务的好处包括:确保数据一致性,防止数据丢失或不一致;提高数据操作性能,通过将多个操作作为一个原子操作来减少网络开销;增加数据安全性,可以使用事务来保护敏感数据。 总的来说,JDBC事务是一种用于管理数据库操作的机制,可以确保数据库的完整性和一致性,并提供了多个操作的原子性,从而提高了数据的安全性和性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

家师曹先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值