大数据WEB阶段(十九)Threadlocal

ThreadLocal

一、ThreadLocal概述

  1. 本地线程变量
  2. 本质上是一种利用线程的执行由程序的上游向下游传递信息的机制
  3. Thread对象内置了一个Map来存取消息 , 但是这个 Map外界无法直接操作 , 需要通过ThreadLocal来实现Thread中Map进行数据的存取
  4. ThreadLocal就是用来实现Thread的Map存取过程的类
  5. 每一个线程保存各自自己的对象 , 后续获取来使用 , 每个线程都有自己的对象自然不会有线程安全的问题

二、ThreadLocal方法

  1. ThreadLocal t1 = new ThreadLocal:获取当前线程 , 并获取线程中的map对象
  2. t1.set(obj) : 向当前线程的map中存储t1:obj键值对
  3. t1.get():得到当前线程中的map , 从map中查找t1对应的值并返回
  4. t1.remove() : 移除map中的键值对

三、基于数据库事务、ThreadLocal的实际案例

  1. 场景:添加商品
  2. 分析: 添加新的商品时 , 需要先判断商品种类表中是否有对应的种类 , 如果有这个种类执行商品信息插入数据库 , 如果没有这商品种类 , 则在商品种类表中添加商品种类后 , 将商品信息插入数据库中 。 但是需要注意 , 在数据库中不允许出现有商品种类但是没有对应商品的情况 , 所以查询商品种类表、添加商品种类 、 添加商品 , 是一组操作 , 要么都执行成功 , 要么都不执行成功 。
  3. 应用技术: 数据库事务操作查看详情 、 ThreadLocal机制
  4. 实现思路分析:
    1. 当添加商品操作时 , 将查询商品种类表、添加商品种类 、 添加商品放到一组事务中 , 也就是说这三个操作必须要使用同一个连接对象conn , 在service层中统一开启事务 ,执行完三个操作后统一提交事务后再统一释放conn对象 。但是这种情况下操作数据库的方法只能由service层调用 , 如果在Service层中创建Connection conn对象 , 再通过方法参数的传递将conn传递给dao层 , 虽然可以实现功能 , 但是违反了JavaEE经典三层架构的原理 , 在Service层中竟然出现了Dao层特有的对象 , 发生了耦合 。
    2. 如果这种耦合不可避免, 那么我们需要尽量将耦合管理起来 , 把service层中的事务操作抽取到一个工具类中 , 将Conn设置为static共享资源 , 一组事务内的所有数据库操作共享同一个 conn , 这样就实现了功能的需求 。
    3. 但是在并发情况下两个用户同时用一个conn对象 , 势必会发生事务的混乱 , 比如发生后来的用户提交了先来用户未操作玩的事务 … 。 这时候需要引入ThreadLocal机制保证每一个用户都有自己的conn ,从而实现了事务之间互不干涉的目的。
  5. 需要注意的是:
    1. 由于一组事务中的所有数据库操作用的都是一个conn , 所以在事务中的每一步操作完成后都不能释放conn , 必须等一组事务中的所有数据库操作完成后统一释放conn
  6. 代码:

        事务管理工具
        public class TransManage {
            private TransManage(){}
            private static ThreadLocal tl = new ThreadLocal();
    
            //获取连接
            public static Connection getConn(){
    
                return tl.get();
    
            }
            //释放资源
            public static void releaase(){
                Connection conn = tl.get();
                MySqlUtils.close(null, null, conn);
                tl.remove();
            }
            //开启事务
            public static void startTrans(){
                try {
                    Connection conn = MySqlUtils.getConn();
                    conn.setAutoCommit(false);
                    tl.set(conn);
                } catch (SQLException e) {
                    e.printStackTrace();
                    throw new RuntimeException(e);
                }
            }
            //提交事务
            public static void commitTrans(){
                try {
                    tl.get().commit();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            //回滚事务
            public static void rollbackTrans(){
                try {
                    tl.get().rollback();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    
        service层执行一组事务
        private ProdDao dao =BaseFactory.getBase().getInstance(ProdDao.class);
        public void addProd(Prod prod) {
            try{
                //开启事务
                TransManage.startTrans();
                //1.根据商品种类查询
                Prod_category category = dao.findPordCategoryByName(prod.getCategory().getCategory());
                //2. 处理商品种类 
                int c_id = 0;
                if(category == null){
                    //商品种类不存在,  添加商品种类
                    Prod_category pc = new Prod_category();
                    pc.setCategory(prod.getCategory().getCategory());
                    dao.addprodcategory(pc);
                    //并获得商品种类的编号保存在商品信息中
                    Prod_category findpc = dao.findPordCategoryByName(prod.getCategory().getCategory());
                    c_id = findpc.getId();
                }else{
                    //如果找到 , 就查询商品种类的编号保存在商品信息中
                    c_id = category.getId();
    
                }
                //3. 将商品存入数据库中
                prod.getCategory().setId(c_id);
                dao.addprod(prod);
                //没有发生异常 , 则提交事务
                TransManage.commitTrans();
            }catch(Exception e){
                //如果发生异常 , 则回滚
                TransManage.rollbackTrans();
                throw new RuntimeException(e);
            }finally{
                //释放资源
                TransManage.releaase();
            }
    
    
        }
    

你可能感兴趣的:(WEB,大数据)