0
点赞
收藏
分享

微信扫一扫

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

三千筱夜 2022-11-30 阅读 119

       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

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

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

 

源码面前,了无秘密



举报

相关推荐

0 条评论