工作杂记
记录一些零碎
【MYSQL】
-
连接方式。连接 mysql 服务器可以通过 tcp/ip,也可以通过 socket(仅限于本地) 。当在连接命令中指定 mysql 服务器 ip 时,连接方式为 tcp/ip 。当连接命令中不指定连接 ip 或 或者 ip 为 localhost 时,连接方式为 socket。如果使用 socket 连接时,mysql 默认从 /tmp 目录下寻找 mysql.sock 文件,如果没有找到,并且没有在全局选项文件里指定,那么会报“Can't connect to local MYSQL server through socket '/tmp/mysql.sock'” 的错误。这种情况下,可以尝试重启 mysql 服务器,重启后进入 /tmp 目录下查看是否生成 mysql.sock,如果没有,先使用命令查找下是否存在 mysql.sock 文件。比如:find / -name mysql.sock,或者 whereis mysql.sock。查询到位置后,那么可以通过修改 /etc/my.cnf 文件:
[mysqld] # 示例位置 socket=/opt/mysql/tmp/mysql.sock [client] socket=/opt/mysql/tmp/mysql.sock
在文件中指定该位置,然后重启 mysql。注意,客户端和服务器需要同时指定同一个位置! - mysql 5.7 在创建联合主键时,每个主键均不能为空!即 NOT NULL。
-
触发器 trigger。现假设有两张表 A 和 B。在 A 表进行 INSERT 操作后,对 B 表的 VERSION 字段做 + 1 的更新操作:
-- ----------------- -- 触发器 -- ----------------- DROP TRIGGER IF EXISTS `test_trigger`; DELIMITER ;; CREATE TRIGGER `test_trigger` AFTER INSERT ON `A` FOR EACH ROW BEGIN UPDATE `B` SET VERSION = VERSION + 1 WHERE ID = NEW.B_ID; END ;; DELIMITER ;
其中 DELIMITER 是 mysql 中的分隔符,默认的分隔符为分号“;”,当一次输入的语句不止一行,且行与行之间有分号,那么需要对该段语句重新定义分隔符。DELIMITER ;; 表示从这行开始分割符为 ;;,当语句结束后需要变回原来的单分号,那么指定 DELIMITER ; 即可。NEW.B_ID 中的 NEW 表示 A 表插入后的数据,这个是特定语法,对应的还有 OLD。 - 视图 VIEW
-- AS 后面接需要查询的语句 CREATE VIEW `test_view` AS (SELECT A.xx, B.yy FROM `A` LEFT JOIN `B` ON A.b_id = B.id)2. 修改视图
CREATE OR REPLACE VIEW `test_view` AS (SELECT ...)在使用视图时,直接当成普通表来使用即可。
- 创建分区 PARTITION
通过 show plugins; 指令可以查看当前 mysql 数据库所拥有的插件,如果存在名为 partition 的插件,说明该数据库支持创建表分区。另: show engines; 指令可以查看所有支持的存储引擎。
- 索引 INDEX
1. 索引的分类
- B tree 二叉树索引
- bitmap 位图索引
- hash 索引
2. 索引的适用范围
B tree : 适用于列值重复次数比较少,如果值比较单一,如“0,1”,“Y,N”等,在大数据量中不太适用,因为从该节点取出的值依然包含大量数据。B tree可以进行范围查询。
bitmap :适用于列取值范围较小或固定情况,比如“男,女”,“已婚,未婚”等,它通过建立向量,根据查询条件进行“与或非”得到数据,但它不适用于列取值范围很广,基本不重复情况,也不太适用于频繁更新的列,因为更新位图索引时会锁表。
hash :根据查询条件生产 hash 函数,只能进行等条件查询,无法进行范围查询,也无法加速排序查询。
via:https://blog.csdn.net/wl044090432/article/details/53423333
【问题定位】
- 遇到一个“每天刷卡记录都会丢失一小部分”的问题,由于有主动从门禁设备中获取已保存的数据的接口,因此每天“丢失”的那部分,可以通过 web 页面操作补上,但终归是个问题。在第一次排查问题时,发现后台处理(批量处理)刷卡记录的速度明显跟不上记录上报的速度并且发现“补数据”的操作发生时,后台尚未处理完刷卡记录,于是认为数据并未丢失而是尚未处理完成,然后通过添加索引优化了后台处理的速度。但是,之后的一两天,发现这个问题依然是存在的。于是,再次分析日志,但是似乎并没有和刷卡记录入库相关的异常发生(存在一个与此问题无关的异常,且数量较多)。然后我想,这个业务是一条线程单独处理的,会不会是分配任务队列的 Size 不够,可是也不对,上报的刷卡记录数量总数与队列 Size 相差 半个到一个数量级,不可能满,而且就算队列满了也会抛出相应异常的。于是陷入僵局...最后在查询异常日志时,用一个在 catch 块中打印的字符串搜到了这个异常,巧合的是,这个异常的原因竟然与那个狂打的,无关的异常一摸一样,都是由 mybatis 产生的“期望得到一个结果,但是找到了多个”异常,这就是在一开始按异常查找没发现问题的原因,然后就转为了“为什么会得到两个结果”的问题......其实一开始如果提出问题时可以更具体到“每天都是缺少几十条数据”,亦或者是“谁的数据每天都会缺失”,那么会比较肯定是批量执行时异常(查异常时,差点就以为批量执行没发生异常)。而且每天批量的数据操作,一旦中间数据出错,会出现比较规律性的一组数据失败,这给我的印象是比较深刻的。
【Controller 的处理】
- BaseController。在 controller 中,许多步骤是重复的,比如:分页对象封装,Session 的获取以及返回形式的封装(如:返回json,返回文件上传结果等);
- 对象转换。接收客户端数据的通常为 VO(Value Object)对象,它是一个值对象,也可以说是业务对象,这个对象需要具备一个方法将 VO convert to(转换为) PO (Persistent Object)对象。PO 对象的字段通常对应的是数据表的字段,因此 VO 对象字段与 PO 对象字段可能不同(可以相同),这一点在完全 ORM 框架中特别明显,在 mybatis 中不太明显;在 service 接口数据返回后,需要将 PO 对象转换为 VO 对象,因为有时候数据库存储的并不是具体的中文,而是类似“0/1”,“YES/NO”,或者存的是个枚举的值,这些数据在返回 客户端之前需要转换为具体的内容,一些不需要的数据也可以直接丢弃。
- 返回对象。对于返回给客户端的数据,除了具体后台处理后得到的(通常是个对象)外,最好有个请求结果的提示,如 success 或 error(failed);还可以定义错误码等。那么可以,将这些数据再封装为一个返回对象。这样代码的整体性会比较好。
【关于分页】
- 接收参数。对于接收分页参数的 VO 对象,可以抽取出一个父类,带有 pageNum,pageSize 字段,如果考虑到可能有排序的需求,那么加上排序字段对象,和排序顺序字段,这样可以通过客户端传递排序参数就能完成不同的排序,而服务端代码无需变动(前提是在 sql 中预先判断排序字段非空则排序)。
- Page对象。通常分页参数至少有三个:当前页,每页数量,查询条件,在每个接口中传递略有些麻烦,可以封装一个 Page 对象,除上述参数外作为字段外,还需加上结果总数字段。
【log4j】
格式参数表示及含义:
- %d:日期,通过大括号定义格式,如:%d{yyyy-MM-dd hh:mm:ss.SSS}
- %p:日志等级,包括 DEBUG,INFO,WARN,ERROR,FATAL,等级依次提高
- %t:线程名称
- %m:具体日志信息
- %c:打印日志的类(在哪个类打印的)
- %F:日志类的名称
- %n:换行符
- %L:日志发生的位置(类名,方法名,行号等)
【IE下的文件上传】
对于后台对于文件上传请求的返回,如果 content-type 设置为 “application/json;charset=UTF-8”,则在 IE 8 下回弹出一个下载框,下载后用文字编辑器打开,发现里面的内容就是后台返回的,相同 content-type 在 chrome 下则正常(兼容性好),如果使用环境包括 IE 8 的,需要将响应的 content-type 设置为 “text/html;charset=UTF-8”。
【@WebFilter 注解执行顺序】
我们知道,在 web.xml 文件中定义 Filter 后,Filter 的执行顺序与它声明的位置正相关。那么当我们使用 @WebFilter 注解声明一个 Filter 后,多个 Filter 的执行顺序是怎样的呢?它是根据“字符顺序(小到大)”执行的。via http://blog.51cto.com/celing/1117299 ;因此,我认为,在使用注解方式的过滤器时,在命名上可以通过形如 X_LoginFilter 的方式进行执行顺序的控制,若与公司命名规范不符,再另作改动。