马府强
2 years ago
42 changed files with 1122 additions and 0 deletions
@ -0,0 +1,74 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
|||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
<parent> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-parent</artifactId> |
|||
<version>2.1.8.RELEASE</version> |
|||
<relativePath/> <!-- lookup parent from repository --> |
|||
</parent> |
|||
<groupId>com.woniu.connection</groupId> |
|||
<artifactId>threadconnectiondemo</artifactId> |
|||
<version>1.0-SNAPSHOT</version> |
|||
|
|||
<dependencies> |
|||
<dependency> |
|||
<groupId>com.baomidou</groupId> |
|||
<artifactId>mybatis-plus-boot-starter</artifactId> |
|||
<version>3.5.2</version> |
|||
</dependency> |
|||
|
|||
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> |
|||
<dependency> |
|||
<groupId>org.projectlombok</groupId> |
|||
<artifactId>lombok</artifactId> |
|||
<version>1.18.24</version> |
|||
</dependency> |
|||
|
|||
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient --> |
|||
<dependency> |
|||
<groupId>org.apache.httpcomponents</groupId> |
|||
<artifactId>httpclient</artifactId> |
|||
<version>4.5.13</version> |
|||
</dependency> |
|||
|
|||
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> |
|||
<dependency> |
|||
<groupId>mysql</groupId> |
|||
<artifactId>mysql-connector-java</artifactId> |
|||
<version>8.0.29</version> |
|||
</dependency> |
|||
|
|||
<!-- https://mvnrepository.com/artifact/commons-lang/commons-lang --> |
|||
<dependency> |
|||
<groupId>commons-lang</groupId> |
|||
<artifactId>commons-lang</artifactId> |
|||
<version>2.6</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>jakarta.validation</groupId> |
|||
<artifactId>jakarta.validation-api</artifactId> |
|||
<version>2.0.2</version> |
|||
<scope>compile</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-web</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>com.alibaba</groupId> |
|||
<artifactId>fastjson</artifactId> |
|||
<version>1.2.15</version> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>com.alibaba</groupId> |
|||
<artifactId>druid-spring-boot-starter</artifactId> |
|||
<version>1.1.13</version> |
|||
</dependency> |
|||
|
|||
</dependencies> |
|||
</project> |
@ -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); |
|||
} |
|||
} |
@ -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; |
|||
} |
|||
|
|||
|
|||
} |
@ -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; |
|||
} |
|||
} |
@ -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"); |
|||
} |
|||
} |
@ -0,0 +1,7 @@ |
|||
package com.woniu.connection.constant; |
|||
|
|||
public class AuthServerConstant { |
|||
|
|||
public static final String LOGIN_USER = "loginUser"; |
|||
|
|||
} |
@ -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(); |
|||
} |
|||
} |
@ -0,0 +1,9 @@ |
|||
package com.woniu.connection.entity; |
|||
|
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
public class User { |
|||
private String userName; |
|||
private String password; |
|||
} |
@ -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<User> 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("<script>alert('请先进行登录,再进行后续操作!')</script>"); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
|
|||
} |
@ -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; |
|||
} |
|||
} |
@ -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<String, DataSourceProperties> datasource = new LinkedHashMap<>(); |
|||
|
|||
public Map<String, DataSourceProperties> getDatasource() { |
|||
return datasource; |
|||
} |
|||
|
|||
public void setDatasource(Map<String, DataSourceProperties> datasource) { |
|||
this.datasource = datasource; |
|||
} |
|||
} |
@ -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(); |
|||
} |
|||
|
|||
} |
@ -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; |
|||
} |
|||
|
|||
} |
@ -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<String> 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(); |
|||
} |
|||
} |
@ -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; |
|||
} |
|||
} |
@ -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<Connection> 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(); |
|||
} |
|||
} |
|||
|
|||
} |
@ -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<String, Object> { |
|||
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<String, Object> 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; |
|||
} |
|||
} |
@ -0,0 +1,16 @@ |
|||
package com.woniu.connection.utils; |
|||
|
|||
|
|||
import java.text.SimpleDateFormat; |
|||
|
|||
public class ThreadSafeFormatterUtil { |
|||
|
|||
public static ThreadLocal<SimpleDateFormat> dateFormatThreadLocal = new ThreadLocal<SimpleDateFormat>() { |
|||
|
|||
//创建一份 SimpleDateFormat 对象
|
|||
@Override |
|||
protected SimpleDateFormat initialValue() { |
|||
return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); |
|||
} |
|||
}; |
|||
} |
@ -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(); |
|||
} |
|||
|
|||
|
|||
} |
@ -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 |
|||
|
@ -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 |
|||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,92 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4"> |
|||
<component name="FacetManager"> |
|||
<facet type="Spring" name="Spring"> |
|||
<configuration /> |
|||
</facet> |
|||
<facet type="web" name="Web"> |
|||
<configuration> |
|||
<webroots /> |
|||
<sourceRoots> |
|||
<root url="file://$MODULE_DIR$/src/main/java" /> |
|||
<root url="file://$MODULE_DIR$/src/main/resources" /> |
|||
</sourceRoots> |
|||
</configuration> |
|||
</facet> |
|||
</component> |
|||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8"> |
|||
<output url="file://$MODULE_DIR$/target/classes" /> |
|||
<output-test url="file://$MODULE_DIR$/target/test-classes" /> |
|||
<content url="file://$MODULE_DIR$"> |
|||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" /> |
|||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" /> |
|||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" /> |
|||
<excludeFolder url="file://$MODULE_DIR$/target" /> |
|||
</content> |
|||
<orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" /> |
|||
<orderEntry type="sourceFolder" forTests="false" /> |
|||
<orderEntry type="library" name="Maven: com.baomidou:mybatis-plus-boot-starter:3.5.2" level="project" /> |
|||
<orderEntry type="library" name="Maven: com.baomidou:mybatis-plus:3.5.2" level="project" /> |
|||
<orderEntry type="library" name="Maven: com.baomidou:mybatis-plus-extension:3.5.2" level="project" /> |
|||
<orderEntry type="library" name="Maven: com.baomidou:mybatis-plus-core:3.5.2" level="project" /> |
|||
<orderEntry type="library" name="Maven: com.baomidou:mybatis-plus-annotation:3.5.2" level="project" /> |
|||
<orderEntry type="library" name="Maven: com.github.jsqlparser:jsqlparser:4.4" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.mybatis:mybatis:3.5.10" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.mybatis:mybatis-spring:2.0.7" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.2.71" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.jetbrains.kotlin:kotlin-stdlib:1.2.71" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.jetbrains.kotlin:kotlin-stdlib-common:1.2.71" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.jetbrains:annotations:13.0" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.2.71" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-autoconfigure:2.1.8.RELEASE" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot:2.1.8.RELEASE" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-jdbc:2.1.8.RELEASE" level="project" /> |
|||
<orderEntry type="library" name="Maven: com.zaxxer:HikariCP:3.2.0" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.springframework:spring-jdbc:5.1.9.RELEASE" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.springframework:spring-tx:5.1.9.RELEASE" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.projectlombok:lombok:1.18.24" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpclient:4.5.13" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpcore:4.4.12" level="project" /> |
|||
<orderEntry type="library" name="Maven: commons-codec:commons-codec:1.11" level="project" /> |
|||
<orderEntry type="library" name="Maven: mysql:mysql-connector-java:8.0.29" level="project" /> |
|||
<orderEntry type="library" name="Maven: commons-lang:commons-lang:2.6" level="project" /> |
|||
<orderEntry type="library" name="Maven: jakarta.validation:jakarta.validation-api:2.0.2" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-web:2.1.8.RELEASE" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter:2.1.8.RELEASE" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-logging:2.1.8.RELEASE" level="project" /> |
|||
<orderEntry type="library" name="Maven: ch.qos.logback:logback-classic:1.2.3" level="project" /> |
|||
<orderEntry type="library" name="Maven: ch.qos.logback:logback-core:1.2.3" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-to-slf4j:2.11.2" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-api:2.11.2" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.slf4j:jul-to-slf4j:1.7.28" level="project" /> |
|||
<orderEntry type="library" name="Maven: javax.annotation:javax.annotation-api:1.3.2" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.springframework:spring-core:5.1.9.RELEASE" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.springframework:spring-jcl:5.1.9.RELEASE" level="project" /> |
|||
<orderEntry type="library" scope="RUNTIME" name="Maven: org.yaml:snakeyaml:1.23" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-json:2.1.8.RELEASE" level="project" /> |
|||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.9.9.3" level="project" /> |
|||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.9.0" level="project" /> |
|||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.9.9" level="project" /> |
|||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.9.9" level="project" /> |
|||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.9" level="project" /> |
|||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.module:jackson-module-parameter-names:2.9.9" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-tomcat:2.1.8.RELEASE" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-core:9.0.24" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-el:9.0.24" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-websocket:9.0.24" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.hibernate.validator:hibernate-validator:6.0.17.Final" level="project" /> |
|||
<orderEntry type="library" name="Maven: javax.validation:validation-api:2.0.1.Final" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.3.3.Final" level="project" /> |
|||
<orderEntry type="library" name="Maven: com.fasterxml:classmate:1.4.0" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.springframework:spring-web:5.1.9.RELEASE" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.springframework:spring-beans:5.1.9.RELEASE" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.springframework:spring-webmvc:5.1.9.RELEASE" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.springframework:spring-aop:5.1.9.RELEASE" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.springframework:spring-context:5.1.9.RELEASE" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.springframework:spring-expression:5.1.9.RELEASE" level="project" /> |
|||
<orderEntry type="library" name="Maven: com.alibaba:fastjson:1.2.15" level="project" /> |
|||
<orderEntry type="library" name="Maven: com.alibaba:druid-spring-boot-starter:1.1.13" level="project" /> |
|||
<orderEntry type="library" name="Maven: com.alibaba:druid:1.1.13" level="project" /> |
|||
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.28" level="project" /> |
|||
</component> |
|||
</module> |
Loading…
Reference in new issue