ThreadLocal天生為解決相同變量的訪問(wèn)沖突問(wèn)題郎哭, 所以這個(gè)對(duì)于spring的默認(rèn)單例bean的多線程訪問(wèn)是一個(gè)完美的解決方案。spring也確實(shí)是用了ThreadLocal來(lái)處理多線程下相同變量并發(fā)的線程安全問(wèn)題哥放。
- 要想實(shí)現(xiàn)jdbc事務(wù), 就必須是在同一個(gè)連接對(duì)象中操作, 多個(gè)連接下事務(wù)就會(huì)不可控龄糊, 需要借助分布式事務(wù)完成玩焰。那spring 如何保證數(shù)據(jù)庫(kù)事務(wù)在同一個(gè)連接下執(zhí)行的呢由驹?
- DataSourceTransactionManager 是spring的數(shù)據(jù)源事務(wù)管理器, 它會(huì)在你調(diào)用getConnection()的時(shí)候從數(shù)據(jù)庫(kù)連接池中獲取一個(gè)connection昔园, 然后將其與ThreadLocal綁定蔓榄, 事務(wù)完成后解除綁定。這樣就保證了事務(wù)在同一連接下完成默刚。
事務(wù)開(kāi)始階段
public static void bindResource(Object key, Object value) throws IllegalStateException {
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
Assert.notNull(value, "Value must not be null");
Map<Object, Object> map = resources.get();
// set ThreadLocal Map if none found
if (map == null) {
map = new HashMap<>();
resources.set(map);
}
Object oldValue = map.put(actualKey, value);
- ThreadLocal存儲(chǔ)的為DataSource生成的actualKey為key值和ConnectionHolder作為value值封裝成的Map甥郑。
private static final ThreadLocal<Map<Object, Object>> resources =
new NamedThreadLocal<>("Transactional resources");
- 將 DBResource 和 ConnectionHolder分別作為KV存入 map
Object oldValue = map.put(actualKey, value);
事務(wù)結(jié)束階段
@Nullable
private static Object doUnbindResource(Object actualKey) {
Map<Object, Object> map = resources.get();
if (map == null) {
return null;
}
Object value = map.remove(actualKey);
// Remove entire ThreadLocal if empty...
if (map.isEmpty()) {
resources.remove();
}
- 獲取ThreadLocalMap
resources.get();
- 刪除map 的Entry并移除
Object value = map.remove(actualKey);
// Remove entire ThreadLocal if empty...
if (map.isEmpty()) {
resources.remove();
}
學(xué)習(xí)更多:
ThreadLocal 面試六連問(wèn),你能 Hold 住嗎荤西?
ThreadLocal-面試必問(wèn)深度解析
Spring事務(wù)之如何保證同一個(gè)Connection對(duì)象
公眾號(hào)"會(huì)講歷史的程序員",歡迎關(guān)注