zoukankan      html  css  js  c++  java
  • JdbcUtils针对事务问题作出的第三次修改

    DAO中的事务
    其实在DAO中处理事务真的是“小菜一碟”
    try{
    con.commit();
    }catch(Exception e){
    con.rollback();
    }
    但是dao层中只能是对账户金额的修改而不是业务的处理
    service层中也可以使用刚才的格式,使用con会暴露出service直接使用数据库的问题

    我们希望这样来处理事务:
    public class XXXService(){
    private XXXDao dao=new XXXDao();
    public void serviceMethod(){
    try{
    JdbcUtils.beginTransaction();
    dao.daoMethod1(...);
    dao.daoMethod2(...);
    JdbcUtils.commitTransaction();
    }catch(Exception e){
    JdbcUtils.rollbackTransaction();
    }
    }
    }
    修改后:

    package cn.itcast.cn;
    
    import java.sql.Connection;
    import java.sql.SQLException;
    
    import javax.sql.DataSource;
    
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    
    public class JdbcUtils {
        /*
         * 配置文件的恶魔人配置!要求你必须给出c3p0-config。xnl!
         */
        private static ComboPooledDataSource dataSource=new ComboPooledDataSource("oracle-config");
        /**
         * 它是事务专用连接
         */
        private static Connection con=null;
        /**
         * 使用连接池返回一个连接对象
         * @return
         * @throws SQLException
         */
        public static Connection getConnection() throws SQLException{
            //当con!=null,表示已经调用过beginTransaction方法了
            if(con!=null) return con;
            return dataSource.getConnection();
        }
        
        /**
         * 返回连接池对象
         * @return
         */
        public static DataSource getDataSource(){
            return dataSource;
        }
        /**
         * 1、开启一个Connection,设置它的setAutoCommit(false)
         * 2、还要保证dao中使用的连接是我们刚刚创建的
         * ------------------------
         * 1、创建一个Connection,设置为手动提交
         * 2、把这个Connection给dao用
         * 3、还要让commitTransaction或rollbackTransaction可以获取到
         * @throws SQLException 
         */
        public static void beignTransaction() throws SQLException{
            if(con!=null) throw new SQLException("已经开始了事务,就不要继续开启事务了!");
            con=getConnection();
            con.setAutoCommit(false);
        }
        /**
         * 提交事务
         * 获取之前开启的Connection,兵提交
         * @throws SQLException 
         */
        public static void commitTransaction() throws SQLException{
            if(con==null) throw new SQLException("还没有开启事务,不能提交!");
            con.commit();
            con.close();
            con=null;//因为前面的close()不会销毁连接而是放回连接池
        }
        /**
         * 回滚事务
         * 获取之前开启的Connection,兵回滚
         * @throws SQLException 
         */
        public static void rollbackTransaction() throws SQLException{
            if(con==null) throw new SQLException("还没有开启事务,不能提交!");
            con.rollback();
            con.close();
            con=null;//因为前面的close()不会销毁连接而是放回连接池
        }
    }
    package cn.itcast.cn;
    
    import java.sql.Connection;
    import java.sql.SQLException;
    
    import org.apache.commons.dbutils.QueryRunner;
    
    public class AccountDao {
        public static void update(String name,double money) throws SQLException{
            QueryRunner qr=new QueryRunner();
            String sql="UPDATE account SET balance=balance+? WHERE aname=?";
            Object[] params={money,name};
            
            //我们需要自己来提供连接,保证多次调用使用的是同一个连接
            Connection con=JdbcUtils.getConnection();
            qr.update(con, sql, params);
        }
    }
    package cn.itcast.cn;
    
    import java.sql.SQLException;
    
    import org.junit.Test;
    
    @SuppressWarnings("static-access")
    public class Demo1 {
        private AccountDao dao=new AccountDao();
        @Test
        public void serviceMethod(){
            try{
                JdbcUtils.beignTransaction();
                dao.update("zs", -1000);
                dao.update("lisi", +1000);
                JdbcUtils.commitTransaction();
        }catch(Exception e){
            try {
                JdbcUtils.rollbackTransaction();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        }
    
        }
    }

    针对前面的针对多线程并发问题和代码复杂度问题作出的再次优化:

    package cn.itcast.cn;
    
    import java.sql.Connection;
    import java.sql.SQLException;
    
    import javax.sql.DataSource;
    
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    
    public class JdbcUtils {
        /*
         * 配置文件的恶魔人配置!要求你必须给出c3p0-config。xnl!
         */
        private static ComboPooledDataSource dataSource=new ComboPooledDataSource();
        /**
         * 它是事务专用连接
         */
        private static ThreadLocal<Connection> t1=new ThreadLocal<Connection>();
        /**
         * 使用连接池返回一个连接对象
         * @return
         * @throws SQLException
         */
        public static Connection getConnection() throws SQLException{
            //当con!=null,表示已经调用过beginTransaction方法了
            Connection con=t1.get();
            if(con!=null) return con;
            return dataSource.getConnection();
        }
        
        /**
         * 返回连接池对象
         * @return
         */
        public static DataSource getDataSource(){
            return dataSource;
        }
        /**
         * 1、开启一个Connection,设置它的setAutoCommit(false)
         * 2、还要保证dao中使用的连接是我们刚刚创建的
         * ------------------------
         * 1、创建一个Connection,设置为手动提交
         * 2、把这个Connection给dao用
         * 3、还要让commitTransaction或rollbackTransaction可以获取到
         * @throws SQLException 
         */
        public static void beignTransaction() throws SQLException{
            Connection con=t1.get();
            if(con!=null) throw new SQLException("已经开始了事务,就不要继续开启事务了!");
            con=getConnection();
            con.setAutoCommit(false);
            t1.set(con);//把连接保存起来
        }
        /**
         * 提交事务
         * 获取之前开启的Connection,兵提交
         * @throws SQLException 
         */
        public static void commitTransaction() throws SQLException{
            Connection con=t1.get();
            if(con==null) throw new SQLException("还没有开启事务,不能提交!");
            con.commit();
            con.close();
    //        con=null;//因为前面的close()不会销毁连接而是放回连接池
            t1.remove();//从t1中移除连接
        }
        /**
         * 回滚事务
         * 获取之前开启的Connection,兵回滚
         * @throws SQLException 
         */
        public static void rollbackTransaction() throws SQLException{
            Connection con=t1.get();
            if(con==null) throw new SQLException("还没有开启事务,不能提交!");
            con.rollback();
            con.close();
    //        con=null;//因为前面的close()不会销毁连接而是放回连接池
            t1.remove();
        }
        
        
        public static void releaseConnection(Connection connection) throws SQLException{
            /*
             *判斷它是不是中事務專用,如果是就不關閉
             *如果不是就要關閉
             */
            //如果con==null,說明沒有事務,那麼connection一定不是事務專用的
            Connection con=t1.get();
            if(con==null)    connection.close();
            if(con!=connection) connection.close();
            
        }
    }
    package cn.itcast.cn;
    
    import java.sql.Connection;
    import java.sql.SQLException;
    
    import org.apache.commons.dbutils.QueryRunner;
    import org.apache.commons.dbutils.ResultSetHandler;
    /**
     * 这个类中的方法自己来处理连接的问题
     * 无需外界传递
     * 怎么处理的呢?
     *     通过JdbcUtils.getConnection()得到连接!有可能是事务连接也有可能是普通连接
     * JdbcUtils.releaseConnection()完成连接的释放
     * @author Administrator
     *
     */
    public class TxQueryRunner extends QueryRunner{
    
        @Override
        public int[] batch(String sql, Object[][] params) throws SQLException {
            /**
             * 得到连接
             * 执行父类方法
             * 释放连接
             * 返回值
             */
            Connection con=JdbcUtils.getConnection();
            int[] result=super.batch(con, sql, params);
            JdbcUtils.releaseConnection(con);
            return result;
        }
    
        @Override
        public <T> T query(String sql, Object param, ResultSetHandler<T> rsh)
                throws SQLException {
            Connection con=JdbcUtils.getConnection();
            T result=super.query(con, sql, param,rsh);
            JdbcUtils.releaseConnection(con);
            return result;
        }
    
        @Override
        public <T> T query(String sql, Object[] params, ResultSetHandler<T> rsh)
                throws SQLException {
            Connection con=JdbcUtils.getConnection();
            T result=super.query(con,sql, params, rsh);
            JdbcUtils.releaseConnection(con);
            return result;
        }
    
        @Override
        public <T> T query(String sql, ResultSetHandler<T> rsh, Object... params)
                throws SQLException {
            Connection con=JdbcUtils.getConnection();
            T result=super.query(con,sql, rsh,params);
            JdbcUtils.releaseConnection(con);
            return result;
        }
    
        @Override
        public <T> T query(String sql, ResultSetHandler<T> rsh) throws SQLException {
            Connection con=JdbcUtils.getConnection();
            T result=super.query(con,sql, rsh);
            JdbcUtils.releaseConnection(con);
            return result;
        }
    
        @Override
        public int update(String sql) throws SQLException {
            Connection con=JdbcUtils.getConnection();
            int result=super.update(con,sql);
            JdbcUtils.releaseConnection(con);
            return result;
        }
    
        @Override
        public int update(String sql, Object param) throws SQLException {
            Connection con=JdbcUtils.getConnection();
            int result=super.update(con,sql,param);
            JdbcUtils.releaseConnection(con);
            return result;
        }
    
        @Override
        public int update(String sql, Object... params) throws SQLException {
            Connection con=JdbcUtils.getConnection();
            int result=super.update(con,sql,params);
            JdbcUtils.releaseConnection(con);
            return result;
        }
        
    }
    package cn.itcast.cn;
    
    import java.sql.SQLException;
    
    import org.apache.commons.dbutils.QueryRunner;
    
    public class AccountDao {
        public static void update(String name,double money) throws SQLException{
    //        QueryRunner qr=new QueryRunner();
            QueryRunner qr=new TxQueryRunner();
            String sql="UPDATE account SET balance=balance+? WHERE aname=?";
            Object[] params={money,name};
            
            //我们需要自己来提供连接,保证多次调用使用的是同一个连接
    //        Connection con=JdbcUtils.getConnection();
    //        qr.update(con, sql, params);
    //        JdbcUtils.releaseConnection(con);
            qr.update(sql,params);
        }
    }
    
    package cn.itcast.cn;
    
    import java.sql.SQLException;
    
    import org.junit.Test;
    
    @SuppressWarnings("static-access")
    public class Demo1 {
        private AccountDao dao=new AccountDao();
        @Test
        public void serviceMethod() throws Exception{
            try{
                JdbcUtils.beignTransaction();
                dao.update("zs", -1000);
                if(true) throw new RuntimeException("不好依稀");
                dao.update("lisi", +1000);
                JdbcUtils.commitTransaction();
        }catch(Exception e){
            try {
                JdbcUtils.rollbackTransaction();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            throw e;
        }
    
        }
    }
  • 相关阅读:
    python学习之函数的参数
    python学习之文件修改及函数基础作业
    日志模块与 re 模块
    day23
    常用模块(二)
    day 22
    python 常用模块
    软件开发目录规范
    day 20
    python 的模块与包
  • 原文地址:https://www.cnblogs.com/aigeileshei/p/5718082.html
Copyright © 2011-2022 走看看