zoukankan      html  css  js  c++  java
  • JDBC 事务控制

    一、简介:

    前面一遍提到了jdbc事务相关的概念。从中了解到事务应具有ACID特性。所以对于javaweb开发来说,某一个service层的方法,应该是一个事务,应该是具有原子性的。特别是当一个service方法中需要调用多次dao层的方法。应该必须要保证,这些多次调用的dao方法必须是要不全部执行成功。要不全部执行失败。比如说银行业务的service方法的转账方法,需要通过dao调用对源转账户信息进行更新减少指定金额,然后调用dao对目标账户信息进行更新增加指定金额。

    那么如下保证在跨dao层调用时,必须事务的acid特性呢?

    二、解决方法思路:

    保证事务的ACID特性,默认情况下对用jdbc对数据库进行操作事务都是自动的commit状态的。必须必须要将事务提交改成手动提交。由程序来控制什么一起向数据库提交。一般来说mysql、sql server与oracle默认的隔离级别是repeatable read级别。可以避免脏读与不可重复读。所以需要重点控制的是事务的提交与回滚。

    那么一个service方法跨多个dao方法调用,如何保证是一个事务呢?首先要保证是同一连接Connection才有可能保证是同一事务。接着需要关注的是如何在多个dao层中获取是同一Connection。让整个应用只有个Connection虽然可以解决同一Connection,但是应用就变成了单线程了。肯定不可以。那么多线程情况下,如何保证同一线程内获取的Connection都是同一对象呢?ThreadLocal类来帮忙,它可以提供线程局部变量。放入到此ThreadLocal中的对象,在同一线程都保证都到的对象都是一致的。

    解决方法:只需要编写一个TransactionUtils类,此类有一个private static的ThreadLocal tl对象。并且静态的getConnction方法体中,先判断tl对象中是否存在Connection对象,存在直接返回tl中的Connection。不存在则先用数据源获取个Connection对象然后放入到tl中,再返回Connection对象。此外TransactionUtils类还需要提供openTransaction方法、Commit方法、rollback方法,openTransaction、commit与rollback需要的Connection对象都直接找本类的getConnection方法。

    接着后面service层,先调用TransactionUtils类的openTransaction方法,再对所有的dao层调用方法都try ... Catch...finally下。Catch中调用TransactionUtils类的rollback方法。finally里中调用 TransactionUtils类的commit方法。

    而dao层获取的Connection都直接找TransactionUtils类的getConnection方法,来确认得到的都是同一Connection对象。

    三、示例代码如下:

    01public class TransactionUtil {

    02    private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();

    03    private static DataSource ds;

    04 

    05    static {

    06        try {

    07            InputStream in = DbcpUtil.class.getClassLoader()

    08                    .getResourceAsStream("dbcpconfig.properties");

    09            Properties props = new Properties();

    10            props.load(in);

    11            ds = BasicDataSourceFactory.createDataSource(props);

    12        } catch (Exception e) {

    13            throw new ExceptionInInitializerError(e);

    14        }

    15    }

    16 

    17    public static DataSource getDataSource() {

    18        return ds;

    19    }

    20 

    21    public static Connection getConnection() {

    22        Connection conn = tl.get(); // 从ThreadLoacl中获取,如果没有再从DataSource中获取

    23        if (conn == null) {

    24            try {

    25                conn = ds.getConnection();

    26                tl.set(conn); // 存到ThreadLoacl中

    27            } catch (SQLException e) {

    28                e.printStackTrace();

    29            }

    30        }

    31        return conn;

    32    }

    33 

    34    public static void startTransaction() {

    35        try {

    36            Connection conn = tl.get();

    37            if(conn == null) {      //如果ThreadLoacl中没有,就从DataSource中获取

    38                conn = ds.getConnection();

    39                tl.set(conn);       //存入

    40            }

    41            conn.setAutoCommit(false);

    42        } catch(Exception e) {

    43            e.printStackTrace();

    44        }

    45    }

    46 

    47    public static voidrollback() { <span style="font-family: 'Courier New'; ">//回滚事务,在service层try下dao层,在catch处调用rollbakc方法</span>

    48        try {

    49            Connection conn = tl.get();

    50            if(conn != null)

    51                conn.rollback();

    52        } catch(Exception e) {

    53            e.printStackTrace();

    54        }

    55    }

    56 

    57    public static voidcommit() {        <span style="font-family: 'Courier New'; ">//在finally里调用提交commint方法</span>

    58        try {

    59            Connection conn = tl.get();

    60            if(conn != null)

    61                conn.commit();

    62        } catch(Exception e) {

    63            e.printStackTrace();

    64        }

    65    }

    66     

    67    public static void release() {

    68        try {

    69            Connection conn = tl.get();

    70            if(conn != null) {

    71                conn.close();

    72                tl.remove();

    73            }

    74        } catch(Exception e) {

    75            e.printStackTrace();

    76        }

    77    }

    78     

    79}

  • 相关阅读:
    ThinkPHP第八天(U函数放置在外部JS不会被解析,错误界面定制,错误信息变量)
    ThinkPHP第七天(F函数使用,项目分组配置,项目分组模板文件放置规则配置)
    thinkphp第二天
    ThinkPHP第五天(提交类型判定常量IS_POST等,错误页面种类,Model实例化方式,模板中使用函数,foreach循环,模板中.语法配置)
    高阶函数、函数嵌套和闭包
    递 归
    函数式编程
    命名空间
    函数的参数
    循环语句
  • 原文地址:https://www.cnblogs.com/toSeeMyDream/p/5539356.html
Copyright © 2011-2022 走看看