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