ThreadLocal: 維護(hù)線程局部的變量。
ThreadLocal 不是線程。它就是一個(gè)Map。可以保存對(duì)象。
它保存的對(duì)象,只與當(dāng)前線程相關(guān)。
當(dāng)一個(gè)線程還沒(méi)有運(yùn)行完成時(shí),如果不想傳遞數(shù)據(jù),可以通過(guò)ThreadLocal來(lái)保存與這個(gè)Thread相關(guān)數(shù)據(jù)。
用ThreadLocal保存和獲取數(shù)據(jù)的示例:
public class BaseDemo { public static void main(String[] args) { //聲明Map<Object key,Object value> //Object是值,key是當(dāng)前線程的引用=Thread.currentThread(); ThreadLocal<Object> tl = new ThreadLocal<Object>(); //保存數(shù)據(jù) tl.set("Helllo"); //獲取數(shù)據(jù) Object val = tl.get(); System.err.PRintln(val); }}
當(dāng)多個(gè)線程共同訪問(wèn)同一個(gè)資源時(shí),用threadLocal來(lái)維護(hù)某個(gè)線程的變量:
一個(gè)應(yīng)用項(xiàng)目中,一般只要有一個(gè)(static)threadlocal的實(shí)例就可以了:
public class MyThreadLocal { //聲明一個(gè)唯一的ThreadLocal private static ThreadLocal<Object> tl = new ThreadLocal<Object>(); public static Object getObject(){ //先從tl中讀取數(shù)據(jù) Object o = tl.get();// 如果沒(méi)有保存過(guò),map.get(Thread.currentThread()); if(o==null){ //生成一個(gè)隨機(jī) o = new Random().nextInt(100); //放到tl tl.set(o); } return o; } public static void remove(){ tl.remove(); }}
對(duì)ThreadLocal內(nèi)部保存的對(duì)象來(lái)說(shuō)。你可以執(zhí)行remove(無(wú)數(shù))方法刪除與當(dāng)前thread相關(guān)的對(duì)象。也可以不執(zhí)行:
因?yàn)椋簍hreadlocal內(nèi)部使用的是弱引用:
WeakReferences
用ThreadLocal管理事務(wù)
用三層模式:
Serlvet(MVC-C) – Sevice(服務(wù)層) – dao(數(shù)據(jù)訪問(wèn)層)
寫兩個(gè)dao,在service中調(diào)用這兩個(gè)dao。
讓第一個(gè)dao成功。讓第二個(gè)dao失敗,必須都回滾。
第一步:開(kāi)發(fā)兩個(gè)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); } }}
第二步:開(kāi)發(fā)Service
public class UserService { //聲明兩個(gè)dao private UserDao1 dao1 = new UserDao1(); private UserDao2 dao2 = new UserDao2(); public void save(){ dao1.save(); dao2.save(); }}
第三步:實(shí)現(xiàn)一個(gè)Servlet
public class UserServlet extends HttpServlet { //聲明service的實(shí)例 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 = // 默認(rèn)的讀取c3p0-config.xml中默認(rèn)配置 new ComboPooledDataSource("itcast"); } public static DataSource getDatasSource() { return ds; } public static Connection getConn() { // 先從tl這個(gè)容器中獲取一次數(shù)據(jù),如果當(dāng)前線程已經(jīng)保存過(guò)connection則直接返回這個(gè)connecton Connection con = tl.get(); if (con == null) { try { con = ds.getConnection();// 每一次從ds中獲取一個(gè)新的連接 //將這個(gè)con放到tl中 tl.set(con); } catch (Exception e) { e.printStackTrace(); } } return con; }}
第五步:聲明一個(gè)過(guò)慮器在過(guò)慮器開(kāi)始事務(wù)
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中開(kāi)始事務(wù) try{ con = DataSourceUtils.getConn(); //開(kāi)始事務(wù) con.setAutoCommit(false); //放行 chain.doFilter(request, response); //如果沒(méi)有出錯(cuò)。 con.commit(); }catch(Exception e){ System.err.println("出錯(cuò)了"); 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() { }}
第六步:將過(guò)慮器配置到weeb.xml中。且對(duì)某個(gè)路徑設(shè)置過(guò)慮
<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>
第七步:總結(jié)
在過(guò)慮器開(kāi)始事務(wù),就叫一種模式:OSIV模式》
OSIV – Open session In View =- 打開(kāi)與數(shù)據(jù)庫(kù)的會(huì)話在View層。- Hibernate.—AOP
第八步:優(yōu)化:
在datasourceutls.java實(shí)現(xiàn)一個(gè)刪除thredlocal中與線程相關(guān)的對(duì)象:
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 = // 默認(rèn)的讀取c3p0-config.xml中默認(rèn)配置 new ComboPooledDataSource("itcast"); } public static DataSource getDatasSource() { return ds; } public static Connection getConn() { // 先從tl這個(gè)容器中獲取一次數(shù)據(jù),如果當(dāng)前線程已經(jīng)保存過(guò)connection則直接返回這個(gè)connecton Connection con = tl.get(); if (con == null) { try { con = ds.getConnection();// 每一次從ds中獲取一個(gè)新的連接 //將這個(gè)con放到tl中 tl.set(con); } catch (Exception e) { e.printStackTrace(); } } return con; } public static void remove(){ tl.remove(); } }
在TxFilter中調(diào)用一個(gè)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中開(kāi)始事務(wù) try{ con = DataSourceUtils.getConn(); //開(kāi)始事務(wù) con.setAutoCommit(false); //放行 chain.doFilter(request, response); //如果沒(méi)有出錯(cuò)。 con.commit(); }catch(Exception e){ System.err.println("出錯(cuò)了"); 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() { }}
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注