ThreadLocal和线程的详解,以及在公共字段自动填充方向的应用

线程是什么:

线程(Thread)是操作系统能够进行运算调度的最小单位。它是进程中的一个执行路径,一个进程可以包含多个线程。线程之间共享进程的资源(如内存、文件句柄等),但每个线程有自己的栈空间和程序计数器。

 线程是操作系统调度的最小单位,可以通过继承 Thread 类、实现 Runnable 接口或使用 CallableFuture 创建和启动。线程之间共享进程的资源,但每个线程有自己的栈空间和程序计数器。为了保证线程安全,可以使用同步机制,如同步方法、同步代码块和 ReentrantLock。线程之间可以通过 wait()notify()Condition 进行通信。

线程的生命周期

线程的生命周期包括以下几个阶段:

  1. 新建(New):线程对象被创建,但还没有调用 start() 方法。
  2. 就绪(Runnable):线程已经调用 start() 方法,等待 CPU 调度执行。
  3. 运行(Running):线程正在执行中。
  4. 阻塞(Blocked):线程因为某些原因(如等待 I/O 操作完成)被阻塞,暂时停止执行。
  5. 等待(Waiting):线程进入等待状态,等待其他线程的通知或时间到期。
  6. 终止(Terminated):线程执行完毕或因异常退出,进入终止状态。

ThreadLocal是什么:

ThreadLocal 是 Java 提供的一种线程本地存储机制,用于在多线程环境下为每个线程提供独立的变量副本。每个线程都可以独立地修改其副本,而不会影响其他线程的副本 。可以利用该机制将数据缓存在某个线程内部,该线程可以在任意时刻,任意方法中获取缓存的数据

底层原理:

 ThreadLocal底层是通过ThreadLocalMap来实现的,每个Thread对象(注意不是ThreadLocal对象)中都存在一个ThreadLocalMap,Map的key为ThreadLocal对象,Map的value为需要缓存的值

我的理解就是threadLocal只是当前线程的一个工具类,get,set,thread就是线程的意思

当一个共享变量是共享的,但是需要每个线程互不影响,相互隔离,就可以使用ThreadLocal

常见用法:

1.将一个变量定义为ThreadLocal共享变量,实现A中存值,可以在BCD中获取,实现跨层传递信息

2.隔离线程,存储一些线程不安全的工具对象,如(simpleDateFormat),比如spring中事务管理器就是使用的ThreadLocal

3.springmvc的HttpSession、HttpServletReuqest、HttpServletResponse都是放在ThreadLocal,因为servlet是单例的,而springmvc允许在controller类中通过@Autowired配置request、response以及requestcontext等实例对象。底层就是搭配Threadlocal才实现线程安全。

 公共字段自动填充:

公共字段自动填充是一种在数据库操作(如插入和更新)时自动填充某些公共字段的机制。这些公共字段通常包括创建时间、更新时间、创建人、更新人等。这种机制可以确保数据的一致性和完整性,减少手动设置这些字段的重复代码。

实现公共字段自动填充的方法:

1. 使用 ThreadLocal 存储当前用户信息的步骤

ThreadLocal 可以用来存储当前线程的用户信息,这样在插入或更新数据时,可以自动填充创建人和更新人字段。

首先,定义一个 UserContext 类,用于存储当前用户的信息:
public class UserContext {
    private static ThreadLocal<Long> currentUser = new ThreadLocal<>();

    public static void setCurrentUser(Long userId) {
        currentUser.set(userId);
    }

    public static Long getCurrentUser() {
        return currentUser.get();
    }

    public static void clear() {
        currentUser.remove();
    }
}
然后定义一个包含公共字段的基类 BaseEntity
import java.time.LocalDateTime;

public class BaseEntity {
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
    private Long createUser;
    private Long updateUser;

    // Getters and setters
    public LocalDateTime getCreateTime() {
        return createTime;
    }

    public void setCreateTime(LocalDateTime createTime) {
        this.createTime = createTime;
    }

    public LocalDateTime getUpdateTime() {
        return updateTime;
    }

    public void setUpdateTime(LocalDateTime updateTime) {
        this.updateTime = updateTime;
    }

    public Long getCreateUser() {
        return createUser;
    }

    public void setCreateUser(Long createUser) {
        this.createUser = createUser;
    }

    public Long getUpdateUser() {
        return updateUser;
    }

    public void setUpdateUser(Long updateUser) {
        this.updateUser = updateUser;
    }
}
接下来在保存或更新实体时,自动填充这些公共字段:
import java.time.LocalDateTime;

public class EntityService {
    public void save(BaseEntity entity) {
        entity.setCreateTime(LocalDateTime.now());
        entity.setUpdateTime(LocalDateTime.now());
        entity.setCreateUser(UserContext.getCurrentUser());
        entity.setUpdateUser(UserContext.getCurrentUser());
        // 保存实体到数据库
    }

    public void update(BaseEntity entity) {
        entity.setUpdateTime(LocalDateTime.now());
        entity.setUpdateUser(UserContext.getCurrentUser());
        // 更新实体到数据库
    }
}
最后在处理请求时,可以设置当前用户的信息:
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 java.io.IOException;

public class UserFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        // 假设从请求中获取用户ID
        Long userId = getUserIdFromRequest(request);
        UserContext.setCurrentUser(userId);
        try {
            chain.doFilter(request, response);
        } finally {
            UserContext.clear();
        }
    }

    private Long getUserIdFromRequest(ServletRequest request) {
        // 从请求中获取用户ID的逻辑
        return 1L; // 示例返回固定用户ID
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void destroy() {
    }
}

2. 使用 MyBatis Plus 自动填充

如果你使用的是 MyBatis Plus,可以利用其提供的自动填充功能来实现公共字段的自动填充。

首先,定义一个填充处理器 MyMetaObjectHandler
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
        this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
        this.strictInsertFill(metaObject, "createUser", Long.class, UserContext.getCurrentUser());
        this.strictInsertFill(metaObject, "updateUser", Long.class, UserContext.getCurrentUser());
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
        this.strictUpdateFill(metaObject, "updateUser", Long.class, UserContext.getCurrentUser());
    }
}
然后在实体类中使用 @TableField 注解配置自动填充:
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;

import java.time.LocalDateTime;

@TableName("employee")
public class Employee extends BaseEntity {
    @TableId
    private Long id;
    
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;

    @TableField(fill = FieldFill.INSERT)
    private Long createUser;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;

    // Getters and setters
}

公共字段自动填充是一种在数据库操作时自动填充某些公共字段的机制,旨在减少重复代码、确保数据一致性和提高开发效率。可以使用 ThreadLocal 存储当前用户信息,并在保存或更新实体时自动填充这些字段。对于使用 MyBatis Plus 的项目,可以利用其自动填充功能进一步简化实现过程。

  • 13
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值