您的当前位置:首页正文

JDBC中的事务-Transaction

2023-11-10 来源:好兔宠物网
事务-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

标签:

小编还为您整理了以下内容,可能对您也有帮助:

Hibernate 基于JDBC的事务

  Hibernate 是JDBC 的轻量级封装 本身并不具备事务管理能力 在事务管理层 Hibernate将其委托给底层的JDBC或者JTA 以实现事务管理和调度功能

  Hibernate的默认事务处理机制基于JDBC Transaction 我们也可以通过配置文件设定采用JTA作为事务管理实现

  Java代码

<hibernate configuration>    <session factory>    ……    <property name= hibernate transaction factory_class >    net sf hibernate transaction JTATransactionFactory    <! net sf hibernate transaction JDBCTransactionFactory >    </property>    ……    </session factory>    </hibernate configuration>  

  <hibernate configuration> <session factory> …… <property name= hibernate transaction factory_class > net sf hibernate transaction JTATransactionFactory <! net sf hibernate transaction JDBCTransactionFactory > </property> …… </session factory> </hibernate configuration>

基于JDBC的事务管理 将事务管理委托给JDBC 进行处理无疑是最简单的实现方式 Hibernate 对于JDBC事务的封装也极为简单 我们来看下面这段代码 Java代码 session = sessionFactory openSession();    Transaction tx = session beginTransaction();    ……    mit();  

  session = sessionFactory openSession(); Transaction tx = session beginTransaction(); …… mit();

从JDBC层面而言 上面的代码实际上对应着 Java代码 Connection dbconn = getConnection();    dbconn setAutoCommit(false);    ……    mit();  

  Connection dbconn = getConnection(); dbconn setAutoCommit(false); …… mit();

就是这么简单 Hibernate并没有做更多的事情(实际上也没法做更多的事情) 只是将这样的JDBC代码进行了封装而已 这里要注意的是 在sessionFactory openSession()中 hibernate会初始化数据库连接 与此同时 将其AutoCommit 设为关闭状态(false) 而其后 在Session beginTransaction 方法中 Hibernate 会再次确认Connection 的AutoCommit 属性被设为关闭状态( 为了防止用户代码对session 的Connection AutoCommit属性进行修改) 这也就是说 我们一开始从SessionFactory获得的session 其自动提交属性就已经被关闭(AutoCommit=false) 下面的代码将不会对数据库产生任何效果 Java代码 session = sessionFactory openSession();    session save(user);    session close();  

  session = sessionFactory openSession(); session save(user); session close();

这实际上相当于 JDBC Connection的AutoCommit属性被设为false 执行了若干JDBC操作之后 没有调用mit操作即将Connection关闭 如果要使代码真正作用到数据库 我们必须显式的调用Transaction指令 Java代码 session = sessionFactory openSession();    Transaction tx = session beginTransaction();    session save(user);    mit();    session close();  

  session = sessionFactory openSession(); Transaction tx = session beginTransaction(); session save(user); mit(); session close();

基于JTA的事务管理 JTA 提供了跨Session 的事务管理能力 这一点是与JDBC Transaction 最大的差异 JDBC事务由Connnection管理 也就是说 事务管理实际上是在JDBC Connection中实现 事务周期限于Connection的生命周期之类 同样 对于基于JDBC Transaction的Hibernate 事务管理机制而言 事务管理在Session 所依托的JDBC Connection中实现 事务周期限于Session的生命周期 JTA 事务管理则由 JTA 容器实现 JTA 容器对当前加入事务的众多Connection 进 行调度 实现其事务性要求 JTA的事务周期可横跨多个JDBC Connection生命周期 同样对于基于JTA事务的Hibernate而言 JTA事务横跨可横跨多个Session JTA 事务是由JTA Container 维护 而参与事务的Connection无需对事务管理进行干涉 这也就是说 如果采用JTA Transaction 我们不应该再调用HibernateTransaction功能 上面基于JDBC Transaction的正确代码 这里就会产生问题 Java代码 public class ClassA{    public void saveUser(User user){    session = sessionFactory openSession();    Transaction tx = session beginTransaction();    session save(user);    mit();    session close();    }    }    public class ClassB{    public void saveOrder(Order order){    session = sessionFactory openSession();    Transaction tx = session beginTransaction();    session save(order);    mit();    session close();    }    }    public class ClassC{    public void save(){    ……    UserTransaction tx = new InitialContext() lookup( …… );    ClassA save(user);    ClassB save(order);    mit();    ……    }    }  

  public class ClassA{ public void saveUser(User user){ session = sessionFactory openSession(); Transaction tx = session beginTransaction(); session save(user); mit(); session close(); } } public class ClassB{ public void saveOrder(Order order){ session = sessionFactory openSession(); Transaction tx = session beginTransaction(); session save(order); mit(); session close(); } } public class ClassC{ public void save(){ …… UserTransaction tx = new InitialContext() lookup( …… ); ClassA save(user); ClassB save(order); mit(); …… } }

