diff --git a/threadconnectiondemo/pom.xml b/threadconnectiondemo/pom.xml
new file mode 100644
index 0000000..b6f38c1
--- /dev/null
+++ b/threadconnectiondemo/pom.xml
@@ -0,0 +1,74 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.1.8.RELEASE
+
+
+ com.woniu.connection
+ threadconnectiondemo
+ 1.0-SNAPSHOT
+
+
+
+ com.baomidou
+ mybatis-plus-boot-starter
+ 3.5.2
+
+
+
+
+ org.projectlombok
+ lombok
+ 1.18.24
+
+
+
+
+ org.apache.httpcomponents
+ httpclient
+ 4.5.13
+
+
+
+
+ mysql
+ mysql-connector-java
+ 8.0.29
+
+
+
+
+ commons-lang
+ commons-lang
+ 2.6
+
+
+
+ jakarta.validation
+ jakarta.validation-api
+ 2.0.2
+ compile
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ com.alibaba
+ fastjson
+ 1.2.15
+
+
+
+ com.alibaba
+ druid-spring-boot-starter
+ 1.1.13
+
+
+
+
\ No newline at end of file
diff --git a/threadconnectiondemo/src/main/java/com/woniu/connection/MainApplication.java b/threadconnectiondemo/src/main/java/com/woniu/connection/MainApplication.java
new file mode 100644
index 0000000..c95fd61
--- /dev/null
+++ b/threadconnectiondemo/src/main/java/com/woniu/connection/MainApplication.java
@@ -0,0 +1,12 @@
+package com.woniu.connection;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class MainApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(MainApplication.class, args);
+ }
+}
diff --git a/threadconnectiondemo/src/main/java/com/woniu/connection/config/DynamicDataSourceConfig.java b/threadconnectiondemo/src/main/java/com/woniu/connection/config/DynamicDataSourceConfig.java
new file mode 100644
index 0000000..79862fe
--- /dev/null
+++ b/threadconnectiondemo/src/main/java/com/woniu/connection/config/DynamicDataSourceConfig.java
@@ -0,0 +1,46 @@
+/**
+ * Copyright (c) 2018 人人开源 All rights reserved.
+ *
+ * https://www.renren.io
+ *
+ * 版权所有,侵权必究!
+ */
+
+package com.woniu.connection.config;
+
+import com.alibaba.druid.pool.DruidDataSource;
+import com.woniu.connection.properties.DataSourceProperties;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 配置多数据源
+ *
+ * @author 蜗牛
+ */
+@Configuration
+public class DynamicDataSourceConfig {
+
+
+ @Bean
+ @ConfigurationProperties(prefix = "spring.datasource.druid")
+ public DataSourceProperties dataSourceProperties() {
+ return new DataSourceProperties();
+ }
+
+ @Bean
+ public DruidDataSource dynamicDataSource(DataSourceProperties dataSourceProperties) {
+
+ //默认数据源
+ DruidDataSource defaultDataSource = DynamicDataSourceFactory.buildDruidDataSource(dataSourceProperties);
+ return defaultDataSource;
+ }
+
+
+}
\ No newline at end of file
diff --git a/threadconnectiondemo/src/main/java/com/woniu/connection/config/DynamicDataSourceFactory.java b/threadconnectiondemo/src/main/java/com/woniu/connection/config/DynamicDataSourceFactory.java
new file mode 100644
index 0000000..e158cf8
--- /dev/null
+++ b/threadconnectiondemo/src/main/java/com/woniu/connection/config/DynamicDataSourceFactory.java
@@ -0,0 +1,54 @@
+/**
+ * Copyright (c) 2018 人人开源 All rights reserved.
+ *
+ * https://www.renren.io
+ *
+ * 版权所有,侵权必究!
+ */
+
+package com.woniu.connection.config;
+
+import com.alibaba.druid.pool.DruidDataSource;
+import com.woniu.connection.properties.DataSourceProperties;
+
+import java.sql.SQLException;
+
+/**
+ * DruidDataSource
+ *
+ * @author 蜗牛
+ * @since 1.0.0
+ */
+public class DynamicDataSourceFactory {
+
+ public static DruidDataSource buildDruidDataSource(DataSourceProperties properties) {
+ DruidDataSource druidDataSource = new DruidDataSource();
+ druidDataSource.setDriverClassName(properties.getDriverClassName());
+ druidDataSource.setUrl(properties.getUrl());
+ druidDataSource.setUsername(properties.getUsername());
+ druidDataSource.setPassword(properties.getPassword());
+
+ druidDataSource.setInitialSize(properties.getInitialSize());
+ druidDataSource.setMaxActive(properties.getMaxActive());
+ druidDataSource.setMinIdle(properties.getMinIdle());
+ druidDataSource.setMaxWait(properties.getMaxWait());
+ druidDataSource.setTimeBetweenEvictionRunsMillis(properties.getTimeBetweenEvictionRunsMillis());
+ druidDataSource.setMinEvictableIdleTimeMillis(properties.getMinEvictableIdleTimeMillis());
+ druidDataSource.setMaxEvictableIdleTimeMillis(properties.getMaxEvictableIdleTimeMillis());
+ druidDataSource.setValidationQuery(properties.getValidationQuery());
+ druidDataSource.setValidationQueryTimeout(properties.getValidationQueryTimeout());
+ druidDataSource.setTestOnBorrow(properties.isTestOnBorrow());
+ druidDataSource.setTestOnReturn(properties.isTestOnReturn());
+ druidDataSource.setPoolPreparedStatements(properties.isPoolPreparedStatements());
+ druidDataSource.setMaxOpenPreparedStatements(properties.getMaxOpenPreparedStatements());
+ druidDataSource.setSharePreparedStatements(properties.isSharePreparedStatements());
+
+ try {
+ druidDataSource.setFilters(properties.getFilters());
+ druidDataSource.init();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ return druidDataSource;
+ }
+}
\ No newline at end of file
diff --git a/threadconnectiondemo/src/main/java/com/woniu/connection/config/WebConfig.java b/threadconnectiondemo/src/main/java/com/woniu/connection/config/WebConfig.java
new file mode 100644
index 0000000..fe136ec
--- /dev/null
+++ b/threadconnectiondemo/src/main/java/com/woniu/connection/config/WebConfig.java
@@ -0,0 +1,26 @@
+package com.woniu.connection.config;
+
+import com.woniu.connection.interceptor.LoginUserInterceptor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+/**
+ * @Description:
+ * @Created: with IntelliJ IDEA.
+ * @author: 蜗牛
+ * @createTime: 2020-07-02 18:38
+ **/
+
+@Configuration
+public class WebConfig implements WebMvcConfigurer {
+
+ @Autowired
+ private LoginUserInterceptor loginUserInterceptor;
+
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ registry.addInterceptor(loginUserInterceptor).addPathPatterns("/app/getUser");
+ }
+}
diff --git a/threadconnectiondemo/src/main/java/com/woniu/connection/constant/AuthServerConstant.java b/threadconnectiondemo/src/main/java/com/woniu/connection/constant/AuthServerConstant.java
new file mode 100644
index 0000000..0204a00
--- /dev/null
+++ b/threadconnectiondemo/src/main/java/com/woniu/connection/constant/AuthServerConstant.java
@@ -0,0 +1,7 @@
+package com.woniu.connection.constant;
+
+public class AuthServerConstant {
+
+ public static final String LOGIN_USER = "loginUser";
+
+}
diff --git a/threadconnectiondemo/src/main/java/com/woniu/connection/dao/AccountDao.java b/threadconnectiondemo/src/main/java/com/woniu/connection/dao/AccountDao.java
new file mode 100644
index 0000000..109174a
--- /dev/null
+++ b/threadconnectiondemo/src/main/java/com/woniu/connection/dao/AccountDao.java
@@ -0,0 +1,37 @@
+package com.woniu.connection.dao;
+
+import com.woniu.connection.utils.JdbcUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+@Service
+public class AccountDao {
+
+ @Autowired
+ private JdbcUtils jdbcUtils;
+
+ //转出
+ public void out(String outUser, int money) throws SQLException {
+ String sql = "update account set money = money - ? where name = ?";
+ Connection conn = jdbcUtils.getConnection();
+ PreparedStatement pstm = conn.prepareStatement(sql);
+ pstm.setInt(1, money);
+ pstm.setString(2, outUser);
+ pstm.executeUpdate();
+ }
+
+ //转入
+ public void in(String inUser, int money) throws SQLException {
+ String sql = "update account set money = money + ? where name = ?";
+
+ Connection conn = jdbcUtils.getConnection();
+ PreparedStatement pstm = conn.prepareStatement(sql);
+ pstm.setInt(1, money);
+ pstm.setString(2, inUser);
+ pstm.executeUpdate();
+ }
+}
diff --git a/threadconnectiondemo/src/main/java/com/woniu/connection/entity/User.java b/threadconnectiondemo/src/main/java/com/woniu/connection/entity/User.java
new file mode 100644
index 0000000..1aff49f
--- /dev/null
+++ b/threadconnectiondemo/src/main/java/com/woniu/connection/entity/User.java
@@ -0,0 +1,9 @@
+package com.woniu.connection.entity;
+
+import lombok.Data;
+
+@Data
+public class User {
+ private String userName;
+ private String password;
+}
diff --git a/threadconnectiondemo/src/main/java/com/woniu/connection/interceptor/LoginUserInterceptor.java b/threadconnectiondemo/src/main/java/com/woniu/connection/interceptor/LoginUserInterceptor.java
new file mode 100644
index 0000000..3c99a29
--- /dev/null
+++ b/threadconnectiondemo/src/main/java/com/woniu/connection/interceptor/LoginUserInterceptor.java
@@ -0,0 +1,40 @@
+package com.woniu.connection.interceptor;
+
+import com.woniu.connection.constant.AuthServerConstant;
+import com.woniu.connection.entity.User;
+import org.springframework.stereotype.Component;
+import org.springframework.util.AntPathMatcher;
+import org.springframework.web.servlet.HandlerAdapter;
+import org.springframework.web.servlet.HandlerInterceptor;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.PrintWriter;
+
+@Component
+public class LoginUserInterceptor implements HandlerInterceptor {
+
+ public static ThreadLocal loginUser = new ThreadLocal<>();
+
+ @Override
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+
+ //获取登录的用户信息
+ User attribute = (User) request.getSession().getAttribute(AuthServerConstant.LOGIN_USER);
+
+ if (attribute != null) {
+ //把登录后用户的信息放在ThreadLocal里面进行保存
+ loginUser.set(attribute);
+ return true;
+ } else {
+ //未登录,返回登录页面
+ response.setContentType("text/html;charset=UTF-8");
+ PrintWriter out = response.getWriter();
+ out.println("");
+ return false;
+ }
+ }
+
+
+}
diff --git a/threadconnectiondemo/src/main/java/com/woniu/connection/properties/DataSourceProperties.java b/threadconnectiondemo/src/main/java/com/woniu/connection/properties/DataSourceProperties.java
new file mode 100644
index 0000000..b78afce
--- /dev/null
+++ b/threadconnectiondemo/src/main/java/com/woniu/connection/properties/DataSourceProperties.java
@@ -0,0 +1,202 @@
+/**
+ * Copyright (c) 2018 人人开源 All rights reserved.
+ *
+ * https://www.renren.io
+ *
+ * 版权所有,侵权必究!
+ */
+
+package com.woniu.connection.properties;
+
+/**
+ * 多数据源属性
+ *
+ * @author 蜗牛
+ * @since 1.0.0
+ */
+public class DataSourceProperties {
+ private String driverClassName;
+ private String url;
+ private String username;
+ private String password;
+
+ /**
+ * Druid默认参数
+ */
+ private int initialSize = 2;
+ private int maxActive = 10;
+ private int minIdle = -1;
+ private long maxWait = 60 * 1000L;
+ private long timeBetweenEvictionRunsMillis = 60 * 1000L;
+ private long minEvictableIdleTimeMillis = 1000L * 60L * 30L;
+ private long maxEvictableIdleTimeMillis = 1000L * 60L * 60L * 7;
+ private String validationQuery = "select 1";
+ private int validationQueryTimeout = -1;
+ private boolean testOnBorrow = false;
+ private boolean testOnReturn = false;
+ private boolean testWhileIdle = true;
+ private boolean poolPreparedStatements = false;
+ private int maxOpenPreparedStatements = -1;
+ private boolean sharePreparedStatements = false;
+ private String filters = "stat,wall";
+
+ public String getDriverClassName() {
+ return driverClassName;
+ }
+
+ public void setDriverClassName(String driverClassName) {
+ this.driverClassName = driverClassName;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public int getInitialSize() {
+ return initialSize;
+ }
+
+ public void setInitialSize(int initialSize) {
+ this.initialSize = initialSize;
+ }
+
+ public int getMaxActive() {
+ return maxActive;
+ }
+
+ public void setMaxActive(int maxActive) {
+ this.maxActive = maxActive;
+ }
+
+ public int getMinIdle() {
+ return minIdle;
+ }
+
+ public void setMinIdle(int minIdle) {
+ this.minIdle = minIdle;
+ }
+
+ public long getMaxWait() {
+ return maxWait;
+ }
+
+ public void setMaxWait(long maxWait) {
+ this.maxWait = maxWait;
+ }
+
+ public long getTimeBetweenEvictionRunsMillis() {
+ return timeBetweenEvictionRunsMillis;
+ }
+
+ public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
+ this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
+ }
+
+ public long getMinEvictableIdleTimeMillis() {
+ return minEvictableIdleTimeMillis;
+ }
+
+ public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
+ this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
+ }
+
+ public long getMaxEvictableIdleTimeMillis() {
+ return maxEvictableIdleTimeMillis;
+ }
+
+ public void setMaxEvictableIdleTimeMillis(long maxEvictableIdleTimeMillis) {
+ this.maxEvictableIdleTimeMillis = maxEvictableIdleTimeMillis;
+ }
+
+ public String getValidationQuery() {
+ return validationQuery;
+ }
+
+ public void setValidationQuery(String validationQuery) {
+ this.validationQuery = validationQuery;
+ }
+
+ public int getValidationQueryTimeout() {
+ return validationQueryTimeout;
+ }
+
+ public void setValidationQueryTimeout(int validationQueryTimeout) {
+ this.validationQueryTimeout = validationQueryTimeout;
+ }
+
+ public boolean isTestOnBorrow() {
+ return testOnBorrow;
+ }
+
+ public void setTestOnBorrow(boolean testOnBorrow) {
+ this.testOnBorrow = testOnBorrow;
+ }
+
+ public boolean isTestOnReturn() {
+ return testOnReturn;
+ }
+
+ public void setTestOnReturn(boolean testOnReturn) {
+ this.testOnReturn = testOnReturn;
+ }
+
+ public boolean isTestWhileIdle() {
+ return testWhileIdle;
+ }
+
+ public void setTestWhileIdle(boolean testWhileIdle) {
+ this.testWhileIdle = testWhileIdle;
+ }
+
+ public boolean isPoolPreparedStatements() {
+ return poolPreparedStatements;
+ }
+
+ public void setPoolPreparedStatements(boolean poolPreparedStatements) {
+ this.poolPreparedStatements = poolPreparedStatements;
+ }
+
+ public int getMaxOpenPreparedStatements() {
+ return maxOpenPreparedStatements;
+ }
+
+ public void setMaxOpenPreparedStatements(int maxOpenPreparedStatements) {
+ this.maxOpenPreparedStatements = maxOpenPreparedStatements;
+ }
+
+ public boolean isSharePreparedStatements() {
+ return sharePreparedStatements;
+ }
+
+ public void setSharePreparedStatements(boolean sharePreparedStatements) {
+ this.sharePreparedStatements = sharePreparedStatements;
+ }
+
+ public String getFilters() {
+ return filters;
+ }
+
+ public void setFilters(String filters) {
+ this.filters = filters;
+ }
+}
\ No newline at end of file
diff --git a/threadconnectiondemo/src/main/java/com/woniu/connection/properties/DynamicDataSourceProperties.java b/threadconnectiondemo/src/main/java/com/woniu/connection/properties/DynamicDataSourceProperties.java
new file mode 100644
index 0000000..1036de3
--- /dev/null
+++ b/threadconnectiondemo/src/main/java/com/woniu/connection/properties/DynamicDataSourceProperties.java
@@ -0,0 +1,33 @@
+/**
+ * Copyright (c) 2018 人人开源 All rights reserved.
+ *
+ * https://www.renren.io
+ *
+ * 版权所有,侵权必究!
+ */
+
+package com.woniu.connection.properties;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * 多数据源属性
+ *
+ * @author 蜗牛
+ * @since 1.0.0
+ */
+@ConfigurationProperties(prefix = "dynamic")
+public class DynamicDataSourceProperties {
+ private Map datasource = new LinkedHashMap<>();
+
+ public Map getDatasource() {
+ return datasource;
+ }
+
+ public void setDatasource(Map datasource) {
+ this.datasource = datasource;
+ }
+}
diff --git a/threadconnectiondemo/src/main/java/com/woniu/connection/service/AService.java b/threadconnectiondemo/src/main/java/com/woniu/connection/service/AService.java
new file mode 100644
index 0000000..c9ae2bb
--- /dev/null
+++ b/threadconnectiondemo/src/main/java/com/woniu/connection/service/AService.java
@@ -0,0 +1,15 @@
+package com.woniu.connection.service;
+
+import org.springframework.stereotype.Service;
+
+@Service
+public class AService {
+
+ public void C() {
+ String s = DealService.threadLocal.get();
+ //做处理
+ System.out.println(s);
+ DealService.threadLocal.remove();
+ }
+
+}
diff --git a/threadconnectiondemo/src/main/java/com/woniu/connection/service/AccountService.java b/threadconnectiondemo/src/main/java/com/woniu/connection/service/AccountService.java
new file mode 100644
index 0000000..141fe48
--- /dev/null
+++ b/threadconnectiondemo/src/main/java/com/woniu/connection/service/AccountService.java
@@ -0,0 +1,64 @@
+package com.woniu.connection.service;
+
+
+import com.woniu.connection.dao.AccountDao;
+import com.woniu.connection.utils.JdbcUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+/*
+ *
+ * 事务的使用注意点:
+ * 1. service层和dao层的连接对象保持一致
+ * 2. 每个线程的connection对象必须前后一致, 线程隔离
+ *
+ * 常规的解决方案
+ * 1. 传参 : 将service层的connection对象直接传递到dao层
+ * 2. 加锁
+ *
+ * 常规解决方案的弊端:
+ * 1. 提高代码耦合度
+ * 2. 降低程序性能
+ * */
+
+@Service
+public class AccountService {
+
+ @Autowired
+ private AccountDao accountDao;
+
+ @Autowired
+ private JdbcUtils jdbcUtils;
+
+ //转账
+ public boolean transfer(String outUser, String inUser, int money) {
+
+ Connection conn = null;
+ try {
+ //1. 开启事务
+ conn = jdbcUtils.getConnection();
+ conn.setAutoCommit(false);
+
+ // 转出
+ accountDao.out(outUser, money);
+ //算术异常: 模拟转出成功,转入失败
+ int i = 1 / 0;
+ // 转入
+ accountDao.in(inUser, money);
+
+ //2. 成功提交
+ jdbcUtils.commitAndClose(conn);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ //2. 或者失败回滚
+ jdbcUtils.rollbackAndClose(conn);
+ return false;
+ }
+
+ return true;
+ }
+
+}
diff --git a/threadconnectiondemo/src/main/java/com/woniu/connection/service/DealService.java b/threadconnectiondemo/src/main/java/com/woniu/connection/service/DealService.java
new file mode 100644
index 0000000..cf4ed69
--- /dev/null
+++ b/threadconnectiondemo/src/main/java/com/woniu/connection/service/DealService.java
@@ -0,0 +1,28 @@
+package com.woniu.connection.service;
+
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class DealService {
+
+ static final ThreadLocal threadLocal = new ThreadLocal();
+
+ @Autowired
+ private AService aService;
+
+ public void dealTransfer() {
+ String address = "nanjing";
+ threadLocal.set(address);
+ A();
+ }
+
+ private void A() {
+ B();
+ }
+
+ private void B() {
+ aService.C();
+ }
+}
diff --git a/threadconnectiondemo/src/main/java/com/woniu/connection/service/LoginService.java b/threadconnectiondemo/src/main/java/com/woniu/connection/service/LoginService.java
new file mode 100644
index 0000000..ba988c3
--- /dev/null
+++ b/threadconnectiondemo/src/main/java/com/woniu/connection/service/LoginService.java
@@ -0,0 +1,21 @@
+package com.woniu.connection.service;
+
+import com.woniu.connection.entity.User;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+@Service
+public class LoginService {
+
+
+
+ public User login(String userName, String passWord) {
+ //假设登录成功
+ if (!StringUtils.isEmpty(userName)&& !StringUtils.isEmpty(passWord)) {
+ User user1 = new User();
+ user1.setUserName("蜗牛");
+ return user1;
+ }
+ return null;
+ }
+}
diff --git a/threadconnectiondemo/src/main/java/com/woniu/connection/utils/JdbcUtils.java b/threadconnectiondemo/src/main/java/com/woniu/connection/utils/JdbcUtils.java
new file mode 100644
index 0000000..dc4b8f1
--- /dev/null
+++ b/threadconnectiondemo/src/main/java/com/woniu/connection/utils/JdbcUtils.java
@@ -0,0 +1,78 @@
+package com.woniu.connection.utils;
+
+import com.alibaba.druid.pool.DruidDataSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+@Component
+public class JdbcUtils {
+
+ static ThreadLocal tl = new ThreadLocal<>();
+
+ @Autowired
+ private DruidDataSource dataSource;
+
+ // 获取连接
+ /*
+ * 原本: 直接从连接池中获取连接
+ * 现在:
+ * 1. 直接获取当前线程绑定的连接对象
+ * 2. 如果连接对象是空的
+ * 2.1 再去连接池中获取连接
+ * 2.2 将此连接对象跟当前线程进行绑定
+ * */
+ public Connection getConnection() throws SQLException {
+ Connection conn = tl.get();
+ if(conn == null){
+ conn = dataSource.getConnection();
+ tl.set(conn);
+ }
+ return conn;
+ }
+ //释放资源
+ public void release(AutoCloseable... ios){
+ for (AutoCloseable io : ios) {
+ if(io != null){
+ try {
+ io.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ public void commitAndClose(Connection conn) {
+ try {
+ if(conn != null){
+ //提交事务
+ conn.commit();
+ //解绑当前线程绑定的连接对象
+ tl.remove();
+ //释放连接
+ conn.close();
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void rollbackAndClose(Connection conn) {
+ try {
+ if(conn != null){
+ //回滚事务
+ conn.rollback();
+ //解绑当前线程绑定的连接对象
+ tl.remove();
+ //释放连接
+ conn.close();
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/threadconnectiondemo/src/main/java/com/woniu/connection/utils/R.java b/threadconnectiondemo/src/main/java/com/woniu/connection/utils/R.java
new file mode 100644
index 0000000..f558be5
--- /dev/null
+++ b/threadconnectiondemo/src/main/java/com/woniu/connection/utils/R.java
@@ -0,0 +1,64 @@
+/**
+ * Copyright (c) 2016-2019 人人开源 All rights reserved.
+ *
+ * https://www.renren.io
+ *
+ * 版权所有,侵权必究!
+ */
+
+package com.woniu.connection.utils;
+
+import org.apache.http.HttpStatus;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 返回数据
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+public class R extends HashMap {
+ private static final long serialVersionUID = 1L;
+
+ public R() {
+ put("code", 0);
+ put("msg", "success");
+ }
+
+ public static R error() {
+ return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, "未知异常,请联系管理员");
+ }
+
+ public static R error(String msg) {
+ return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, msg);
+ }
+
+ public static R error(int code, String msg) {
+ R r = new R();
+ r.put("code", code);
+ r.put("msg", msg);
+ return r;
+ }
+
+ public static R ok(String msg) {
+ R r = new R();
+ r.put("msg", msg);
+ return r;
+ }
+
+ public static R ok(Map map) {
+ R r = new R();
+ r.putAll(map);
+ return r;
+ }
+
+ public static R ok() {
+ return new R();
+ }
+
+ public R put(String key, Object value) {
+ super.put(key, value);
+ return this;
+ }
+}
diff --git a/threadconnectiondemo/src/main/java/com/woniu/connection/utils/ThreadSafeFormatterUtil.java b/threadconnectiondemo/src/main/java/com/woniu/connection/utils/ThreadSafeFormatterUtil.java
new file mode 100644
index 0000000..5315ca8
--- /dev/null
+++ b/threadconnectiondemo/src/main/java/com/woniu/connection/utils/ThreadSafeFormatterUtil.java
@@ -0,0 +1,16 @@
+package com.woniu.connection.utils;
+
+
+import java.text.SimpleDateFormat;
+
+public class ThreadSafeFormatterUtil {
+
+ public static ThreadLocal dateFormatThreadLocal = new ThreadLocal() {
+
+ //创建一份 SimpleDateFormat 对象
+ @Override
+ protected SimpleDateFormat initialValue() {
+ return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
+ }
+ };
+}
diff --git a/threadconnectiondemo/src/main/java/com/woniu/connection/web/WebController.java b/threadconnectiondemo/src/main/java/com/woniu/connection/web/WebController.java
new file mode 100644
index 0000000..d733691
--- /dev/null
+++ b/threadconnectiondemo/src/main/java/com/woniu/connection/web/WebController.java
@@ -0,0 +1,126 @@
+package com.woniu.connection.web;
+
+import com.woniu.connection.constant.AuthServerConstant;
+import com.woniu.connection.entity.User;
+import com.woniu.connection.interceptor.LoginUserInterceptor;
+import com.woniu.connection.service.AccountService;
+import com.woniu.connection.service.DealService;
+import com.woniu.connection.service.LoginService;
+import com.woniu.connection.utils.R;
+import com.woniu.connection.utils.ThreadSafeFormatterUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 公众号 :woniuxgg ,回复 :”源码“
+ */
+@RestController
+@RequestMapping("/app")
+public class WebController {
+
+
+ @Autowired
+ private AccountService accountService;
+
+ /**
+ * ThreadLocal实战 代码演示 工作中是怎么使用的
+ * demo1 每个线程绑定一个连接 实现线程内隔离 控制事务
+ * @return
+ */
+ @GetMapping("transfer")
+ public R transfer() {
+ // 模拟数据 : woniu 给 lili 转账 100
+ String outUser = "woniu";
+ String inUser = "lili";
+ int money = 100;
+
+ boolean result = accountService.transfer(outUser, inUser, money);
+
+ if (!result) {
+ System.out.println("转账失败!");
+ } else {
+ System.out.println("转账成功!");
+ }
+ return R.ok();
+ }
+
+
+ @Autowired
+ private LoginService loginService;
+
+ /**
+ * demo2 每个线程内需要保存全局变量(例如在拦截器中获取用户信息),可以让不同方法直接使用,避免参数传递的麻烦
+ *
+ * @return
+ */
+ @GetMapping("login")
+ public R login(@RequestParam String userName, @RequestParam String passWord, HttpServletRequest httpServletRequest) {
+
+ //用户登录 返回实体类
+ User userLogin = loginService.login(userName,passWord);
+
+ //放入session中
+ HttpSession session = httpServletRequest.getSession();
+ session.setAttribute(AuthServerConstant.LOGIN_USER, userLogin);
+
+ return R.ok();
+ }
+
+
+ /**
+ * 获得用户信息 localhost:8080/app/getUser
+ * @return
+ */
+ @GetMapping("getUser")
+ public R getUser() {
+
+ User user = LoginUserInterceptor.loginUser.get();
+ return R.ok().put("user",user);
+ }
+
+
+ @Autowired
+ private DealService dealService;
+
+ /**
+ * demo3 在方法调用的过程中 用来代替参数传值!
+ * @return
+ */
+ @GetMapping("dealTransfer")
+ public R dealTransfer() {
+
+ dealService.dealTransfer();
+ return R.ok();
+ }
+
+
+ /**
+ * demo4 每个线程需要一个独享对象(通常是工具类,典型需要使用的类有SimpleDateFormat)
+ * 每个Thread内有自己的实例副本,不共享
+ * @return
+ */
+ @GetMapping("dealDate")
+ public R dealDate() {
+
+ for (int i = 0; i < 30; i++) {
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ SimpleDateFormat simpleDateFormat = ThreadSafeFormatterUtil.dateFormatThreadLocal.get();
+ String date = simpleDateFormat.format(new Date());
+ System.out.println(date);
+ }
+ }).start();
+ }
+ return R.ok();
+ }
+
+
+}
diff --git a/threadconnectiondemo/src/main/resources/application.yml b/threadconnectiondemo/src/main/resources/application.yml
new file mode 100644
index 0000000..22b8b90
--- /dev/null
+++ b/threadconnectiondemo/src/main/resources/application.yml
@@ -0,0 +1,39 @@
+
+
+spring:
+ datasource:
+ type: com.alibaba.druid.pool.DruidDataSource
+ druid:
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
+ username: root
+ password: 123456
+ initial-size: 10
+ max-active: 100
+ min-idle: 10
+ max-wait: 60000
+ pool-prepared-statements: true
+ max-pool-prepared-statement-per-connection-size: 20
+ time-between-eviction-runs-millis: 60000
+ min-evictable-idle-time-millis: 300000
+ #Oracle需要打开注释
+ #validation-query: SELECT 1 FROM DUAL
+ test-while-idle: true
+ test-on-borrow: false
+ test-on-return: false
+ stat-view-servlet:
+ enabled: true
+ url-pattern: /druid/*
+ #login-username: admin
+ #login-password: admin
+ filter:
+ stat:
+ log-slow-sql: true
+ slow-sql-millis: 1000
+ merge-sql: false
+ wall:
+ config:
+ multi-statement-allow: true
+server:
+ port: 8080
+
diff --git a/threadconnectiondemo/target/classes/application.yml b/threadconnectiondemo/target/classes/application.yml
new file mode 100644
index 0000000..22b8b90
--- /dev/null
+++ b/threadconnectiondemo/target/classes/application.yml
@@ -0,0 +1,39 @@
+
+
+spring:
+ datasource:
+ type: com.alibaba.druid.pool.DruidDataSource
+ druid:
+ driver-class-name: com.mysql.cj.jdbc.Driver
+ url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
+ username: root
+ password: 123456
+ initial-size: 10
+ max-active: 100
+ min-idle: 10
+ max-wait: 60000
+ pool-prepared-statements: true
+ max-pool-prepared-statement-per-connection-size: 20
+ time-between-eviction-runs-millis: 60000
+ min-evictable-idle-time-millis: 300000
+ #Oracle需要打开注释
+ #validation-query: SELECT 1 FROM DUAL
+ test-while-idle: true
+ test-on-borrow: false
+ test-on-return: false
+ stat-view-servlet:
+ enabled: true
+ url-pattern: /druid/*
+ #login-username: admin
+ #login-password: admin
+ filter:
+ stat:
+ log-slow-sql: true
+ slow-sql-millis: 1000
+ merge-sql: false
+ wall:
+ config:
+ multi-statement-allow: true
+server:
+ port: 8080
+
diff --git a/threadconnectiondemo/target/classes/com/woniu/connection/MainApplication.class b/threadconnectiondemo/target/classes/com/woniu/connection/MainApplication.class
new file mode 100644
index 0000000..838ffa5
Binary files /dev/null and b/threadconnectiondemo/target/classes/com/woniu/connection/MainApplication.class differ
diff --git a/threadconnectiondemo/target/classes/com/woniu/connection/config/DynamicDataSourceConfig.class b/threadconnectiondemo/target/classes/com/woniu/connection/config/DynamicDataSourceConfig.class
new file mode 100644
index 0000000..f8c8038
Binary files /dev/null and b/threadconnectiondemo/target/classes/com/woniu/connection/config/DynamicDataSourceConfig.class differ
diff --git a/threadconnectiondemo/target/classes/com/woniu/connection/config/DynamicDataSourceFactory.class b/threadconnectiondemo/target/classes/com/woniu/connection/config/DynamicDataSourceFactory.class
new file mode 100644
index 0000000..960ed6c
Binary files /dev/null and b/threadconnectiondemo/target/classes/com/woniu/connection/config/DynamicDataSourceFactory.class differ
diff --git a/threadconnectiondemo/target/classes/com/woniu/connection/config/WebConfig.class b/threadconnectiondemo/target/classes/com/woniu/connection/config/WebConfig.class
new file mode 100644
index 0000000..111064a
Binary files /dev/null and b/threadconnectiondemo/target/classes/com/woniu/connection/config/WebConfig.class differ
diff --git a/threadconnectiondemo/target/classes/com/woniu/connection/constant/AuthServerConstant.class b/threadconnectiondemo/target/classes/com/woniu/connection/constant/AuthServerConstant.class
new file mode 100644
index 0000000..254c1df
Binary files /dev/null and b/threadconnectiondemo/target/classes/com/woniu/connection/constant/AuthServerConstant.class differ
diff --git a/threadconnectiondemo/target/classes/com/woniu/connection/dao/AccountDao.class b/threadconnectiondemo/target/classes/com/woniu/connection/dao/AccountDao.class
new file mode 100644
index 0000000..245ea9e
Binary files /dev/null and b/threadconnectiondemo/target/classes/com/woniu/connection/dao/AccountDao.class differ
diff --git a/threadconnectiondemo/target/classes/com/woniu/connection/entity/User.class b/threadconnectiondemo/target/classes/com/woniu/connection/entity/User.class
new file mode 100644
index 0000000..dee0794
Binary files /dev/null and b/threadconnectiondemo/target/classes/com/woniu/connection/entity/User.class differ
diff --git a/threadconnectiondemo/target/classes/com/woniu/connection/interceptor/LoginUserInterceptor.class b/threadconnectiondemo/target/classes/com/woniu/connection/interceptor/LoginUserInterceptor.class
new file mode 100644
index 0000000..49257e9
Binary files /dev/null and b/threadconnectiondemo/target/classes/com/woniu/connection/interceptor/LoginUserInterceptor.class differ
diff --git a/threadconnectiondemo/target/classes/com/woniu/connection/properties/DataSourceProperties.class b/threadconnectiondemo/target/classes/com/woniu/connection/properties/DataSourceProperties.class
new file mode 100644
index 0000000..b925c77
Binary files /dev/null and b/threadconnectiondemo/target/classes/com/woniu/connection/properties/DataSourceProperties.class differ
diff --git a/threadconnectiondemo/target/classes/com/woniu/connection/properties/DynamicDataSourceProperties.class b/threadconnectiondemo/target/classes/com/woniu/connection/properties/DynamicDataSourceProperties.class
new file mode 100644
index 0000000..13815bb
Binary files /dev/null and b/threadconnectiondemo/target/classes/com/woniu/connection/properties/DynamicDataSourceProperties.class differ
diff --git a/threadconnectiondemo/target/classes/com/woniu/connection/service/AService.class b/threadconnectiondemo/target/classes/com/woniu/connection/service/AService.class
new file mode 100644
index 0000000..6acbe60
Binary files /dev/null and b/threadconnectiondemo/target/classes/com/woniu/connection/service/AService.class differ
diff --git a/threadconnectiondemo/target/classes/com/woniu/connection/service/AccountService.class b/threadconnectiondemo/target/classes/com/woniu/connection/service/AccountService.class
new file mode 100644
index 0000000..0d7c342
Binary files /dev/null and b/threadconnectiondemo/target/classes/com/woniu/connection/service/AccountService.class differ
diff --git a/threadconnectiondemo/target/classes/com/woniu/connection/service/DealService.class b/threadconnectiondemo/target/classes/com/woniu/connection/service/DealService.class
new file mode 100644
index 0000000..28cb4fb
Binary files /dev/null and b/threadconnectiondemo/target/classes/com/woniu/connection/service/DealService.class differ
diff --git a/threadconnectiondemo/target/classes/com/woniu/connection/service/LoginService.class b/threadconnectiondemo/target/classes/com/woniu/connection/service/LoginService.class
new file mode 100644
index 0000000..766defe
Binary files /dev/null and b/threadconnectiondemo/target/classes/com/woniu/connection/service/LoginService.class differ
diff --git a/threadconnectiondemo/target/classes/com/woniu/connection/utils/JdbcUtils.class b/threadconnectiondemo/target/classes/com/woniu/connection/utils/JdbcUtils.class
new file mode 100644
index 0000000..d77ddfb
Binary files /dev/null and b/threadconnectiondemo/target/classes/com/woniu/connection/utils/JdbcUtils.class differ
diff --git a/threadconnectiondemo/target/classes/com/woniu/connection/utils/R.class b/threadconnectiondemo/target/classes/com/woniu/connection/utils/R.class
new file mode 100644
index 0000000..b47be5d
Binary files /dev/null and b/threadconnectiondemo/target/classes/com/woniu/connection/utils/R.class differ
diff --git a/threadconnectiondemo/target/classes/com/woniu/connection/utils/ThreadSafeFormatterUtil$1.class b/threadconnectiondemo/target/classes/com/woniu/connection/utils/ThreadSafeFormatterUtil$1.class
new file mode 100644
index 0000000..f03a6f5
Binary files /dev/null and b/threadconnectiondemo/target/classes/com/woniu/connection/utils/ThreadSafeFormatterUtil$1.class differ
diff --git a/threadconnectiondemo/target/classes/com/woniu/connection/utils/ThreadSafeFormatterUtil.class b/threadconnectiondemo/target/classes/com/woniu/connection/utils/ThreadSafeFormatterUtil.class
new file mode 100644
index 0000000..81a59be
Binary files /dev/null and b/threadconnectiondemo/target/classes/com/woniu/connection/utils/ThreadSafeFormatterUtil.class differ
diff --git a/threadconnectiondemo/target/classes/com/woniu/connection/web/WebController$1.class b/threadconnectiondemo/target/classes/com/woniu/connection/web/WebController$1.class
new file mode 100644
index 0000000..b3aee85
Binary files /dev/null and b/threadconnectiondemo/target/classes/com/woniu/connection/web/WebController$1.class differ
diff --git a/threadconnectiondemo/target/classes/com/woniu/connection/web/WebController.class b/threadconnectiondemo/target/classes/com/woniu/connection/web/WebController.class
new file mode 100644
index 0000000..9cd5ff3
Binary files /dev/null and b/threadconnectiondemo/target/classes/com/woniu/connection/web/WebController.class differ
diff --git a/threadconnectiondemo/threadconnectiondemo.iml b/threadconnectiondemo/threadconnectiondemo.iml
new file mode 100644
index 0000000..17b1fdb
--- /dev/null
+++ b/threadconnectiondemo/threadconnectiondemo.iml
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file