简介
本周想分享以下几个内容:
- tomcat配置文件对spring定时任务的影响
- 使用BigDecimal原因和BigDecimal的坑
- java中的“find_in_set”函数
- 你不知道的mybatis,执行多条sql
一、tomcat配置文件对spring定时任务的影响
描述: 以前一直都没有研究过tomcat的启动,一直都是默认启动,即:把war包名字改成ROOT,然后启动tomcat就能直接访问了。但是这次在一个简单的单服项目中加了一个简单的spring定时任务之后,发现这个定时任务执行了两边。。。运维的人意思是我这边代码的问题,但是我本地测了好几遍都是只执行了一次,所以我怀疑是运维做了负载,最后发现是tomcat配置的问题。
打开server.xml配置文件,我们来看看这几个参数
1、appBase:这个参数,个人认为就是指定tomcat去加载哪个目录下的文件
2、docBase:这个参数,个人认为就是让tomcat去解压appBase下名字为XXX的war包(XXX就是docBase配置的名字)
3、path:问题就是出在这个参数,如果我们不配置这个参数的话,他会生成在appBase指定的目录下生成两个文件夹:ROOT和docBase中指定的名字,如:
实际上你启动的tomcat是启动了两个项目,一个是ROOT,一个是zongsMobileApi-0.0.1-SNAPSHOT,虽然在配置文件中配置了跳转到zongsMobileApi-0.0.1-SNAPSHOT项目中去,但是ROOT项目确确实实也是起来了运行的,对于spring定时任务来说,无论有没有前端在调用这个项目并不影响,ROOT项目中的定时任务也会执行,这样就变成了两个定时任务在执行了!
解决: 其实不配置path这个参数,无非就是想访问的时候不加项目名称,但是如果这样不配置的话,定时任务就出现了执行两边的问题,解决方式无非就是三种:
- 单服下:配置path,然后如果想访问的时候不加项目名称,可以在nginx上配置转发,即:转发的时候配置上项目名称
- 单服下:将war包的名称改为ROOT,这样tomcat解压的时候就会生成一个ROOT项目,这样外面访问也不需要加上项目名称
- 用quartz集群来做(一般简单的定时任务不建议用quartz,这个东西要引入一大堆表)
二、使用BigDecimal原因和BigDecimal的坑
名人不说暗话,我是第一次在java里面用BigDecimal,无奈本人没文化,曾今以为double、int行天下,直到我在单元测试中跑出了这么个例子(意不意外,惊不惊喜):
在意外和惊喜之中,我们是不是发现曾今如此信任的double竟然有bug?最近我刚好在做的是一个电商项目,之前规定数据库中存入的金额都是分,这个时候如果使用了double是不是就莫名其妙的少了一分钱,那如果日交易量大的话,是不是会造成不少的损失呢?下面我们来看看用BigDecimal会变成什么样,是不是也有同样的bug呢?
BigDecimal构造参数是String型:
BigDecimal构造参数是double型:
结果:实验结果告诉我们,BigDecimal在使用String类型的构造函数的时候,结果是准确的,而使用double的构造函数的时候任然存在这种隐形的bug,这样就是为什么网上为什么那么多建议使用String类型的构造函数的原因。
问题:看到这里是不是大家都觉得BigDecimal那么好,其实他也有坑的地方!
神奇不?第一次用BigDecimal的我百度了一下BigDecimal的加法,然后发现是用add的,但是后来发现项目中结果add和没add一样,但是单元测试输出他们add的结果又是对的。
分析(个人版本。可能不对):这是因为这里存在一个误区,把BigDecimal的add类似于list的那种add了,这是一种严重的错误,我们可以认为 int a=0; a++;a就变成了1,但是BigDecimal是一个对象,bigDecimal.add(bigDecimal1)这个对象确实存在,也输出了,但是bigDecimal这个引用并没有指向这片新的内存;只有bigDecimal=bigDecimal.add(bigDecimal1)这么写才改变了bigDecimal的引用!
三、java中的“find_in_set”函数
大家还记得在上期中分享的mysql中的find_in_set函数吗,这个函数主要体现的是mysql中处理数据的能力,而java中的“find_in_set”函数其实并不存在,而是一种思想。
我想大家对String的contains、indexOf和lastIndexOf这几个函数应该不陌生,但是想通过这几个函数达到mysql中的find_in_set功能,你们觉得能实现吗???
如果正常思维显然是不能实现的(判断这个人的公司列表是否含有id为12的公司):
解决:其实我看我同事这么写的时候,我是震惊的,说实话不难,也没啥水准可言,但是我的他很有想法!
四、你不知道的mybatis,执行多条sql
很多小伙伴看到这个标题,肯定第一想到的是foreach,恭喜你答对了一半,那还有一半是什么呢?
可能在大多数情况下,我们认识的执行多条sql是一个执行头(insert、delete、update、select)即:
<select id="XXXX" resultType="java.util.HashMap">
SELECT user_name FROM XXX where delete_mark=0 and user_id in
<foreach collection="list" item="item" open="(" close=")" separator=",">
#{item}
</foreach>
</select>
但是我今天要讲的是如何在mybatis里面一个dao方法执行多个执行头:
<update id="XXX">
<foreach collection="list" item="item" separator=";">
update XXX set column1=#{item.SSSS} where id=#{item.id}
</foreach>
</update>
这种写法。。。是不是既熟悉又陌生???其实这种写法在java里面就是for循环调用update方法而已,但是为什么要这么写呢?
优势:我们不妨想象一下,如果这个循环是100,而你在java里面循环调用dao,在连接数据库的话,是不是需要连接100次数据库,如果这个数是1000,1万呢,你觉得你数据库的连接数扛得住吗,但是这种写法只要连接一次数据库就行了!
其实我们很多时候数据库挂了,tomcat挂了等等,都是我们平时写代码的时候没考虑性能问题造成的,大量的连表,for循环连接数据库等,这种操作对于数据库来说都是头皮发麻!
注意:上面介绍的那种写法需要做一个配置:allowMultiQueries=true 即:支持执行多条sql
jdbc:mysql://XXXX:3306/XXX?characterEncoding=utf-8&allowMultiQueries=true