这里有两个类ClassA和ClassB 分别提供了两个方法 saveUsersaveOrder 用于保存用户信息和订单信息 在ClassC中 我们接连调用了ClassA saveUser方法和ClassB saveOrder 方法 同时引入了JTA 中的UserTransaction 以实现ClassC save方法中的事务性 问题出现了 ClassA 和ClassB 中分别都调用了Hibernate 的Transaction 功能 在Hibernate 的JTA 封装中 Session beginTransaction 同样也执行了InitialContext lookup方法获取UserTransaction实例 mit方法同样也调用了mit方法 实际上 这就形成了两个嵌套式的JTA Transaction ClassC 申明了一个事务 而在ClassC 事务周期内 ClassA 和ClassB也企图申明自己的事务 这将导致运行期错误 因此 如果决定采用JTA Transaction 应避免再重复调用Hibernate 的 Transaction功能 上面的代码修改如下 Java代码 public class ClassA{    public void save(TUser user){    session = sessionFactory openSession();    session save(user);    session close();    }    ……    }    public class ClassB{    public void save (Order order){    session = sessionFactory openSession();    session save(order);    session close();    }    ……    }    public class ClassC{    public void save(){    ……    UserTransaction tx = new InitialContext() lookup( …… );    classA save(user);    classB save(order);    mit();    ……    }    }  

  public class ClassA{ public void save(TUser user){ session = sessionFactory openSession(); session save(user); session close(); } …… } public class ClassB{ public void save (Order order){ session = sessionFactory openSession(); session save(order); session close(); } …… } public class ClassC{ public void save(){ …… UserTransaction tx = new InitialContext() lookup( …… ); classA save(user); classB save(order); mit(); …… } }

