总摘要: spring
2018-01-03
- 摘要: spring注入对象
1. 在springmvc获取request的方式中,RequestContextListener、.@Autowired,这两种会不会有并发时的线程安全问题?[河北-波涛]
广州-小护士<-> 17:27:29
controller注入request对象不会有并发问题
河北-波涛(-) 17:34:27
我也是在网上学习,想到这种问题,这两种方式的代码也没啥特殊的吧,如果我理解无误应该是:
RequestContextListener:在web.xml配置lisener,在代码通过全局类获取(HttpServletRequest req = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
@Autowired:
就是什么request属性,实现spring自动注入吧
@广州-小护士 注入式有啥特殊实现吗?不同方法对应不同request,而注入的是方法公用的类属性,这样不会并发时不会有问题,还是我对这两种方式的理解有误
成都-梅小西(-) 17:42:17
controller里注入的对象只是线程安全
成都-勇<-> 17:46:12
利用threadlocal 和 ObjectFactory来实现的线程安全,每次在processRequest设置的reqeust对象, 你看FrameworkServlet这个类里面的service()方法嘛
广州-小护士<-> 17:51:22
先看看 DispatchServlet源码~
河北-波涛(-) 17:51:58
a请求映射到controller的方法1,b请求映射到方法2,a、b都会对controller的request做注入,如果a、b请求同时发起,方法1和方法2中的去使用这个被注入的request,那这个被注入的request到底是对应哪个请求?这不会用线程安全问题?
成都-勇<-> 17:54:05
你可以简单的认为每个请求都会启一个线程来处理,所以threadlocal获取的对象也不一样的
广州-小护士<-> 17:54:45
如果说用到的request不是真实的request,是代理类. 从头到尾都在代理。注入request对象有两种方式嘛,一个是方法上传参,一个是字段注入. 方法传参很好理解,就是反射调用的时候传参进去, 字段注入就比较难理解了. 单例模式下也是安全的. Inject HttpServletRequest into Controller
2018-01-08
- 摘要: 线程阻塞
1. 请教大家一个问题,我想限制一个线程池的最大队列不超过200,如果线程里已经有 core+队列200 个线程了,就阻塞,直到有线程空出来,才能放入新的线程请求, 有现成的线程池可以实现这样的功能吗?[杭州-Freedom]
深圳-rubin(-) 13:59:44
Jdk就可以满足呀
杭州-Freedom(-) 14:00:30
怎么做?
广州-扬帆(-) 14:00:44
线程池有四种方式来处理满了后的线程, 你如果满了后直接丢弃的话,本身就有的
广州-小护士<-> 14:00:46
@杭州-Freedom 你到底要队列还是线程池?
北京-w(-) 14:01:25
newFixedThreadPool
杭州-Freedom(-) 14:02:18
有点像队列+线程池,因为外部请求会一直不断的放入,但我想限制线程池最多只能有200个线程
广州-小护士<-> 14:04:37
我感觉你要的是生产者消费者模式,固定队列长度
成都-孤狼(-) 14:04:40
线程池不是有一个最大线程数目的参数么
广州-小护士<-> 14:05:02
PriorityBlockingQueue, DelayQueue, LinkedBlockingQueue, 我推荐的设计是用LinkedBlockingQueue + threadpool
成都-梅小西(-) 14:30:54
直接core=200然后用无限队列不就行了
杭州-Freedom(-) 18:23:02
最终解决方案: 支持生产阻塞的线程池
2018-01-09
- 摘要: 线程阻塞
1. 下单支付遇到个问题, 下单后事务还没提交或者提交到数据库后还没执行完成,订单这边就收到付款成功的MQ 消息,但是此时根据结算号去查找订单的信息 有几率出现查询不到的场景,不知道有啥好办法规避掉呢? [杭州-水表哥]
北京-喜<-> 17:26:10
这个问题太多了啊. 都不知道该给你出什么方法了
杭州-水表哥(-) 17:26:48
我的问题吗?
北京-喜<-> 17:27:03
下单后事务还没提交或者提交到数据库后还没执行完成,订单这边就收到付款成功的MQ 消息 - 这里有2个问题
北京-Sun(-) 17:27:07
你这个是app端支付完成,但是你订单都没生成。
北京-喜<-> 17:27:23
此时根据结算号去查找订单的信息 有几率出现查询不到 - 这里是1个问题, 2, 你订单没生成或者没修改完状态对面就能付款了?
湖南-stone(-) 17:27:29
应该是先有订单吧,回调的时候再改状态啊, 怎么会查不到订单?这业务不正常吧
杭州-水表哥(-) 17:28:02
下单这边只是把订单号和结算信息返回给客户端,但是这个时候事务是已经提交到数据库了,但是量大的时候 其实数据库这个事务都还没执行完成, 会出现这种场景的 时间 基本精确到10毫秒以内
北京-Sun(-) 17:28:37
那就等事务完成后在返回给客户端啊。
北京-喜<-> 17:29:10
那就是业务流上 本身是保证不了时序的
杭州-水表哥(-) 17:29:15
这个事务完成后 其实也不可控啊,完全依赖数据库了
北京-喜<-> 17:29:25
你就需要额外做个 时序派发的处理, 面向状态机跃迁,自己做个统一的时序控制和排外处理
杭州-水表哥(-) 17:30:12
没看懂
北京-喜<-> 17:30:15
简单的说就是,支付回调回来,发现订单状态不对。先落地
成都-奋斗(-) 17:30:18
不是应该先把订单生成成功之后,再提交支付到第三方吗?
重庆-Rocky(-) 17:30:26
嗯 先存下来, 后期定时跑, 更新
北京-喜<-> 17:30:41
等订单下单成功之后,反向去解锁支付回调数据
杭州-水表哥(-) 17:30:43
@ffud 明白你的意思了,也就是所谓的补偿
北京-喜<-> 17:30:52
不是补偿, 你这个是前半段的技术设计有问题, 在后半段 谁也不知道互相之间的关系, 就得互相检测, 你完成的时候看看我对不对, 我完成到时候看看你在不在
天津-Michael(-) 17:31:51
下单和支付fork/join
成都-奋斗(-) 17:32:04
喜神,是不是应该先生成了订单,然后再提交到第三方支付,收到回调消息,更新库状态。这是才正常的业务流程吧, 怎么可能你自己的库的订单还未生成完成,第三方回调都来了
北京-喜<-> 17:32:37
是的,一般是这样, 否则有超卖、退款等风险
重庆-Rocky(-) 17:32:55
现在讨论的就是这种特殊情况
杭州-水表哥(-) 17:33:21
奋斗,我现在是订单号和结算号都生成了,事务也提交到数据库了,只是量大的场景下会出现事务还没执行完成,客户端就可以付款,订单这边就收到 MQ 消息了
成都-奋斗(-) 17:33:36
恩,明白你的意思, 你们是在订单事务里面也提交到第三方支付的吧
杭州-水表哥(-) 17:34:13
按照喜神的意思,我可以在收到 支付消息后 如果找不到订单信息的话 先落地后续再处理这笔单子
北京-喜<-> 17:34:18
就是状态机 跃迁不是 下单成功-> 支付成功,多了一个 支付成功->下单成功->支付成功, 应该是在事务里RPC了
杭州-水表哥(-) 17:34:55
我没在订单事务里面 提交第三方支付的
北京-喜<-> 17:35:14
有异步么
杭州-水表哥(-) 17:35:19
没异步的, 订单这边 只负责生产订单号和结算号, 客户端拿到这些数据后去请求支付
北京-喜<-> 17:35:27
没有的话,就是前面说的第3个问题 主从延迟, 订单有超时不支付,关闭的动作么?
杭州-水表哥(-) 17:36:16
有的, 我自己判断应该就是 事务提交到数据库里面 在排队等待处理,但是这边有结算号就可以去支付
北京-喜<-> 17:36:39
有好多方案可以处理,前面提到的可以, 还有一种是解决主从延迟的问题, 加热点,读主库也可以
杭州-水表哥(-) 17:37:23
目前订单和支付 我这边都是 读主库
北京-Jerry(-) 17:36:38
按照你说的应该会造成长款问题吧
北京-喜<-> 17:37:37
如果一直在读主库 出现这个问题
杭州-水表哥(-) 17:37:39
因为之前发生过主从延时 就没再读从库
北京-喜<-> 17:37:42
就是前面的设计的时序不对, 如果不改时序,就用先存储,后处理的方案
杭州-水表哥(-) 17:38:07
能详细的说下 哪里的时序不对吗?
北京-Jerry(-) 17:38:08
你的业务每秒多少笔交易?
杭州-水表哥(-) 17:38:28
每秒有100单的并发量
北京-喜<-> 17:38:25
你提交给三方支付之前, 你对外承诺的业务语义,是你的事情做成功了, 结果支付回调回来之后,发现你没做成
北京-Jerry(-) 17:38:36
你这个是不是有专门的一个订单服务的,和交易系统是拆分出来的
杭州-水表哥(-) 17:38:47
这个问题 搞活动的时候会比较明显
成都-奋斗(-) 17:39:07
强制服主库
北京-喜<-> 17:39:39
事务没做完,就把订单号+订单状态返回出去了?
杭州-水表哥(-) 17:39:54
事务只是提交到数据库, 关键我这边也这边也不知道数据库这边把事务执行完了啊
北京-喜<-> 17:40:40
这个事务不是你们自己的代码编写的么?
杭州-水表哥(-) 17:41:00
是的
北京-喜<-> 17:41:06
那怎么会不知道呢, JDBC处理完 你知道的啊
杭州-水表哥(-) 17:42:37
网上我是查了下 有 事务处理成功以后的回调,我今天问下 dba ,他的意思是说 事务只是提交到数据库了,但是不是提交到数据库就意味着执行完成了
北京-喜<-> 17:43:17
什么数据库
杭州-水表哥(-) 17:43:24
mysql
北京-liunx(-) 17:44:07
commit之后成功或者失败都应该会有一个结果吧?
杭州-东子(-) 17:44:28
@杭州-水表哥 这查错了吧
杭州-水表哥(-) 17:46:05
怎么说
上海-给你们(-) 17:46:45
从库策略本来就是做报表之类的查询用的, 如果实时性要求高就别才用主从这种策略
杭州-水表哥(-) 17:47:03
网上我是看到有 spring 事务提交后的回调处理,也就是说 事务真正提交后再处理后续的。 喜神,求解惑 我也不太想通过 数据线落地再去处理。
北京-喜<-> 17:47:15
不是一件事, 你们DBA说的是 begin 和 commit , begin不等于一定能够commit, 你的问题是commit后,没拿到 提交的信息, spring 那个是java的callback,更不是一件事, commit成功或失败都是可以知道的啊。commit如果返回的是成功,是一定会包成持久化的. 这个是ACID的语义,mysql不能master扩展 也是因为这个原因。本地强一致性,CAP里 不做P。 先落地。后续互相检查在处理,是可以解决的, 但还是没找到根本原因。
杭州-水表哥(-) 17:51:05
嗯,这个是第二种方案,还是没找到根本原因
北京-鹅鹅鹅(-) 17:51:06
mysql就是不做p吧
北京-喜<-> 17:51:15
是啊, 你可以在讲讲处理流程 , 1 2 3 4这样列下
上海-给你们(-) 17:52:17
异步支付回调比订单生成早 在支付回调后没找到订单放到队列里,设置一个重试次数就行了, 从用户付款到支付回调,我觉得正常情况下不会比生成订单早,你们订单生成的真复杂。
北京-alex(-) 17:54:43
一般都是生成订单在支付的吧
上海-给你们(-) 17:54:52
不一定
北京-alex(-) 17:54:55
也见过不支付不生成订单的app, 京东淘宝等都是先有订单在支付的
杭州-水表哥(-) 17:55:39
下单大致流程
1.生成结算号
2.预减库存
3.执行下单 (生成订单号,调用支付服务增加结算付款信息)
4.返回客户端 订单 结算信息 (后续可以发起支付操作)
北京-喜<-> 17:57:13
全部是同步的?
杭州-水表哥(-) 17:57:52
嗯, 压根没异步的场景
北京-喜<-> 17:58:07
那可能是 redo log 到 fsync file system的问题, 你问下DBA, redo log刷盘用的什么策略
杭州-水表哥(-) 17:59:45
mysql 默认的, redo log 刷盘用的是默认的 ,具体是啥我也不懂
北京-喜<-> 18:02:04
就是redo log buffer,会在事务commit的时候,一定持久化到数据文件里
杭州-水表哥(-) 18:03:04
也就是说 只要事务提交了,那就肯定数据都持久化到数据库了
北京-喜<-> 18:04:02
是的
杭州-水表哥(-) 18:04:27
那我知道啥问题了,目前截图给群里的代码是我改造后的,原来的代码事务是无效的, 原来的事务代码 只在 executeOrder 这个方法上面加了事务注解,没生效, 在addOrder 上加了注解就行了.