JDBC中的事务-Transaction

Posted kuillldan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JDBC中的事务-Transaction相关的知识,希望对你有一定的参考价值。

事务-Transaction

某些情况下我们希望对数据库的某一操作要么整体成功,要么整体失败,经典的例子就是支付宝提现。例如我们发起了支付宝到银行卡的100元提现申请,我们希望的结果是支付宝余额减少100元,银行卡余额增加100元,而不是支付宝的100元被扣除,而银行卡的100元却没收到。也就是说,要么100元从支付宝扣除的同时银行卡也会多出一百元,要么这次提现失败支付宝的100元还在,银行卡也没有收到钱。支付宝扣钱和银行卡收钱,这两件事要么都成功要么都失败。

 

 

事物的ACID特性:

满足ACID特性的操作,我们可以说它是一个事物。

  1. 原子性:该操作是最小逻辑单元整体,已经不可分隔。
  2. 一致性:要么所有都执行,要么所有都不执行。
  3. 隔离性:多个事务相互隔离,互不影响。
  4. 持久性:事物的执行结果永久生效。

 

 

对事物的控制:

在JDBC中可以调用Connection对象的setAutoCommit(false)这个接口,将commit()之前的所有操作都看成是一个事物。同时,如果事务执行过程中发生异常,可以调用rollback()接口进行回滚到事务开始之前的状态。

 

 

示例代码:

下面代码演示了将cjk的100元转账到ly的账户上:

package org.lyk.main;

 

import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;

import org.apache.commons.dbcp2.BasicDataSource;

 

 

 

public class Main

{

       public static String DBDRIVER = "com.mysql.jdbc.Driver";

       public static String DB_URL = "jdbc:mysql://localhost:3306/mldn";

       public static String USERNAME = "root";

       public static String PASSWORD = "admin";

       public static BasicDataSource bds = null;

 

       public static void main(String[] args)

       {

              dbPoolInit();

              transferAmount();

              System.out.println("///Done~~~");

       }

 

       public static void dbPoolInit()

       {

              bds = new BasicDataSource();

              bds.setDriverClassName(DBDRIVER);

              bds.setUrl(DB_URL);

              bds.setUsername(USERNAME);

              bds.setPassword(PASSWORD);

       }

      

       public static boolean transferAmount()

       {

              boolean retVal = true;

             

              String sql = "UPDATE user SET amount=? WHERE userid=?";

              Connection conn = null;

              PreparedStatement stmt = null;

              ResultSet rs = null;

             

             

              try

              {

                     conn = bds.getConnection();

                     conn.setAutoCommit(false);

                     stmt = conn.prepareStatement(sql);

                     stmt.setInt(1, 0);

                     stmt.setString(2, "cjk");

                     stmt.execute();

                     stmt.setInt(1, 100);

                     stmt.setString(2, "ly");

                     stmt.execute();

                     conn.commit();

              } catch (SQLException e)

              {

                     // TODO Auto-generated catch block

                     e.printStackTrace();

                     try

                     {

                           conn.rollback();

                     } catch (SQLException e1)

                     {

                           // TODO Auto-generated catch block

                           e1.printStackTrace();

                     }

              }

              finally

              {

                     try

                     {

                           if(conn != null)

                                  conn.close();

                           if(stmt != null)

                                  stmt.close();

                           if(rs != null)

                                  rs.close();

                     }

                     catch(Exception e)

                     {

                           //ignore all exceptions when closing...

                     }

              }

             

             

              return retVal;

       }

}

 

 

事务断点(Savepoint):

某些时候,我们对一个事物操作失败,我们并不像回滚到最初状态,而是回滚到事务开始后的某一个地方,这时我们可以使用断点的方式让事物回滚到指定的断点(Savepoint)上.

示例代码:

下面的代码演示了如果cjk的100元转账到ly失败的话,我们将这100元转到cyx的账户上。(其中用手动跑出异常的方式模拟cjk到ly的转账失败)

package org.lyk.main;

 

import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;

import java.sql.Savepoint;

 

import org.apache.commons.dbcp2.BasicDataSource;

 

 

 

public class Main

{

      public static String DBDRIVER = "com.mysql.jdbc.Driver";

      public static String DB_URL = "jdbc:mysql://localhost:3306/mldn";

      public static String USERNAME = "root";

      public static String PASSWORD = "admin";

      public static BasicDataSource bds = null;

 

      public static void main(String[] args)

      {

            dbPoolInit();

            transferAmount();

            System.out.println("///Done~~~");

      }

 

      public static void dbPoolInit()

      {

            bds = new BasicDataSource();

            bds.setDriverClassName(DBDRIVER);

            bds.setUrl(DB_URL);

            bds.setUsername(USERNAME);

            bds.setPassword(PASSWORD);

      }

     

      public static boolean transferAmount()

      {

            boolean retVal = true;

           

            String sql = "UPDATE user SET amount=? WHERE userid=?";

            Connection conn = null;

            PreparedStatement stmt = null;

            ResultSet rs = null;

            Savepoint sp = null;

           

            try

            {

                  conn = bds.getConnection();

                 

                  conn.setAutoCommit(false);

                  stmt = conn.prepareStatement(sql);

                  stmt.setInt(1, 0);

                  stmt.setString(2, "cjk");

                  stmt.execute();

                  sp = conn.setSavepoint();

                 

                  stmt.setInt(1, 100);

                  stmt.setString(2, "ly");

                  stmt.execute();

                  throw new Exception();

            }

            catch (Exception e)

            {

                  e.printStackTrace();

                  try

                  {

                        conn.rollback(sp);

                        stmt.setInt(1, 100);

                        stmt.setString(2, "cyx");

                        stmt.execute();

                        conn.commit();

                  } catch (SQLException e1)

                  {

                        // TODO Auto-generated catch block

                        e1.printStackTrace();

                  }

            }

            finally

            {

                  try

                  {

                        if(conn != null)

                              conn.close();

                        if(stmt != null)

                              stmt.close();

                        if(rs != null)

                              rs.close();

                  }

                  catch(Exception e)

                  {

                        //ignore all exceptions when closing...

                  }

            }

           

           

            return retVal;

      }

}

 

以上是关于JDBC中的事务-Transaction的主要内容,如果未能解决你的问题,请参考以下文章

JDBC 中的事务和批处理 batch

Spring中的Jdbc事务管理

JDBC浅谈

JDBC事务处理&批量处理

如何处理 jdbc 事务中的父键约束?

多线程环境中的 JDBC 事务