java配置SSM纯注解整合Redis开发高并发抢红包项目
前言: 前段时间学习点Redis,这次结合ssm实现一个高并发抢红包的项目。跟以前不一样的: 基于java配置SSM,而并非XML.为什么要这样呢?找了点网络上的答案: 在使用Spring开发时,我们经常会看到各种各样xml配置,过于繁多的xml配置显得复杂烦人。 在Spring3之后,Spring支持使用JavaConfig来代替xml配置, 这种方式也得到越来越多人的推荐,甚至在Spring Boot的项目中,基本上已经见不到xml的影子了。 抢红包的记录使用Lua保存到Redis内存中,最后再异步使用批量事务插入到Mysql。目的:Redis内存响应速度比Mysql硬盘响应速度快。 这个项目的目的也是为了实现上面的两个内容。具体的项目我已经放到Github上了:有兴趣的朋友可以下载看看,里面也都写好了注释,如果有不明白的,可以联系我QQ:1115106468 一起交流 https://github.com/jjc123/Grab_RED_PACKET/blob/master/README.md 问题:此项目中高并发为了使用Redis? 如果使用Mysql直接保存,也可以,那如何解决数据不一致的问题?可以使用乐观锁和悲观锁,此次项目中我使用的是Lua+Redis,看一下这三者区别:悲观锁:使用数据库的锁机制,并发的过程中同时只能有一个线程操作数据,其他得不到资源的线程就会被挂起,过程中会频繁得被挂起和恢复,导致cpu频繁切换现场上下文。可以通过for update语句锁行如果是使用主键查询如where id=#{id}是锁行,如果是非主键查询要考虑是否对全表加锁。可以消除数据不一致性,但是性能会下降,因为他是阻塞性的,而且需要大量的恢复过程。乐观锁:不会阻塞并发,是非阻塞锁,他是具有CAS原理,但是会有ABA问题(CAS和ABA具体百度,更详细),可以通过添加版本号,但是会导致多次请求服务失败的概率大大提高,可以通过重入的方法(按时间戳或者次数限定)来提高成功率,但是会导致大量SQL被执行,容易引发性能瓶颈。Lua+Redis:正是因为上面集中方法的局限性,所以选择Redis去实现高并发,因为Lua具有原子性,消除了数据不一致。而且Redis是保存在内存中的,响应速度极快。注意:为了不影响最后抢一个红包的响应时间,在最后一次操作数据的时候,开启一个新的线程,批量处理数据插入Mysql。而且最后还会删除Redis中批量处理的数据。 现在正是开始这个高并发的抢红包项目吧! 首先我们先配置数据库: 两个表:T_RED_PACKET存红包信息T_USER_RED_PACKET存用户抢红包信息 create table T_RED_PACKET( id int(12) not null auto_increment, user_id int(12) not null, amount decimal(16,2) not null, send_date timestamp not null, total int(12) not null, unit_amount decimal(12) not null, stock int(12) not null, version int(12) default 0 not null, note varchar(256) null, primary key clustered(id) ); create table T_USER_RED_PACKET( id int(12) not null auto_increment, red_packet_id int(12) not null, user_id int(12) not null, amount decimal(16,2) not null, grab_time timestamp not null, note varchar(256) null, primary key clustered (id) ); insert into T_RED_PACKET(user_id,amount,send_date,total,unit_amount,stock,note) values(1,200000.00,now(),20000,10.00,20000,'20万元金额,2万个小红包 每个10元'); 注意: amount :金额 要用decimal而不是double send_date :发红包时间 stock:剩余的红包数 primary key clustered (id) 是设置主键和聚集索引 题外话:Ubuntu下设置MySQL字符集为utf8 1.mysql配置文件地址/etc/mysql/my.cnf 2.在[mysqld]在下方添加以下代码[mysqld]init_connect='SET collation_connection = utf8_unicode_ci'init_connect='SET NAMES utf8'character-set-server=utf8collation-server=utf8_unicode_ciskip-character-set-client-handshake 3.重启mysql服务sudo service mysql restart 4.检测字符集是否更新成utf8. 进入mysql,mysql -u root -p,输入show variables like '%character%' 查看字符集 Variable_name Value character_set_client utf8 character_set_connection utf8 character_set_database utf8 character_set_filesystem binary character_set_results utf8 character_set_server utf8 character_set_system utf8 character_sets_dir /usr/share/mysql/charsets/ 配置Redis: 注意:redis的数据即使电脑关机下次打开redis的时候还会存在 进入redis的src然后./redis-server ../redis.conf &指定配置文件启动而且是后台启动再打开新的客户端:./redis-cli127.0.0.1:6379> hset red_packet_2 stock 20000 (保存红包库存 也可以用来直接修改)(integer) 0127.0.0.1:6379> hset red_packet_2 unit_amount 10 (保存单个红包库存)(integer) 0题外话: hget red_packet_2 stock hash获取该键的值 ltrim red_packet_list_2 1 0 清空list对应键的值 RPUSH red_packet_list_2 c list添加单个元素 LRANGE red_packet_list_2 0 -1 获取对应list的所有值 LLEN red_packet_list_2 获取list长度 这些外部内容已经配置好了,具体的项目我也放到了github上 有兴趣的朋友可以看看。 需要注意的是ubuntu每次开机运行项目的时候老是我的端口被占用:查看端口:sudo netstat -lnp | grep 8082杀死占用端口进程:sudo kill-9 进程号 注意:使用jdbc批量处理的时候需要:url添加rewriteBatchedStatements=true 我的测试数据:url添加rewriteBatchedStatements=true 开始保存数据 耗时:5917插入数量:20000 url不添加rewriteBatchedStatements=true 开始保存数据 耗时:13315插入数量:20000 所以批量处理一定要加上rewriteBatchedStatements=true