JdbcUtils(内部使用c3p0得到连接池对象datasource)的第三次修改---完成事务的处理...

  把事务处理的方法从DAO层中抽离出来,写到Service层中,还有就是Service层中不能有Connection相关的东西,所以要对得到同一连接做相应的封装处理。

进一步封装JdbcUtils,使其具有事务的功能(即,有开启事务,提交事务,回滚事务功能),并且支持多线程(ThreadLocal的应用)。

该数据库连接池使用c3p0

 1.JdbcUtils.java:

package com.xjs.jdbcutils;

import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.DataSource;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class JdbcUtils {
    //使用文件的默认配置,要求必须给出c3p0-config.xml
    private static ComboPooledDataSource dataSource=new ComboPooledDataSource();
    //它是事务专用连接---允许多线程访问
    private static ThreadLocal<Connection> tl=new ThreadLocal<Connection>();
    
    //使用连接池返回一个连接对象
    public static Connection getConnection() throws SQLException{
        //得到自己线程的con,解决多线程问题
        Connection con=tl.get();
        //当con不为null时,说明已经调用过beginTransaction方法,表示开启了事务
        if(con != null){
            return con;
        }
        //如果是简单的获取连接的话,就返回连接池创建的连接
        return dataSource.getConnection();
    }
    
    //返回连接池对象
    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 beginTransaction() throws SQLException{
        Connection con=tl.get();
        if(con != null) throw new SQLException("已经开启了事务,就不要重复开启了!");
        /*
         * 1.给con赋值!
         * 2.给con设置手动提交!
         */
        con=getConnection();
        con.setAutoCommit(false);
        
        tl.set(con);//把当前线程的;连接保存起来
    }
    /**
     * 提交事务
     * 1.获取beginTransaction提供的Connection,然后调用commit方法
     * @throws SQLException 
     */
    public static void commitTransaction() throws SQLException{
        Connection con=tl.get();//获取当前线程的专用连接
        if(con == null) throw new SQLException("还没有开启了事务,不能提交!");
        //直接使用con.commit()
        con.commit();
        con.close();//在这只是把连接归还给连接池了,这时con不为null;防止后面再次使用时出错,把con赋为null
        tl.remove();//从tl中移除连接
    }
    /**
     * 回滚事务
     * 1.获取beginTransaction提供的Connection,然后调用rollback方法
     * @throws SQLException 
     */
    public static void rollbackTransaction() throws SQLException{
        Connection con=tl.get();
        if(con == null) throw new SQLException("还没有开启了事务,不能关闭!");
        //直接使用con.rollback()
        con.rollback();
        con.close();
        //把它设置为null,表示事务已经结束了!下次在调用getConnection()返回的就不是con了!
        
        tl.remove();
    }
    /**
     * 释放连接
     * @param connection
     * @throws SQLException 
     */
    public static void releaseConnection(Connection connection) throws SQLException{
        Connection con=tl.get();
        /*
         * 判断它是不是事务专用,如果是,就不关闭!
         * 如果不是事务专用,那么就要关闭!
         */
        //如果con=null,说明现在没有事务,那么connection一定不是事务专用!
        if(con == null) connection.close();
        
        //如果con!=null,说明有事务,那么需要判断参数连接是否与con相等,若不等,说明参数连接不是事务专用连接
        if(con != connection) connection.close();
        
    }

    
}

  QueryRunner类是apache对数据库操作进行的封装,对事务的实现不完善,自己写一个TxQueryRunner类继承QueryRunner类,重写父类中(参数中带Connection)的方法。在开启事务之后,TxQueryRunner类中的方法都已经得到事务专用的connection(使用时都需要传递参数Connection)都支持事务。

2.TxQueryRunner.java:

package com.xjs.jdbcutils;

import java.sql.Connection;
import java.sql.SQLException;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;

/**
 * 这个类中的方法,自己类处理连接的问题
 * 无需外界传递!
 * 怎样处理的呢?
 *     通过JdbcUtils.getConnection()得到连接!又可能是事务连接,也有可能是普通连接!
 *     JdbcUtils.releaseConnection()完成对连接的释放!如果是普通连接,关闭之(即把con归还给池)!
 * @author hp
 *
 */
public class TxQueryRunner extends QueryRunner{

    /**
     * 继承父类,重写父类中不带connection参数的方法,自己给那些不带con参数的方法加上con,
     * 在方法前面得到con,方法后面释放con
     * 这样能保证这个类中的所有方法都使用Connection对象
     */
    @Override
    public int[] batch(String sql, Object[][] params) throws SQLException {
        /*
         * 1.得到连接
         * 2.执行父类方法,传递连接对象
         * 3.释放连接
         * 4.返回值
         */ 
        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;
    }
}

3.模拟Dao层:

package com.xjs.jdbcutils;

import java.sql.Connection;
import java.sql.SQLException;

import org.apache.commons.dbutils.QueryRunner;
//Dao层--转账
public class AccountDao {

    public static void update(String name,double money) throws SQLException{
        //使用QueryRunner(对操作数据库一些相同步骤进行了封装),完成对数据库的操作---使用commons-dbutils包中的类
        QueryRunner qr=new TxQueryRunner();
        String sql="update account set balance=balance+? where name=?";
        Object[] params={money,name};
        qr.update(sql, params);//没有con,在方法的内部有con
    }
}

该Dao层中使用的TxQueryRunner类中的方法,其方法中有事务专用的连接con,以及con的释放。注意:其实在这的这个事务专用连接con没有关闭,也没有归还给池。因为在下边的其他方法中还需用到它对数据库操作。

4.模拟service层:---调用dao层

package com.xjs.jdbcutils;

import java.sql.SQLException;

import org.junit.Test;

//模拟service层
public class Demo1 {
    private AccountDao dao = new AccountDao();

    @Test
    public void serviceMethod() throws Exception {
        try {
            JdbcUtils.beginTransaction();

            dao.update("zs", -100);
            /*if (true){
                throw new RuntimeException("抛出异常。。。");
            }*/
            dao.update("ls", 100);

            JdbcUtils.commitTransaction();
        } catch (Exception e) {
            try {
                JdbcUtils.rollbackTransaction();
            } catch (SQLException e1) {
            }
            throw e;
        }
    }
}

这样可以完成一次转账的操作。

数据库:

 各类的使用:

 

转载于:https://www.cnblogs.com/xjs1874704478/p/10946420.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值