环境:
Spring Boot 2.4.3
Druid 1.1.23
Mysql 8.0
实现功能:利用乐观锁实现对表中一个字段进行相加操作。
1、Mysql 8.0 加大连接数,登录到Mysql,输入命令:setpersist max_connections=1000;
2、项目中druid配置:
#表明使用Druid连接池
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
# 初始化时建立物理连接的个数
spring.datasource.initialSize=5
# 最小连接池数量
spring.datasource.minIdle=5
# 最大连接池数量
spring.datasource.maxActive=1000
# 获取连接时最大等待时间,单位毫秒
spring.datasource.maxWait=10000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
spring.datasource.timeBetweenEvictionRunsMillis=60000
# 连接保持空闲而不被驱逐的最小时间
spring.datasource.minEvictableIdleTimeMillis=300000
# 用来检测连接是否有效的sql,要求是一个查询语句
spring.datasource.validationQuery=SELECT 1 FROM DUAL
# 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
spring.datasource.testWhileIdle=true
# 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能
spring.datasource.testOnBorrow=false
# 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。
spring.datasource.testOnReturn=false
# 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。
spring.datasource.poolPreparedStatements=true
# 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计
spring.datasource.filters=stat,wall,log4j
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
3、Spring代码
Controller层:
@PostMapping("updateAmount")
public String updateAmount(@RequestBody JSONObject jsonObject)throws SQLException {
Double amount = jsonObject.getDoubleValue("amount");
boolean flag =false;
int count =1;
for (int i =0; i <3; i++) {
Integer version =userService.getAmontVersion();
if (userService.updateAmount(amount,version)) {
flag =true;
break;
}
count++;
}
System.out.println("========== count: " + count +", flag: " + flag);
if (flag) {
return "successfully";
}
return "failed";
}
Service层:
@Override
public boolean updateAmount(Double amount,Integer version)throws SQLException {
return druidDao.updateAmount(amount, version);
}
@Override
public Integer getAmontVersion()throws SQLException {
return druidDao.getAmontVersion();
}
DAO层:
@Override
public boolean updateAmount(Double amount,Integer version)throws SQLException {
QueryRunner queryRunner =new QueryRunner();
String sql ="update t_pay_amount set amount=amount+" + amount;
sql +=", version=version+1";
sql +=" where version=" + version;
Connection connection =dataSource.getConnection();
int result =queryRunner.update(connection, sql);
connection.close();
return (result ==1) ?true :false;
}
@Override
public Integer getAmontVersion()throws SQLException {
QueryRunner queryRunner =new QueryRunner();
String sql ="select version from t_pay_amount";
Connection connection =dataSource.getConnection();
Integer version = ((Integer)queryRunner.query(connection,sql,new ScalarHandler()));
connection.close();
if (null ==version) {
return 0;
}
return version;
}
重点在于DAO在使用Connection连接后,要立即关闭,否则会导致连接突然增多,其它请求过来时无法连接到数据库,引起连接超时,从而请求失败。