• 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

  • 相关阅读:
    字符串样式效果
    javaScript 继承原型链
    javaScript 的继承,call()
    二维数组中的查找
    如何证明一个映射是混沌的。
    netty如何知道连接已经关闭,socket心跳,双工?异步?
    java中线程安全的map是ConcurrentHashMap
    failed to load class "org.sl4j.impl.StaticLoggerBinder"
    Tcp端口以及端口相关协议详解
    Tcp的三次握手,以及原理详解
  • 原文地址:https://www.cnblogs.com/ms-grf/p/7214601.html
Copyright © 2020-2023  润新知