上面代码中的ClassC save方法 也可以改成这样 Java代码 public class ClassC{    public void save(){    ……    session = sessionFactory openSession();    Transaction tx = session beginTransaction();    classA save(user);    classB save(order);    mit();    ……    }    }   实际上 这是利用Hibernate来完成启动和提交UserTransaction的功能 但这样的做法比原本直接通过InitialContext获取UserTransaction 的做法消耗了更多的资源 得不偿失 在EJB 中使用JTA Transaction 无疑最为简便 我们只需要将save 方法配置为JTA事务支持即可 无需显式申明任何事务 下面是一个Session Bean的save方法 它的事务属性被申明为 Required EJB容器将自动维护此方法执行过程中的事务 Java代码 /**   * @ejb interface method   * view type= remote   *   * @ejb transaction type =  Required   **/   public void save(){    //EJB环境中 通过部署配置即可实现事务申明 而无需显式调用事务    classA save(user);    classB save(log);    }//方法结束时 如果没有异常发生 则事务由EJB容器自动提交 lishixin/Article/program/Java/ky/201311/28740

Hibernate 基于JDBC的事务

  Hibernate 是JDBC 的轻量级封装 本身并不具备事务管理能力 在事务管理层 Hibernate将其委托给底层的JDBC或者JTA 以实现事务管理和调度功能

  Hibernate的默认事务处理机制基于JDBC Transaction 我们也可以通过配置文件设定采用JTA作为事务管理实现

  Java代码

<hibernate configuration>    <session factory>    ……    <property name= hibernate transaction factory_class >    net sf hibernate transaction JTATransactionFactory    <! net sf hibernate transaction JDBCTransactionFactory >    </property>    ……    </session factory>    </hibernate configuration>  

  <hibernate configuration> <session factory> …… <property name= hibernate transaction factory_class > net sf hibernate transaction JTATransactionFactory <! net sf hibernate transaction JDBCTransactionFactory > </property> …… </session factory> </hibernate configuration>

基于JDBC的事务管理 将事务管理委托给JDBC 进行处理无疑是最简单的实现方式 Hibernate 对于JDBC事务的封装也极为简单 我们来看下面这段代码 Java代码 session = sessionFactory openSession();    Transaction tx = session beginTransaction();    ……    mit();  

  session = sessionFactory openSession(); Transaction tx = session beginTransaction(); …… mit();

从JDBC层面而言 上面的代码实际上对应着 Java代码 Connection dbconn = getConnection();    dbconn setAutoCommit(false);    ……    mit();  

  Connection dbconn = getConnection(); dbconn setAutoCommit(false); …… mit();

就是这么简单 Hibernate并没有做更多的事情(实际上也没法做更多的事情) 只是将这样的JDBC代码进行了封装而已 这里要注意的是 在sessionFactory openSession()中 hibernate会初始化数据库连接 与此同时 将其AutoCommit 设为关闭状态(false) 而其后 在Session beginTransaction 方法中 Hibernate 会再次确认Connection 的AutoCommit 属性被设为关闭状态( 为了防止用户代码对session 的Connection AutoCommit属性进行修改) 这也就是说 我们一开始从SessionFactory获得的session 其自动提交属性就已经被关闭(AutoCommit=false) 下面的代码将不会对数据库产生任何效果 Java代码 session = sessionFactory openSession();    session save(user);    session close();  

  session = sessionFactory openSession(); session save(user); session close();

这实际上相当于 JDBC Connection的AutoCommit属性被设为false 执行了若干JDBC操作之后 没有调用mit操作即将Connection关闭 如果要使代码真正作用到数据库 我们必须显式的调用Transaction指令 Java代码 session = sessionFactory openSession();    Transaction tx = session beginTransaction();    session save(user);    mit();    session close();  

  session = sessionFactory openSession(); Transaction tx = session beginTransaction(); session save(user); mit(); session close();

基于JTA的事务管理 JTA 提供了跨Session 的事务管理能力 这一点是与JDBC Transaction 最大的差异 JDBC事务由Connnection管理 也就是说 事务管理实际上是在JDBC Connection中实现 事务周期限于Connection的生命周期之类 同样 对于基于JDBC Transaction的Hibernate 事务管理机制而言 事务管理在Session 所依托的JDBC Connection中实现 事务周期限于Session的生命周期 JTA 事务管理则由 JTA 容器实现 JTA 容器对当前加入事务的众多Connection 进 行调度 实现其事务性要求 JTA的事务周期可横跨多个JDBC Connection生命周期 同样对于基于JTA事务的Hibernate而言 JTA事务横跨可横跨多个Session JTA 事务是由JTA Container 维护 而参与事务的Connection无需对事务管理进行干涉 这也就是说 如果采用JTA Transaction 我们不应该再调用HibernateTransaction功能 上面基于JDBC Transaction的正确代码 这里就会产生问题 Java代码 public class ClassA{    public void saveUser(User user){    session = sessionFactory openSession();    Transaction tx = session beginTransaction();    session save(user);    mit();    session close();    }    }    public class ClassB{    public void saveOrder(Order order){    session = sessionFactory openSession();    Transaction tx = session beginTransaction();    session save(order);    mit();    session close();    }    }    public class ClassC{    public void save(){    ……    UserTransaction tx = new InitialContext() lookup( …… );    ClassA save(user);    ClassB save(order);    mit();    ……    }    }  

  public class ClassA{ public void saveUser(User user){ session = sessionFactory openSession(); Transaction tx = session beginTransaction(); session save(user); mit(); session close(); } } public class ClassB{ public void saveOrder(Order order){ session = sessionFactory openSession(); Transaction tx = session beginTransaction(); session save(order); mit(); session close(); } } public class ClassC{ public void save(){ …… UserTransaction tx = new InitialContext() lookup( …… ); ClassA save(user); ClassB save(order); mit(); …… } }

这里有两个类ClassA和ClassB 分别提供了两个方法 saveUsersaveOrder 用于保存用户信息和订单信息 在ClassC中 我们接连调用了ClassA saveUser方法和ClassB saveOrder 方法 同时引入了JTA 中的UserTransaction 以实现ClassC save方法中的事务性 问题出现了 ClassA 和ClassB 中分别都调用了Hibernate 的Transaction 功能 在Hibernate 的JTA 封装中 Session beginTransaction 同样也执行了InitialContext lookup方法获取UserTransaction实例 mit方法同样也调用了mit方法 实际上 这就形成了两个嵌套式的JTA Transaction ClassC 申明了一个事务 而在ClassC 事务周期内 ClassA 和ClassB也企图申明自己的事务 这将导致运行期错误 因此 如果决定采用JTA Transaction 应避免再重复调用Hibernate 的 Transaction功能 上面的代码修改如下 Java代码 public class ClassA{    public void save(TUser user){    session = sessionFactory openSession();    session save(user);    session close();    }    ……    }    public class ClassB{    public void save (Order order){    session = sessionFactory openSession();    session save(order);    session close();    }    ……    }    public class ClassC{    public void save(){    ……    UserTransaction tx = new InitialContext() lookup( …… );    classA save(user);    classB save(order);    mit();    ……    }    }  

  public class ClassA{ public void save(TUser user){ session = sessionFactory openSession(); session save(user); session close(); } …… } public class ClassB{ public void save (Order order){ session = sessionFactory openSession(); session save(order); session close(); } …… } public class ClassC{ public void save(){ …… UserTransaction tx = new InitialContext() lookup( …… ); classA save(user); classB save(order); mit(); …… } }

上面代码中的ClassC save方法 也可以改成这样 Java代码 public class ClassC{    public void save(){    ……    session = sessionFactory openSession();    Transaction tx = session beginTransaction();    classA save(user);    classB save(order);    mit();    ……    }    }   实际上 这是利用Hibernate来完成启动和提交UserTransaction的功能 但这样的做法比原本直接通过InitialContext获取UserTransaction 的做法消耗了更多的资源 得不偿失 在EJB 中使用JTA Transaction 无疑最为简便 我们只需要将save 方法配置为JTA事务支持即可 无需显式申明任何事务 下面是一个Session Bean的save方法 它的事务属性被申明为 Required EJB容器将自动维护此方法执行过程中的事务 Java代码 /**   * @ejb interface method   * view type= remote   *   * @ejb transaction type =  Required   **/   public void save(){    //EJB环境中 通过部署配置即可实现事务申明 而无需显式调用事务    classA save(user);    classB save(log);    }//方法结束时 如果没有异常发生 则事务由EJB容器自动提交 lishixin/Article/program/Java/ky/201311/28740

Jdbc中是否支持事务,如果支持包含了哪些

  • import java.io.IOException;  
  • import java.sql.Connection;  
  • import java.sql.SQLException;  
  • import java.util.Properties;  
  • import javax.sql.DataSource;  
  • import com.mchange.v2.c3p0.DataSources;  
  • import com.tjitcast.dao.DaoException;  
  • /** 
  •  *  数据库工具类 
  •  *  可以根据classpath下配置文件jdbc.properties中配置的参数来获取数据库连接并绑定到当前线程上 
  •  *  可以获取JDBC的事务管理器 
  •  * @author qiujy 
  •  * @version 0.9Beta 
  •  */  
  • public class DbUtils {  
  •     private static Properties prop = new Properties();  
  •     /** 数据源 */  
  •     private static DataSource ds = null;   
  •       
  •     //用来把Connection绑定到当前线程上的变量  
  •     private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();  
  •     static{  
  •         try {  
  •             prop.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("jdbc.properties"));  
  •         } catch (IOException e) {  
  •             e.printStackTrace();  
  •             System.out.println("在classpath下没有找到jdbc.properties文件");  
  •         }  
  •           
  •         //使用C3P0连接池技术  
  •         try {  
  •             Class.forName("com.mysql.jdbc.Driver");  
  •               
  •             DataSource unpooled = DataSources.unpooledDataSource(  
  •                     prop.getProperty("url"),  
  •                     prop.getProperty("user"),  
  •                     prop.getProperty("password"));  
  •             ds = DataSources.pooledDataSource(unpooled);  
  •               
  •         } catch (ClassNotFoundException e) {  
  •             e.printStackTrace();  
  •         } catch (SQLException e) {  
  •             e.printStackTrace();  
  •         }  
  •     }  
  •       
  •     private DbUtils(){}  
  •       
  •     /** 
  •      * 根据数据库的默认连接参数获取数据库的Connection对象,并绑定到当前线程上 
  •      * @return 成功,返回Connection对象,否则返回null 
  •      */  
  •     public static synchronized Connection getConnection(){  
  •         Connection conn = tl.get(); //先从当前线程上取出连接实例  
  •           
  •         if(null == conn){ //如果当前线程上没有Connection的实例   
  •             try {  
  •                 conn = ds.getConnection(); // 从连接池中取出一个连接实例   
  •                 tl.set(conn);  //把它绑定到当前线程上  
  •             } catch (SQLException e) {  
  •                 e.printStackTrace();  
  •             }  
  •         }  
  •         return conn;  
  •     }  
  •     /** 
  •      * 获取事务管理器 
  •      * @return 事务管理实例 
  •      */  
  •     public static synchronized TransactionManager getTranManager(){  
  •         return new TransactionManager(getConnection());  
  •     }  
  •       
  •     /** 
  •      * 关闭数据库连接,并卸装线程绑定 
  •      * @param conn 要关闭数据库连接实例 
  •      * @throws DaoException  
  •      */  
  •     protected static void close(Connection conn) throws DaoException{  
  •         if(conn != null){  
  •             try {  
  •                 conn.close();  
  •             } catch (SQLException e) {  
  •                 throw new DaoException("关闭连接时出现异常",e);  
  •             } finally {  
  •                     tl.remove(); //卸装线程绑定  
  •             }  
  •         }  
  •     }  
  •       
  • }  
  •  

     

    如下事务管理器类:

     

    [java] view plaincopy 
    1. package com.tjitcast.common;  
    2. import java.sql.Connection;  
    3. import java.sql.SQLException;  
    4. import com.tjitcast.dao.DaoException;  
    5. /** 
    6.  * 事务管理器 
    7.  * @author qiujy 
    8.  * @version 0.9Beta 
    9.  */  
    10. public class TransactionManager {  
    11.     private Connection conn;  
    12.       
    13.     protected TransactionManager(Connection conn) {  
    14.         this.conn = conn;  
    15.     }  
    16.       
    17.     /** 开启事务 */  
    18.     public void beginTransaction() throws DaoException{  
    19.         try {  
    20.             conn.setAutoCommit(false);  //把事务提交方式改为手工提交  
    21.         } catch (SQLException e) {  
    22.             throw new DaoException("开户事务时出现异常",e);  
    23.         }  
    24.     }  
    25.       
    26.     /** 提交事务并关闭连接 */  
    27.     public void commitAndClose() throws DaoException{  
    28.         try {  
    29.             conn.commit(); //提交事务  
    30.         } catch (SQLException e) {  
    31.             throw new DaoException("提交事务时出现异常",e);  
    32.         }finally{  
    33.             DbUtils.close(conn);  
    34.         }  
    35.     }  
    36.       
    37.     /** 回滚并关闭连接 */  
    38.     public void rollbackAndClose()throws DaoException{  
    39.         try {  
    40.             conn.rollback();  
    41.         } catch (SQLException e) {  
    42.             throw new DaoException("回滚事务时出现异常",e);  
    43.         }finally{  
    44.             DbUtils.close(conn);  
    45.         }  
    46.     }  
    47. }  

     

     

    如下业务层类:

     

    [java] view plaincopy 
    1. package com.tjitcast.service;  
    2. import java.util.List;  
    3. import com.tjitcast.common.DbUtils;  
    4. import com.tjitcast.common.TransactionManager;  
    5. import com.tjitcast.dao.DaoException;  
    6. import com.tjitcast.dao.DaoFactory;  
    7. import com.tjitcast.dao.DeptDao;  
    8. import com.tjitcast.dao.EmployeeDao;  
    9. import com.tjitcast.entity.Dept;  
    10. import com.tjitcast.entity.Employee;  
    11. import com.tjitcast.entity.PageModel;  
    12. /** 
    13.  * 业务层门面  --> 添加事务控制 
    14.  * @author qiujy 
    15.  */  
    16. public class ServiceFacade {  
    17.     private DeptDao deptDao = DaoFactory.getInstance("deptDao", DeptDao.class);  
    18.     private EmployeeDao empDao  = DaoFactory.getInstance("empDao", EmployeeDao.class);  
    19.       
    20.     /** 
    21.      * 新增部门 
    22.      * @param dept 
    23.      */  
    24.     public void insertDept(Dept dept){  
    25.         TransactionManager tx = DbUtils.getTranManager();  
    26.         try{  
    27.             tx.beginTransaction();  
    28.               
    29.             deptDao.insert(dept);  
    30.               
    31.             tx.commitAndClose();  
    32.         }catch (DaoException e) {  
    33.             tx.rollbackAndClose();  
    34.         }  
    35.     }  
    36.       
    37.     /** 
    38.      * 新增员工 
    39.      * @param emp 员工 
    40.      */  
    41.     public void insertEmp(Employee emp){  
    42.         TransactionManager tx = DbUtils.getTranManager();  
    43.         try{  
    44.             tx.beginTransaction();  
    45.               
    46.             empDao.insert(emp);  
    47.               
    48.             tx.commitAndClose();  
    49.         }catch (DaoException e) {  
    50.             tx.rollbackAndClose();  
    51.         }  
    52.     }  
    53.       
    54.     /** 
    55.      * 获取所有部门的列表 
    56.      * @return 部门列表 
    57.      */  
    58.     public List<Dept> getDeptList(){  
    59.         List<Dept> list = null;  
    60.           
    61.         TransactionManager tx = DbUtils.getTranManager();  
    62.         try{  
    63.             tx.beginTransaction();  
    64.               
    65.             list = deptDao.getDeptList();  
    66.               
    67.             tx.commitAndClose();  
    68.         }catch (DaoException e) {  
    69.             e.printStackTrace();  
    70.             tx.rollbackAndClose();  
    71.         }  
    72.           
    73.         return list;  
    74.     }  
    75.       
    76.     /** 
    77.      * 获取指定部门下的员工分页列表 
    78.      * @param deptId 
    79.      * @param pageNo 
    80.      * @param pageSize 
    81.      * @return 符合条件的PageModel 
    82.      */  
    83.     public PageModel<Employee> getEmpListByDeptId(int deptId, int pageNo, int pageSize){  
    84.         PageModel<Employee> pm = null;   
    85.         TransactionManager tx = DbUtils.getTranManager();  
    86.         try{  
    87.             tx.beginTransaction();  
    88.               
    89.             pm = empDao.getEmpListByDeptId(deptId, pageNo, pageSize);  
    90.               
    91.             tx.commitAndClose();  
    92.         }catch (DaoException e) {  
    93.             tx.rollbackAndClose();  
    94.         }  
    95.         return pm;  
    96.     }  
    97.       
    98.     /** 
    99.      * 删除指定ID的部门 
    100.      * @param id 部门ID 
    101.      */  
    102.     public void deleteDept(int id){  
    103.           
    104.         TransactionManager tx = DbUtils.getTranManager();  
    105.         try{  
    106.             tx.beginTransaction();  
    107.               
    108.             empDao.deleteByDeptId(id); //先删除指定ID部门下的所有员工  
    109.             deptDao.delete(id);  //再删除该部门  
    110.               
    111.             tx.commitAndClose();  
    112.         }catch (DaoException e) {  
    113.             tx.rollbackAndClose();  
    114.         }  
    115.     }  
    116. }  

     

     

    具体的示例代码结构如下(Eclipse工程):

    技术分享

    分层架构下的纯JDBC事务控制简单解决方案【转】

    标签:

    Jdbc中是否支持事务,如果支持包含了哪些

  • import java.io.IOException;  
  • import java.sql.Connection;  
  • import java.sql.SQLException;  
  • import java.util.Properties;  
  • import javax.sql.DataSource;  
  • import com.mchange.v2.c3p0.DataSources;  
  • import com.tjitcast.dao.DaoException;  
  • /** 
  •  *  数据库工具类 
  •  *  可以根据classpath下配置文件jdbc.properties中配置的参数来获取数据库连接并绑定到当前线程上 
  •  *  可以获取JDBC的事务管理器 
  •  * @author qiujy 
  •  * @version 0.9Beta 
  •  */  
  • public class DbUtils {  
  •     private static Properties prop = new Properties();  
  •     /** 数据源 */  
  •     private static DataSource ds = null;   
  •       
  •     //用来把Connection绑定到当前线程上的变量  
  •     private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();  
  •     static{  
  •         try {  
  •             prop.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("jdbc.properties"));  
  •         } catch (IOException e) {  
  •             e.printStackTrace();  
  •             System.out.println("在classpath下没有找到jdbc.properties文件");  
  •         }  
  •           
  •         //使用C3P0连接池技术  
  •         try {  
  •             Class.forName("com.mysql.jdbc.Driver");  
  •               
  •             DataSource unpooled = DataSources.unpooledDataSource(  
  •                     prop.getProperty("url"),  
  •                     prop.getProperty("user"),  
  •                     prop.getProperty("password"));  
  •             ds = DataSources.pooledDataSource(unpooled);  
  •               
  •         } catch (ClassNotFoundException e) {  
  •             e.printStackTrace();  
  •         } catch (SQLException e) {  
  •             e.printStackTrace();  
  •         }  
  •     }  
  •       
  •     private DbUtils(){}  
  •       
  •     /** 
  •      * 根据数据库的默认连接参数获取数据库的Connection对象,并绑定到当前线程上 
  •      * @return 成功,返回Connection对象,否则返回null 
  •      */  
  •     public static synchronized Connection getConnection(){  
  •         Connection conn = tl.get(); //先从当前线程上取出连接实例  
  •           
  •         if(null == conn){ //如果当前线程上没有Connection的实例   
  •             try {  
  •                 conn = ds.getConnection(); // 从连接池中取出一个连接实例   
  •                 tl.set(conn);  //把它绑定到当前线程上  
  •             } catch (SQLException e) {  
  •                 e.printStackTrace();  
  •             }  
  •         }  
  •         return conn;  
  •     }  
  •     /** 
  •      * 获取事务管理器 
  •      * @return 事务管理实例 
  •      */  
  •     public static synchronized TransactionManager getTranManager(){  
  •         return new TransactionManager(getConnection());  
  •     }  
  •       
  •     /** 
  •      * 关闭数据库连接,并卸装线程绑定 
  •      * @param conn 要关闭数据库连接实例 
  •      * @throws DaoException  
  •      */  
  •     protected static void close(Connection conn) throws DaoException{  
  •         if(conn != null){  
  •             try {  
  •                 conn.close();  
  •             } catch (SQLException e) {  
  •                 throw new DaoException("关闭连接时出现异常",e);  
  •             } finally {  
  •                     tl.remove(); //卸装线程绑定  
  •             }  
  •         }  
  •     }  
  •       
  • }  
  •  

     

    如下事务管理器类:

     

    [java] view plaincopy 
    1. package com.tjitcast.common;  
    2. import java.sql.Connection;  
    3. import java.sql.SQLException;  
    4. import com.tjitcast.dao.DaoException;  
    5. /** 
    6.  * 事务管理器 
    7.  * @author qiujy 
    8.  * @version 0.9Beta 
    9.  */  
    10. public class TransactionManager {  
    11.     private Connection conn;  
    12.       
    13.     protected TransactionManager(Connection conn) {  
    14.         this.conn = conn;  
    15.     }  
    16.       
    17.     /** 开启事务 */  
    18.     public void beginTransaction() throws DaoException{  
    19.         try {  
    20.             conn.setAutoCommit(false);  //把事务提交方式改为手工提交  
    21.         } catch (SQLException e) {  
    22.             throw new DaoException("开户事务时出现异常",e);  
    23.         }  
    24.     }  
    25.       
    26.     /** 提交事务并关闭连接 */  
    27.     public void commitAndClose() throws DaoException{  
    28.         try {  
    29.             conn.commit(); //提交事务  
    30.         } catch (SQLException e) {  
    31.             throw new DaoException("提交事务时出现异常",e);  
    32.         }finally{  
    33.             DbUtils.close(conn);  
    34.         }  
    35.     }  
    36.       
    37.     /** 回滚并关闭连接 */  
    38.     public void rollbackAndClose()throws DaoException{  
    39.         try {  
    40.             conn.rollback();  
    41.         } catch (SQLException e) {  
    42.             throw new DaoException("回滚事务时出现异常",e);  
    43.         }finally{  
    44.             DbUtils.close(conn);  
    45.         }  
    46.     }  
    47. }  

     

     

    如下业务层类:

     

    [java] view plaincopy 
    1. package com.tjitcast.service;  
    2. import java.util.List;  
    3. import com.tjitcast.common.DbUtils;  
    4. import com.tjitcast.common.TransactionManager;  
    5. import com.tjitcast.dao.DaoException;  
    6. import com.tjitcast.dao.DaoFactory;  
    7. import com.tjitcast.dao.DeptDao;  
    8. import com.tjitcast.dao.EmployeeDao;  
    9. import com.tjitcast.entity.Dept;  
    10. import com.tjitcast.entity.Employee;  
    11. import com.tjitcast.entity.PageModel;  
    12. /** 
    13.  * 业务层门面  --> 添加事务控制 
    14.  * @author qiujy 
    15.  */  
    16. public class ServiceFacade {  
    17.     private DeptDao deptDao = DaoFactory.getInstance("deptDao", DeptDao.class);  
    18.     private EmployeeDao empDao  = DaoFactory.getInstance("empDao", EmployeeDao.class);  
    19.       
    20.     /** 
    21.      * 新增部门 
    22.      * @param dept 
    23.      */  
    24.     public void insertDept(Dept dept){  
    25.         TransactionManager tx = DbUtils.getTranManager();  
    26.         try{  
    27.             tx.beginTransaction();  
    28.               
    29.             deptDao.insert(dept);  
    30.               
    31.             tx.commitAndClose();  
    32.         }catch (DaoException e) {  
    33.             tx.rollbackAndClose();  
    34.         }  
    35.     }  
    36.       
    37.     /** 
    38.      * 新增员工 
    39.      * @param emp 员工 
    40.      */  
    41.     public void insertEmp(Employee emp){  
    42.         TransactionManager tx = DbUtils.getTranManager();  
    43.         try{  
    44.             tx.beginTransaction();  
    45.               
    46.             empDao.insert(emp);  
    47.               
    48.             tx.commitAndClose();  
    49.         }catch (DaoException e) {  
    50.             tx.rollbackAndClose();  
    51.         }  
    52.     }  
    53.       
    54.     /** 
    55.      * 获取所有部门的列表 
    56.      * @return 部门列表 
    57.      */  
    58.     public List<Dept> getDeptList(){  
    59.         List<Dept> list = null;  
    60.           
    61.         TransactionManager tx = DbUtils.getTranManager();  
    62.         try{  
    63.             tx.beginTransaction();  
    64.               
    65.             list = deptDao.getDeptList();  
    66.               
    67.             tx.commitAndClose();  
    68.         }catch (DaoException e) {  
    69.             e.printStackTrace();  
    70.             tx.rollbackAndClose();  
    71.         }  
    72.           
    73.         return list;  
    74.     }  
    75.       
    76.     /** 
    77.      * 获取指定部门下的员工分页列表 
    78.      * @param deptId 
    79.      * @param pageNo 
    80.      * @param pageSize 
    81.      * @return 符合条件的PageModel 
    82.      */  
    83.     public PageModel<Employee> getEmpListByDeptId(int deptId, int pageNo, int pageSize){  
    84.         PageModel<Employee> pm = null;   
    85.         TransactionManager tx = DbUtils.getTranManager();  
    86.         try{  
    87.             tx.beginTransaction();  
    88.               
    89.             pm = empDao.getEmpListByDeptId(deptId, pageNo, pageSize);  
    90.               
    91.             tx.commitAndClose();  
    92.         }catch (DaoException e) {  
    93.             tx.rollbackAndClose();  
    94.         }  
    95.         return pm;  
    96.     }  
    97.       
    98.     /** 
    99.      * 删除指定ID的部门 
    100.      * @param id 部门ID 
    101.      */  
    102.     public void deleteDept(int id){  
    103.           
    104.         TransactionManager tx = DbUtils.getTranManager();  
    105.         try{  
    106.             tx.beginTransaction();  
    107.               
    108.             empDao.deleteByDeptId(id); //先删除指定ID部门下的所有员工  
    109.             deptDao.delete(id);  //再删除该部门  
    110.               
    111.             tx.commitAndClose();  
    112.         }catch (DaoException e) {  
    113.             tx.rollbackAndClose();  
    114.         }  
    115.     }  
    116. }  

     

     

    具体的示例代码结构如下(Eclipse工程):

    技术分享

    分层架构下的纯JDBC事务控制简单解决方案【转】

    标签:

    Java语言(事务是什么?)跟事务有关的两个问题。(答得好考虑加分)

    1.事务就是由几个步骤组成的业务操作,要么全部成功,要么全部失败。

    2.JDBC中就是把事务设置为手动提交,等完成多个操作后,进行一次性提交。

    3.要在Hibernate中使用事务,可以配置Hibernate事务为JDBCTransaction或者JTATransaction,这两种事务的生命周期不一样,可以在hibernate.cfg.xml中指定使用的是哪一种事务。以下配置为使用JDBC事务。注:如果不进行配置,Hibernate也会默认使用JDBC事务。

    <session-factory>

    ……

    <property name="hibernate.transaction.factory_class">

    org.hibernate.transaction.JDBCTransactionFactory

    </property>

    ……

    </session-factory>

    Hibernate 使用JDBC transaction处理方式如下所示:

    Transaction tx = null;

    try {

    tx = sess.beginTransaction();

    // do some work

    ...

    tx.commit();

    }

    catch (RuntimeException e) {

    if (tx != null) tx.rollback();

    throw e; // or display error message

    }

    finally {

    sess.close();

    }

    JTA(java Transaction API)是事务服务的JavaEE解决方案。本质上,它是描述事务接口的JavaEE模型的一部分。

    JTA具有的3个接口:UserTransaction接口、TransactionManager接口和Transaction接口,这些接口共享公共的事务操作。UserTransaction能够执行事务划分和基本的事务操作,TransactionManager能够执行上下文管理。

    在一个具有多个数据库的系统中,可能一个程序将会调用几个数据库中的数据,需要一种分布事务,或者准备用JTA来管理Session的长事务,那么就需要使用JTATransaction。

    在hibernate.cfg.xml中配置JTA事务管理:

    <session-factory>

    ……

    <property name="hibernate.transaction.factory_class">

    org.hibernate.transaction.JTATransactionFactory

    </property>

    ……

    </session-factory>

    下面是一个实际应用的JTA示例:

    // BMT(bean管理事务) idiom with getCurrentSession()

    try {

    UserTransaction tx = (UserTransaction)new InitialContext()

    .lookup("java:comp/UserTransaction");

    tx.begin();

    // Do some work on Session bound to transaction

    factory.getCurrentSession().load(...);

    factory.getCurrentSession().persist(...);

    tx.commit();

    }

    catch (RuntimeException e) {

    tx.rollback();

    throw e; // or display error message

    }

    4.声明式事务处理通过AOP的实现把事物管理代码作为方面封装来横向插入到业务代码中,使得事务管理代码和业务代码解藕。

    java 事务

    Java中的事务处理

    一般情况下,J2EE应用服务器支持JDBC事务、JTA(Java Transaction API)事务、容器管理事务。一般情况下,最好不要在程序中同时使用上述三种事务类型,比如在JTA事务中嵌套JDBC事务。第二方面,事务要在尽可能短的时间内完成,不要在不同方法中实现事务的使用。下面我们列举两种事务处理方式。

    1、JavaBean中使用JDBC方式进行事务处理

    在JDBC中怎样将多个SQL语句组合成一个事务呢?在JDBC中,打开一个连接对象Connection时,缺省是auto-commit模式,每个SQL语句都被当作一个事务,即每次执行一个语句,都会自动的得到事务确认。为了能将多个SQL语句组合成一个事务,要将auto-commit模式屏蔽掉。在auto-commit模式屏蔽掉之后,如果不调用commit()方法,SQL语句不会得到事务确认。在最近一次commit()方法调用之后的所有SQL会在方法commit()调用时得到确认。

    public int delete(int sID) {

    dbc = new DataBaseConnection();

    Connection con = dbc.getConnection();

    try {

    con.setAutoCommit(false);// 更改JDBC事务的默认提交方式

    dbc.executeUpdate("delete from bylaw where ID=" + sID);

    dbc.executeUpdate("delete from bylaw _content where ID=" + sID);

    dbc.executeUpdate("delete from bylaw _affix where bylawid=" + sID);

    con.commit();//提交JDBC事务

    con.setAutoCommit(true);// 恢复JDBC事务的默认提交方式

    dbc.close();

    return 1;

    }

    catch (Exception exc) {

    con.rollBack();//回滚JDBC事务

    exc.printStackTrace();

    dbc.close();

    return -1;

    }

    }

    2、SessionBean中的JTA事务

    JTA 是事务服务的 J2EE 解决方案。本质上,它是描述事务接口(比如 UserTransaction 接口,开发人员直接使用该接口或者通过 J2EE 容器使用该接口来确保业务逻辑能够可靠地运行)的 J2EE 模型的一部分。JTA 具有的三个主要的接口分别是 UserTransaction 接口、TransactionManager 接口和 Transaction 接口。这些接口共享公共的事务操作,例如 commit() 和 rollback(), 但是也包含特殊的事务操作,例如 suspend(),resume() 和 enlist(),它们只出现在特定的接口上,以便在实现中允许一定程度的访问控制。例如,UserTransaction 能够执行事务划分和基本的事务操作,而 TransactionManager 能够执行上下文管理。

    应用程序可以调用UserTransaction.begin()方法开始一个事务,该事务与应用程序正在其中运行的当前线程相关联。底层的事务管理器实际处理线程与事务之间的关联。UserTransaction.commit()方法终止与当前线程关联的事务。UserTransaction.rollback()方法将放弃与当前线程关联的当前事务。

    public int delete(int sID) {

    DataBaseConnection dbc = null;

    dbc = new DataBaseConnection();

    dbc.getConnection();

    UserTransaction transaction = sessionContext.getUserTransaction();//获得JTA事务

    try {

    transaction.begin(); //开始JTA事务

    dbc.executeUpdate("delete from bylaw where ID=" + sID);

    dbc.executeUpdate("delete from bylaw _content where ID=" + sID);

    dbc.executeUpdate("delete from bylaw _affix where bylawid=" + sID);

    transaction.commit(); //提交JTA事务

    dbc.close();

    return 1;

    }

    catch (Exception exc) {

    try {

    transaction.rollback();//JTA事务回滚

    }

    catch (Exception ex) {

    //JTA事务回滚出错处理

    ex.printStackTrace();

    }

    exc.printStackTrace();

    dbc.close();

    return -1;

    }

    }