单例模式为什么要使用volatile

volatile作用 1.保证可见性 2.禁止指令重排序 重排序 int mod = 0; int a = 1; public void chmod(){ a = 2; mod = 1 } public void test(){ if(mod == 1){ System.out.println(a); } } 由于指令重排序会导致一些前后没有直接联系的代码顺序问题,如chmod中a和mod不直接联系,可能出现mod先为1的情况,此时如果有另一线程执行test就会出问题。 故而使用volatile通过加内存屏障,可以使修饰的变量被执行时,保证之前的命令执行完毕。 单例模式双检锁为什么要volatile public class Single{ private volatile static MyService service; private Single(){ // 私有化构造函数 } public static MyService get(){ if(service == null){ synchronized(Single.class){ if(service == null){ service = new Single(); } } } return service; } } 如上代码,如果没有volatile,线程a执行service = new Single()时,可能导致原本的分配内存、初始化对象、分配地址改变顺序,比方说变成分配内存、分配地址、初始化对象。...

April 10, 2024 · 1 min · 74 words · Me

利用SpringCache实现Redis随机过期时间的解决方案

起因 为了防止缓存雪崩,缓存过期时间最好设置成随机过期。 原始方案 public UserInfoVO getUserInfo(Long id) { // 判断redis中是否存在缓存 String key = "userInfo:" + id; if (Boolean.TRUE.equals(redisTemplate.hasKey(key))){ return (UserInfoVO) redisTemplate.opsForValue().get(key); } if (id == null){ throw new RequestExcetption(MessageConstant.ILLEGAL_REQUEST); } UserInfoDO userInfoDO = userInfoService.getOne(new QueryWrapper<UserInfoDO>().eq("user_id", id)); if (userInfoDO == null || userInfoDO.getDeleted() == 1){ throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND); } UserInfoVO userInfoVO = new UserInfoVO(); BeanUtils.copyProperties(userInfoDO, userInfoVO); // 装入缓存,设置随机时间 Random random = new Random(); redisTemplate.opsForValue().set(key, userInfoVO, 10 + random.nextInt(11), TimeUnit.SECONDS); return userInfoVO; } 比如这里我想把用户信息数据缓存到Redis中,需要利用到RedisTemplate,为每个不同id的数据做key的拼接,然后用Random设置随机过期时间(如上是10-20分钟)。...

April 5, 2024 · 5 min · 1023 words · Me

全局异常捕获器令Seata事务无法回滚的解决方案

起因 项目使用seata进行分布式事务管理 项目使用了全局异常处理器来捕获异常 服务A执行分布式事务: 1.A中方法 2.用Feign调用B中方法,方法抛出异常 最终1.成功提交(未回滚),2.未提交 原因 @RestControllerAdvice @Slf4j public class GlobalExceptionHandler { /** * 捕获业务异常 * @param ex * @return */ @ExceptionHandler public Result<?> exceptionHandler(BaseException ex){ log.error("异常信息:{}", ex.getMessage()); BaseContext.removeCurrentId(); return Result.error(ex.getMessage()); } } 全局异常处理器捕获异常,导致A中方法得到Feign调用的正常返回值,因此Seata认为无异常 解决 @RestControllerAdvice @Slf4j public class GlobalExceptionHandler { /** * 捕获业务异常 * @param ex * @return */ @ExceptionHandler @ResponseBody @ResponseStatus(HttpStatus.BAD_REQUEST) public Result<?> exceptionHandler(BaseException ex){ log.error("异常信息:{}", ex.getMessage()); BaseContext.removeCurrentId(); return Result.error(ex.getMessage()); } } 通过添加响应状态码为4xx,5xx,即可令Feign调用返回异常

April 4, 2024 · 1 min · 67 words · Me

利用Docker安装Seata

Docker拉取 docker pull seataio/seata-server 配置 数据库配置 https://gitcode.com/seata/seata/blob/1.7.1/script/server/db/mysql.sql?init=initRepo 查看数据库sql,并创建数据库seata -- -------------------------------- The script used when storeMode is 'db' -------------------------------- -- the table to store GlobalSession data CREATE TABLE IF NOT EXISTS `global_table` ( `xid` VARCHAR(128) NOT NULL, `transaction_id` BIGINT, `status` TINYINT NOT NULL, `application_id` VARCHAR(32), `transaction_service_group` VARCHAR(32), `transaction_name` VARCHAR(128), `timeout` INT, `begin_time` BIGINT, `application_data` VARCHAR(2000), `gmt_create` DATETIME, `gmt_modified` DATETIME, PRIMARY KEY (`xid`), KEY `idx_status_gmt_modified` (`status` , `gmt_modified`), KEY `idx_transaction_id` (`transaction_id`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4; -- the table to store BranchSession data CREATE TABLE IF NOT EXISTS `branch_table` ( `branch_id` BIGINT NOT NULL, `xid` VARCHAR(128) NOT NULL, `transaction_id` BIGINT, `resource_group_id` VARCHAR(32), `resource_id` VARCHAR(256), `branch_type` VARCHAR(8), `status` TINYINT, `client_id` VARCHAR(64), `application_data` VARCHAR(2000), `gmt_create` DATETIME(6), `gmt_modified` DATETIME(6), PRIMARY KEY (`branch_id`), KEY `idx_xid` (`xid`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4; -- the table to store lock data CREATE TABLE IF NOT EXISTS `lock_table` ( `row_key` VARCHAR(128) NOT NULL, `xid` VARCHAR(128), `transaction_id` BIGINT, `branch_id` BIGINT NOT NULL, `resource_id` VARCHAR(256), `table_name` VARCHAR(32), `pk` VARCHAR(36), `status` TINYINT NOT NULL DEFAULT '0' COMMENT '0:locked ,1:rollbacking', `gmt_create` DATETIME, `gmt_modified` DATETIME, PRIMARY KEY (`row_key`), KEY `idx_status` (`status`), KEY `idx_branch_id` (`branch_id`), KEY `idx_xid` (`xid`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4; CREATE TABLE IF NOT EXISTS `distributed_lock` ( `lock_key` CHAR(20) NOT NULL, `lock_value` VARCHAR(20) NOT NULL, `expire` BIGINT, primary key (`lock_key`) ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4; INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('AsyncCommitting', ' ', 0); INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryCommitting', ' ', 0); INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryRollbacking', ' ', 0); INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('TxTimeoutCheck', ' ', 0); 创建配置文件夹 mkdir -p /home/${username}/docker/seata/resources 启动临时容器获取配置文件后删除临时容器 docker run -d -p 8091:8091 -p 7091:7091 --name seata-server seataio/seata-server docker cp seata-server:/seata-server/resources/....

April 3, 2024 · 4 min · 796 words · Me

Docker安装RabbitMQ

RabbitMQ 拉取 docker pull rabbitmq:management 配置 mkdir -p /home/akiey/docker/rabbitmq/ 启动 docker run -id --name=rabbitmq -v /home/akiey/docker/rabbitmq:/var/lib/rabbitmq -p 15672:15672 -p 5672:5672 --restart=always -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=123456 rabbitmq:management

April 2, 2024 · 1 min · 26 words · Me

Docker安装Redis

Redis 安装 docker pull redis 配置 mkdir -p /home/${username}/docker/redis/conf ## 创建空白配置文件 touch /home/${username}/docker/redis/conf/redis.conf 启动 最后两行顺序不能倒 docker run \ --name redis \ -p 6379:6379 \ --restart always \ -v /home/${username}/docker/redis/data:/data \ -v /home/${username}/docker/redis/conf/redis.conf:/etc/redis/redis.conf \ -d redis \ redis-server /etc/redis/redis.conf

April 1, 2024 · 1 min · 38 words · Me

VMWare Linux 虚拟机配置永久共享文件夹

设置共享文件夹 挂载 创建挂载文件夹 mkdir /mnt/hgfs 挂载 /usr/bin/vmhgfs-fuse .host:/ /mnt/hgfs -o allow_other -o uid=0 -o gid=0 -o umask=022 永久挂载 提升文件权限 chmod 777 /etc/fstab 文件尾行添加内容 echo ".host:/ /mnt/hgfs fuse.vmhgfs-fuse allow_other,uid=0,gid=0,umask=022 0 0" >> /etc/fstab 添加快捷方式 ln -s /mnt/hgfs/${文件夹名称} /home/${username}/桌面

March 30, 2024 · 1 min · 37 words · Me

Ubuntu使用Docker安装Mysql和Nacos,服务注册踩坑

MySQL 安装 docker拉取 docker pull mysql:8.0.27 配置 创建配置挂载文件夹 mkdir -p /home/${username}/docker/mysql/{date,conf} 在conf中新建配置文件my.cnf [mysqld] #Mysql服务的唯一编号 每个mysql服务Id需唯一 server-id=1 #服务端口号 默认3306 port=3306 #mysql安装根目录(default /usr) #basedir=/usr/local/mysql #mysql数据文件所在位置 datadir=/var/lib/mysql #pid pid-file=/var/run/mysqld/mysqld.pid #设置socke文件所在目录 socket=/var/lib/mysql/mysql.sock #设置临时目录 #tmpdir=/tmp # 用户 user=mysql # 允许访问的IP网段 bind-address=0.0.0.0 # 跳过密码登录 #skip-grant-tables #主要用于MyISAM存储引擎,如果多台服务器连接一个数据库则建议注释下面内容 #skip-external-locking #只能用IP地址检查客户端的登录,不用主机名 #skip_name_resolve=1 #事务隔离级别,默认为可重复读,mysql默认可重复读级别(此级别下可能参数很多间隙锁,影响性能) #transaction_isolation=READ-COMMITTED #数据库默认字符集,主流字符集支持一些特殊表情符号(特殊表情符占用4个字节) character-set-server=utf8mb4 #数据库字符集对应一些排序等规则,注意要和character-set-server对应 collation-server=utf8mb4_general_ci #设置client连接mysql时的字符集,防止乱码 init_connect='SET NAMES utf8mb4' #是否对sql语句大小写敏感,1表示不敏感 lower_case_table_names=1 #最大连接数 max_connections=400 #最大错误连接数 max_connect_errors=1000 #TIMESTAMP如果没有显示声明NOT NULL,允许NULL值 explicit_defaults_for_timestamp=true #SQL数据包发送的大小,如果有BLOB对象建议修改成1G max_allowed_packet=128M #MySQL连接闲置超过一定时间后(单位:秒)将会被强行关闭 #MySQL默认的wait_timeout 值为8个小时, interactive_timeout参数需要同时配置才能生效 interactive_timeout=1800 wait_timeout=1800 #内部内存临时表的最大值 ,设置成128M。 #比如大数据量的group by ,order by时可能用到临时表, #超过了这个值将写入磁盘,系统IO压力增大 tmp_table_size=134217728 max_heap_table_size=134217728 #禁用mysql的缓存查询结果集功能 #后期根据业务情况测试决定是否开启 #大部分情况下关闭下面两项 #query_cache_size = 0 #query_cache_type = 0 #数据库错误日志文件 #log-error=/var/log/mysqld....

6 min · 1191 words · Me