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

    }

}

 

你可能感兴趣的:(ThreadLocal模式)