ThreadLocal: 維護線程局部的變量。
ThreadLocal 不是線程。它就是一個Map??梢员4鎸ο?。
它保存的對象,只與當前線程相關。
當一個線程還沒有運行完成時,如果不想傳遞數據,可以通過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() { }}
新聞熱點
疑難解答