1. 程式人生 > 程式設計 >Mybatis多執行緒下如何使用Example詳解

Mybatis多執行緒下如何使用Example詳解

前言

伺服器每收到一個請求,都會從執行緒池中排程一個空閒執行緒來處理,spring整合的web時,controller和service一般都是單例的,這樣導致無論你的Example標註的是單例還是多例,同一個service下的Example也只有一個,多執行緒訪問時產生的

問題如下

問題詳情

工程目錄結構如下

MyService 的service()方法接收兩個引數並據此查詢資料庫

@Service
public class MyService {
 @Autowired
 StudentMapper studentMapper;
 @Autowired
 StudentExample studentExample;
 public void service(Integer begin,Integer end){
  StudentExample.Criteria criteria1 = studentExample.createCriteria();
  criteria1.andAgeBetween(begin,end);
  List<Student> list=studentMapper.selectByExample(studentExample);
  studentExample.clear();
  System.out.println(list);
 }
}

當同時有兩個請求時,兩個請求的StudentExample相同

請求1如下

begin=2,end=8

請求2如下

begin=4,end=8

先放行請求1,請求1成功新增條件

再放行請求2,請求2新增失敗

這時如果請求2在請求1執行查詢操作前就已經執行完studentExample.clear (),請求1的查詢條件就失效了

至此兩個請求都沒有得到正確的結果。

解決方案

可以使用ThreadLocal為每個執行緒配備單獨的Example,為保證每次都能獲取到值,這裡對ThreadLocal簡單擴充套件一下,如果當前執行緒沒有對應的Example(多例),就從spring容器中獲取一個並與這個執行緒繫結。

ThreadLocalExtension

public class ThreadLocalExtension<T> extends ThreadLocal<T> {
   //獲取ApplicationContext方法見下
  @Autowired
  ApplicationContext applicationContext;
  public ThreadLocalExtension(){
    super();
  }
  public T get(Class<T> example){
    T bean=super.get();
    if(bean==null){
      super.set((T) applicationContext.getBean(example));
    }
    return super.get();
  }
}

spring泛型依賴注入

由於Example會有很多個,所以這裡使用了泛型,spring4.0提供了對泛型依賴注入的支援。

首先實際型別對應的ThreadLocalExtension交由spring管理

@Repository
public class StudentExampleThreadLocal extends ThreadLocalExtension<StudentExample> {
}

然後直接在程式碼中注入

@Autowired
ThreadLocalExtension<StudentExample> studentExampleThreadLocal;

修改後的MyService

@Service
public class MyService {
  @Autowired
  StudentMapper studentMapper;
  @Autowired
  ThreadLocalExtension<StudentExample> studentExampleThreadLocal;
  public void service(Integer begin,Integer end){
    StudentExample studentExample = studentExampleThreadLocal.get(StudentExample.class);
    StudentExample.Criteria criteria1 = studentExample.createCriteria();
    criteria1.andAgeBetween(begin,end);
    List<Student> list=studentMapper.selectByExample(studentExample);
    studentExample.clear();
    System.out.println(list);
  }
}

獲取ApplicationContext

建立一個類實現ApplicationContextAware,並向spring容器中注入applicationContext

@Component
public class ApplicationContextHelper implements ApplicationContextAware {
  private static ApplicationContext applicationContext;

  public ApplicationContextHelper() {
  }
  @Bean(name="applicationContext")
  public ApplicationContext getApplicationContext(){
    return applicationContext;
  }

  @Override
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    ApplicationContextHelper.applicationContext = applicationContext;
  }

  public static Object getBean(String beanName) {
    return applicationContext != null?applicationContext.getBean(beanName):null;
  }
}

結果

至此,整個改造完成,看看效果

請求1

請求2


每個請求獲取到了不同的StudentExample,也就不存在衝突的問題,並且StudentExample沒有大量的建立與銷燬,最多隻建立了與伺服器執行緒池中執行緒相同的個數,實現了重複使用

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對我們的支援。