你的位置:首页 > Java教程

[Java教程]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.    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.

<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.    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() {  }}