学科分类
目录
Java Web

JDBC处理事务

在数据库操作中,一项事务是由一条或多条操作数据库的SQL语句组成的一个不可分割的工作单元。只有当事务中的所有操作都正常完成,整个事务才能被提交到数据库中,如果有一项操作没有完成,则整个事务会被撤销。例如,在银行的转账业务中,假定zhangsan从自己的账号上把200块钱转到lisi的账号里,相关的SQL语句如下:

UPDATE ACCOUNT set MONEY=MONEY-200 WHERE NAME='zhangsan';

UPDATE ACCOUNT set MONEY=MONEY+200 WHERE NAME='lisi';

在上述SQL语句中,它们只有全部执行成功,才能提交整个事务。否则,如果zhangsan账号的钱少了200,而lisi账号的钱没有变化,势必会造成银行转账业务的混乱。

针对JDBC处理事务的操作,在Connection接口中,提供了三个相关的方法,具体如下:

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

● commit():提交事务。

● rollback():撤销事务。

在上述三个方法中,默认情况下,事务是自动进行提交的。也就是说,如果每一条操作数据库的SQL语句执行成功,系统会自动调用commit()方法来提交事务,否则就自动调用rollback()撤销事务。

为了大家更好地学习JDBC如何处理事务,接下来,通过一个案例来模拟银行之间的转账业务,具体步骤如下:

(1)首先创建一个chapter02的数据库,并在该数据库中创建名称为account的表,向表中插入若干条数据,具体的SQL语句如下所示:

CREATE DATABASE chapter02;

USE chapter02;

CREATE TABLE account(

 id int primary key auto_increment,

 name varchar(40),

 money float

)character set utf8 collate utf8_general_ci;


INSERT INTO account(name,money) VALUES('aaa',1000);

INSERT INTO account(name,money) VALUES ('bbb',1000);

INSERT INTO account(name,money) VALUES ('ccc',1000);

上述SQL语句执行成功后,使用SELECT语句查询account表中的数据,SQL语句的执行结果如下:

mysql> SELECT * FROM account;

+----+------+-------+

| id | name | money |

+----+------+-------+

| 1 | aaa | 1000 |

| 2 | bbb | 1000 |

| 3 | ccc | 1000 |

+----+------+-------+

3 rows in set (0.00 sec)

从上述结果可以看出,account表存在三条数据,并且这三条数据的money值都为1000。

(2)新建工程chapter02,在工程中,新建一个类Example01,该类用于模拟两个账号之间的转账业务,Example01的具体实现代码如例1所示。

例1 Example01.java

 1  package cn.itcast.jdbc.example;

 2  import java.sql.Connection;

 3  import java.sql.PreparedStatement ;

 4  import java.sql.SQLException;

 5  import cn.itcast.utils.JDBCUtils;

 6  public class Example01{

 7    public static void main(String[] args) {

 8      String outAccount = "aaa";

 9      String inAccount = "bbb";

 10     double amount = 200;

 11     Connection conn = null;

 12     PreparedStatement pstmt1 = null;

 13     PreparedStatement pstmt2 = null;

 14     try {

 15       conn = JDBCUtils.getConnection();

 16       // 控制事务,关闭事务的自动提交

 17       conn.setAutoCommit(false);

 18       // 账号转出200

 19       String sql = "UPDATE account SET money = money-? WHERE "

 20           + "name=? AND money>=200";

 21       pstmt1 = conn.prepareStatement(sql);

 22       // 设置参数

 23       pstmt1.setDouble(1, amount);

 24       pstmt1.setString(2, outAccount);

 25       pstmt1.executeUpdate();

 26       // 账号转入200

 27       String sql2 = "update account set money=money+? where name=?";

 28       pstmt2 = conn.prepareStatement(sql2);

 29       pstmt2.setDouble(1, amount);

 30       pstmt2.setString(2, inAccount);

 31       pstmt2.executeUpdate();

 32       // 提交事务

 33       conn.commit();

 34       System.out.println("转账成功");

 35     } catch (Exception e) {

 36       // 回滚事务

 37       try {

 38         conn.rollback();

 39         System.out.println("转账失败");

 40       } catch (SQLException e1) {

 41         e1.printStackTrace();

 42       }

 43     } finally {

 44       if (pstmt1 != null) {

 45         try {

 46           pstmt1.close();

 47         } catch (SQLException e) {

 48           e.printStackTrace();

 49         }

 50         pstmt1 = null;

 51       }

 52       if (pstmt2 != null) {

 53         try {

 54           pstmt2.close();

 55         } catch (SQLException e) {

 56           e.printStackTrace();

 57         }

 58         pstmt2 = null;

 59       }

 60       if (conn != null) {

 61         try {

 62           conn.close();

 63         } catch (SQLException e) {

 64           e.printStackTrace();

 65         }

 66         conn = null;

 67       }

 68     }

 69   }

 70 }

程序运行后,会在控制台打印出“转账成功”的结果,这时,进入MySQL,使用SELECT语句查看当前的account表,SQL语句的执行结果如下:

mysql> SELECT * FROM account;

+----+------+-------+

| id | name | money |

+----+------+-------+

| 1 | aaa |  800 |

| 2 | bbb | 1200 |

| 3 | ccc | 1000 |

+----+------+-------+

3 rows in set (0.00 sec)

从上述执行结果可以看出,第一条数据的money值为800,第二条数据的money值为1200。由此可见,JDBC程序成功实现了转账功能。

需要注意的是,将setAutoCommit()方法的参数设置为false后,事务必须使用conn.commit()方法提交,而事务的回滚不一定显式执行conn.rollback()。如果程序最后没有执行conn.commit(),事务也会回滚,一般是直接抛出异常,终止程序的正常执行。因此,通常情况下,我们会将conn.rollback()语句放在catch语句块中执行。

点击此处
隐藏目录