每月都会把遇到的一些坑记录下来,一方面是写一次加深自己的印象,以后遇到也能尽快检索到,另一方面就是分享。
1. windows系统把项目放到Tomcat,然后注册成服务
进入bin目录,cmd打开dos窗口。输入service install 服务名,即可将项目注册成windows服务。
注册成服务之后再设置为自动启动,可以实现开机就启动项目。
2. windows删除服务
1)关闭服务 2)sc delete 服务名
3. tomcat最重要的三个端口都有什么作用?
shutdown:关闭tomcat的监听接口
:http走8080;https走8443
AJP/1.3 这个用于支持AJP协议(注掉也没事)以后用到在学(这个东西比较冷门,估计这辈子也用不到)
4. 复制tomcat
复制一个tomcat文件出来,打开webapp,删除原来的项目文件,将新的放进去。
修改conf的service配置文件service.xml,改三个端口,分别是shutdown、HTTP1.1、AJP1.3(可有可无)
5. executor="tomcatThreadPool",指定使用共享线程池
tomcat中每个用户请求,都是一个线程。web容器一般都有线程池的实现,这样当用户请求过来的时候就不需要再去临时创建线程。容器会分配线程池中的线程,提高访问速度。
todo:学习tomcat线程池
6. mybatis返回值 Map和Map
value返回String,如果返回值都是char,那就相安无事。否则取值会出问题
根本原因是:java里的泛型是类型擦除,虚拟机并不认识泛型,是编译器实现的,java泛型只在程序源码中存在,在编译后的字节码文件中,全部都被替换成原来的裸类型(详见深入理解JAVA虚拟机-泛型)
7. SimpleDateFormat线程不安全,DateTimeFormatter不但是不变对象,它还是线程安全的。
SimpleDateFormat不是线程安全的,使用的时候,只能在方法内部创建新的局部变量。而DateTimeFormatter可以只创建一个实例,到处引用。
原因:在多线程环境下,当多个线程同时使用相同的SimpleDateFormat对象,如果调用format方法,多个线程会同时调用calender.setTime()方法。time可能会被别的线程修改,所以线程不安全。
final DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd")
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
.parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
.parseDefaulting(ChronoField.MILLI_OF_SECOND, 0)
.toFormatter();
LocalDateTime localDateTime = LocalDateTime.parse("2018-12-11", formatter);
8. idea断开和svn的连接,然后换个目录重新上传
1) idea下载插件:SVN Disconnect
2) VCS->SVN Disconnect
3) 打开settings -》 version control,点击加号选择要上传的项目,选择完毕项目就会变色
4) 整个项目文件,右键选择subversion,选中share directory。然后选择要上传到的svn文件夹,点确定
5) share完成之后,项目变色了。这个时候提交一下要上传的文件就行,和开发中上传一样
上面的方法太慢了。。。用idea做这个事儿不行,有两种办法:1.myeclipse 2.小乌龟
9. Java多文件上传,postman怎么发?
后端接收:MultipartFile[] files
postman:body - form-data key写一样的,value选择文件类型,发出去就是文件数组了
10. mysql my.ini ,windows其实只显示my
my.ini怎么也搜不到,急死个人
11. mysql my.ini ,注意编码格式ANSI
在windows服务器,用记事本修改了my.ini文件,可是怎么也启动不了mysql。最后发现竟然是配置文件的锅,果断下载notepad++
12. 导入sql出现MYSQl server has gone away这个错误,原因可能是base64图片数据太大导致,设置max_allowed_packet即可
这个据说可以通过配置文件设置,然后重启mysql完成修改,但是我没成功
最后通过命令行set global max_allowed_packet=1024*1024*16,解决sql执行失败的问题。如果还报错,就设置的更大点
13. 容易忽略的小问题:集合即使是isNotEmpty,里面也可能有null,对拿出的元素别忘了判空
14. 一个windows自带的功能:windows任务,可以定时执行一些任务,或者说开机启动一些程序(比如idea开机自启)
15. java包装类,不要用 == 比较大小,应该用equals(虽然很简单,但是工作中确实看到有人犯这个错误,写下来自己警戒下)
整型、char类型所对应的包装类,在自动装箱时,对于-128~127之间的值会进行缓存处理。当然其目的就是提高效率。
缓存处理的原理为:如果数据在-128~127这个区间,那么在类加载时就已经为该区间的每个数值创建了对象,并将这256个对象存放到一个名为cache的数组中。每当自动装箱过程发生时(或者手动调用valueOf()时),就会先判断数据是否在该区间,如果在则直接获取数组中对应的包装类对象的引用,如果不在该区间,则会通过new调用包装类的构造方法来创建对象。
此处以Integer类为例,源码参考:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
// 超过范围就是new的Integer对象
}
==,比较地址值
16. redis dump.rdb
默认情况下 每隔一段时间redis服务器程序会自动对数据库做一次遍历,把内存快照写在一个叫做“dump.rdb”的文件里,这个持久化机制叫做SNAPSHOT。有了SNAPSHOT后,重新启动redis服务器程序时redis会自动加载dump.rdb,将数据库状态恢复到上一次做SNAPSHOT时的状态。
17. 往数据库存图片是真下水道
永远不要采用这种方式保存用户附件,数据迁移就是天坑,数据量稍微大点,半天都执行不完sql
再说,大文件保存在数据库,一旦加载到缓存,会把很多原来在缓存里的数据挤出去,导致缓存命中率降低,性能肯定拉跨
18. 将redis注册为服务(总是忘记,只好记录一下)
进入到redis安装目录下:执行:
redis-server.exe --service-install redis.windows.conf --service-name redis_6380 --port 6380
19. Multiparthttpservletrequest
文件上传可以用这个,能设置参数
20. ConCurrentHashMap.newKeySet
HashSet 是从hashmap实现的,所以线程不安全。上面的方法可以获取线程安全的Set
21. mybatis批量更新,&allowMultiQueries=true打开,separator=“;”,一定记得要用分号
22. Runtime.getRuntime().availableProcessors()
返回的是可用的计算资源,而不是CPU物理核心数
多线程情况下:cpu密集型任务,推荐设置为N,和可用计算资源保持一致,尽量减少cpu上下文切换
io密集型推荐设置为可用计算资源2N
23. Mysql使用本地IP无法连接,使用localhost或127.0.0.1可以正常连接
Mysql默认不会开启本地IP连接的权限,需要手动开启
关键的不是记住多少东西,而是要掌握解决问题的方法。遇到这个问题,一开始无谓的改密码,重建数据库,都没能如愿,因为懒得思考.....,后来还是仔细思考了一下解决了。
24. 多层循环的时候,尽量外层循环小,内层循环大
因为cpu有分支预测功能,我们要尽量让CPU少预测错误几次
比方循环a,循环100次;b,循环10000次
a放外面,预测错100次。b放外面,会预测错10000次(真实情况可能不是这样,没学过硬件,先按照这样理解),差距越大,内外差越明显。
25. 2022-08-0900:00:00
这种日和时不带空格,会出bug。他可以parse但是日期是错的,如果不注意很可能会出bug。(项目中遇到这个问题是因为工具类有问题,一个用trim,另一个竟然用replace去空格,不知道哪个人才写的,导致一个正常有空格,另一个没有,坑死我辣!)
26. replace和replaceAll都是替换所有。
- replace的参数是字符或字符串,可以支持字符的替换,也支持字符串的替换;
- replaceAll的参数是正则表达式,即基于规则表达式的替换;
若是replaceAll()所用的参数据不是正则表达式,则与replace()替换字符串的效果是同样的
replaceFirst(),这个⽅法也是基于正则表达式的替换,但与replaceAll()不同的是,只替换第⼀次出现的字符串
27. WARN!不要在finally块中使用return
try块中return执行成果之后,并不马上返回,而是等到finally块语句执行完毕,如果此处存在return语句,就会丢弃try中的返回。
28. MySQL表可以选择不同的存储引擎,而不是一个库只能用一种
以前一直以为存储引擎是和库绑定的,今天忽然发现是和表绑定的,误解了两年。
另外这也牵出了一个知识点:Mysql服务层部不管理事务,事务是由下层的存储引擎实现的。所以在同一个事务中使用多种存储引擎是不可靠的。如果在事务中混用了事务和非事务的表,一旦需要回滚,非事务型的表就会变得无法撤销。
更致命的是,在非事务的表上执行事务相关操作时,MySQL通常不会提醒也不报错。只有在回滚的时候才会给个警报:某些非事务型的表上的变更不能回滚。
29. leftjoin where和and
on后加and,都作为on条件。
on后用where,where是筛选条件。(有次sql写迷糊了就用错了,导致结果不对)
30. try can use automic resource management
从 Java 7 build 105版本开始,Java 7的编译器和运行环境支持新的try-with-resources语句,称为ARM 块(Automatic Resource Management) ,自动资源管理。新的语句支持包括流以及任何可关闭的资源。
数据流会在try执行完毕之后自动关闭,前提是可关闭的资源必须实现java.lang.AutoCloseable接口。
try(资源) { }
31. String.ValueOf(null),会得到“null”,小心。
return (obj == null) ? "null" : obj.toString();
32. HashedMap,虽然写错了但是歪打正着,真有这个方法!
33. 注意:使用BigDecimal来计算时需要将它计算出的结果进行保存,若不进行操作,则原始值还是不变的。
平时用的比较少,每次用都要看文档~