ThreadLocal 用于控制事务

1、封装一个从连接池获取Connection的工具类

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.sql.DataSource;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class DataSourceUtils {

    private static DataSource dataSource = new ComboPooledDataSource();

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

    // 直接可以获取一个连接池
    public static DataSource getDataSource() {
        return dataSource;
    }

    // 获取连接对象
    public static Connection getConnection() throws SQLException {

        Connection con = tl.get();
        if (con == null) {
            con = dataSource.getConnection();
            tl.set(con);
        }
        return con;
    }

    // 开启事务
    public static void startTransaction() throws SQLException {
        Connection con = getConnection();
        if (con != null) {
            con.setAutoCommit(false);
        }
    }

    // 事务回滚
    public static void rollback() throws SQLException {
        Connection con = getConnection();
        if (con != null) {
            con.rollback();
        }
    }

    // 提交并且 关闭资源及从ThreadLocall中释放
    public static void commitAndRelease() throws SQLException {
        Connection con = getConnection();
        if (con != null) {
            con.commit(); // 事务提交
            con.close();// 关闭资源
            tl.remove();// 从线程绑定中移除
        }
    }

    // 关闭资源方法
    public static void closeConnection() throws SQLException {
        Connection con = getConnection();
        if (con != null) {
            con.close();
        }
    }

    public static void closeStatement(Statement st) throws SQLException {
        if (st != null) {
            st.close();
        }
    }

    public static void closeResultSet(ResultSet rs) throws SQLException {
        if (rs != null) {
            rs.close();
        }
    }

}

2、使用

servlet封装数据调用service

//order对象封装完毕
ProductService service = new ProductService();
service.submitOrder(order);

service调用dao层,并开启事务

public void submitOrder(Order order) {
   //2,3两步必须是保持同时保存成功
    ProductDao dao = new ProductDao();
    //开始开启事务
    try {
        //1、开启事务
        DataSourceUtils.startTransaction();
        //2、调用dao存储order表数据的方法
        dao.addOrders(order);
        //3、调用到存储orderItem表数据的方法
        dao.addOrderItems(order);
        
    } catch (SQLException e) {
        try {
        //4、如果2,3两步其中一个出现异常则回归该事务
            DataSourceUtils.rollback();
        } catch (SQLException e1) {
            e1.printStackTrace();
        }
        e.printStackTrace();
    } finally{
        try {
        //5、最后关闭资源
            DataSourceUtils.commitAndRelease();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    
}

dao层做的就是存放数据到数据库,和上面的service层一样重要(注意看上面两个标红的方法,方法明细如下)

public void addOrders(Order order) throws SQLException {
    QueryRunner runner = new QueryRunner();
    String sql = "insert into orders values(?,?,?,?,?,?,?,?)";
    Connection conn = DataSourceUtils.getConnection();
    runner.update(conn,sql, order.getOid(),order.getOrdertime(),order.getTotal(),order.getState(),
            order.getAddress(),order.getName(),order.getTelephone(),order.getUser().getUid());
}

public void addOrderItems(Order order) throws SQLException {
    QueryRunner runner = new QueryRunner();
    String sql = "insert into orderitem values(?,?,?,?,?)";
    Connection conn = DataSourceUtils.getConnection();
    List<OrderItem> orderItems = order.getOrderItems();
    for(OrderItem item : orderItems){
        runner.update(conn,sql,item.getItemid(),item.getCount(),item.getSubtotal(),item.getProduct().getPid(),
         item.getOrder().getOid()); } }
//上面两个方法获取的conn是同一个conn,因为用到了ThreadLocal所以才会出现同一个conn的效果

想了解ThreadLocal可以参考下面这篇文章:彻底理解ThreadLocal

posted @ 2017-07-20 21:32  发福大叔  阅读(409)  评论(0编辑  收藏  举报