java—ThreadLocal模式与OSIV模式(53)

       ThreadLocal: 维护线程局部的变量。

       ThreadLocal 不是线程。它就是一个Map。可以保存对象。

       它保存的对象,只与当前线程相关。

       当一个线程还没有运行完成时,如果不想传递数据,可以通过ThreadLocal来保存与这个Thread相关数据。

用ThreadLocal保存和获取数据的示例:

public class BaseDemo {
    public static void main(String[] args) {
        //声明Map<Object key,Object value>
        //Object是值,key是当前线程的引用=Thread.currentThread();
        ThreadLocal<Object> tl = new ThreadLocal<Object>();
        //保存数据
        tl.set("Helllo");
        //获取数据
        Object val = tl.get();
        System.err.println(val);
    }
}

当多个线程共同访问同一个资源时,用threadLocal来维护某个线程的变量:

一个应用项目中,一般只要有一个(static)threadlocal的实例就可以了:

public class MyThreadLocal {
    //声明一个唯一的ThreadLocal
    private static ThreadLocal<Object> tl = new ThreadLocal<Object>(); 
    public static Object getObject(){
        //先从tl中读取数据
        Object o = tl.get();//  如果没有保存过,map.get(Thread.currentThread());
        if(o==null){
            //生成一个随机
            o = new Random().nextInt(100);
            //放到tl
            tl.set(o); 
        }
        return o;
    }
    public static void remove(){
        tl.remove(); 
    }
}

对ThreadLocal内部保存的对象来说。你可以执行remove(无数)方法删除与当前thread相关的对象。也可以不执行:

因为:threadlocal内部使用的是弱引用:

WeakReferences

用ThreadLocal管理事务

用三层模式:

       Serlvet(MVC-C) – Sevice(服务层) – dao(数据访问层)

       写两个dao,在service中调用这两个dao。

       让第一个dao成功。让第二个dao失败,必须都回滚。

第一步:开发两个dao

public class UserDao2 {
    public void save(){
        String sql = "insert into users values(?,?,?)";
        QueryRunner run = new QueryRunner();
        try {
            run.update(DataSourceUtils.getConn(),sql,"U002","Jack","333");
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        
    }
}

第二步:开发Service

public class UserService {
    //声明两个dao
    private UserDao1 dao1 = new UserDao1();
    private UserDao2 dao2 = new UserDao2();
     public void save(){
        dao1.save();
        dao2.save();
    }
}

第三步:实现一个Servlet

public class UserServlet extends HttpServlet {
    //声明service的实例
    private UserService service = new UserService();
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        service.save();
    }
}

第四步:修改datasourceutils.java

package cn.hx.utils;
import java.sql.Connection;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class DataSourceUtils {
    // 声明线程局部的容器
    private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>(); 
    private static DataSource ds;
    static {
        ds = // 默认的读取c3p0-config.xml中默认配置
        new ComboPooledDataSource("itcast");
    }
    public static DataSource getDatasSource() {
        return ds;
    }
    public static Connection getConn() {
        // 先从tl这个容器中获取一次数据,如果当前线程已经保存过connection则直接返回这个connecton
        Connection con = tl.get(); 
        if (con == null) {
            try {
                con = ds.getConnection();// 每一次从ds中获取一个新的连接
                //将这个con放到tl中
                tl.set(con); 
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return con;
    }
}

第五步:声明一个过虑器在过虑器开始事务

package cn.hx.filter;

import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import cn.itcast.utils.DataSourceUtils;

public class TxFilter implements Filter{
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        //获取连接
        Connection con = null;
        //在try中开始事务
        try{
            con = DataSourceUtils.getConn();
            //开始事务
            con.setAutoCommit(false);
            //放行
            chain.doFilter(request, response);
            //如果没有出错。
            con.commit();
        }catch(Exception e){
            System.err.println("出错了");
            try {
                con.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            throw new RuntimeException(e);
        }finally{
            try {
                con.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    public void destroy() {
    }
}

第六步:将过虑器配置到weeb.xml中。且对某个路径设置过虑

<filter>
  <filter-name>tx</filter-name>
  <filter-class>cn.itcast.filter.TxFilter</filter-class>
 </filter>
 <filter-mapping>
  <filter-name>tx</filter-name>
     <url-pattern>/tx/*</url-pattern> 
 </filter-mapping>

第七步:总结

       在过虑器开始事务,就叫一种模式:OSIV模式》

       OSIV – Open Session In View =- 打开与数据库的会话在View层。- Hibernate.—AOP

第八步:优化:

在datasourceutls.java实现一个删除thredlocal中与线程相关的对象:

package cn.hx.utils;
import java.sql.Connection;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class DataSourceUtils {
    // 声明线程局部的容器
    private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
    private static DataSource ds;
    static {
        ds = // 默认的读取c3p0-config.xml中默认配置
        new ComboPooledDataSource("itcast");
    }
    public static DataSource getDatasSource() {
        return ds;
    }
    public static Connection getConn() {
        // 先从tl这个容器中获取一次数据,如果当前线程已经保存过connection则直接返回这个connecton
        Connection con = tl.get();
        if (con == null) {
            try {
                con = ds.getConnection();// 每一次从ds中获取一个新的连接
                //将这个con放到tl中
                tl.set(con);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return con;
    }
    public static void remove(){
        tl.remove();
    }
 }
在TxFilter中调用一个remove:
public class TxFilter implements Filter{
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        System.err.println("thread:"+Thread.currentThread().getName());
        //获取连接
        Connection con = null;
        //在try中开始事务
        try{
            con = DataSourceUtils.getConn();
            //开始事务
            con.setAutoCommit(false);
            //放行
            chain.doFilter(request, response);
            //如果没有出错。
            con.commit();
        }catch(Exception e){
            System.err.println("出错了");
            try {
                if(e instanceof SQLException){
                    con.rollback();
                }else{
                    con.commit();
                }
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            throw new RuntimeException(e);
        }finally{
            try {
                con.close();
                DataSourceUtils.remove(); 
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    public void destroy() {
    }
}
原文地址:https://www.cnblogs.com/zhenghongxin/p/4472109.html