本文是读 杨开振老师的《深入浅出 Mybatis技术原理与实践》所做笔记,主要是知识积累。
1、文件处理
blob 字段的读写使用,一般情况下不会在数据库中使用这样的数据类型,因为存储的内容太大容易导致内存溢出,何况内容也是不可读的,就算是文本文件,可读性也是很差的。所以建议使用文件服务器来存储文件,数据库只保存文件服务器的地址。
2、批量更新
所谓的批量执行是指,默认情况下,它在 commit 后才发送 SQL 到数据库执行。很明显如果使用批量执行可以提高性能,因为减少了数据库的请求次数,降低了数据库服务压力。
1)全局配置配置批量执行(默认是 SIMPLE),即修改 Mybatis 主配置文件
<settings>
<setting name="defaultExecutorType" value="BATCH"/>
</settings>
注:ExetuorType 有三个值,simple、reuse、batch,reuse是指重复利用预编译语句。
2)单个数据执行配置,使用 Java 编码
SqlSession sqlSession = SqlsessionFactory.openSession(ExetuorType.BATCH);
注:这里开启了一个新的 SqlSession,那么他有独立的事务控制,不会被 Spring 事务传播影响。
另外,因为批处理是打包一起发送到数据库执行,所以会有个问题,那就是在commit之前你是不可能从数据库那里获得反馈信息的,其实 Redis 的管道流也是这样的。所以对于那些执行之后立刻要查询出来的最好不用批处理,或者可以手动使用 SqlSession.flushStatements();它的含义是将当前缓存的SQL发送给数据库执行,但是不提交事务。
3、调用存储过程
尽量不使用存储过程,存储过程一般使用在银行金融这种安全性比较高的行业,因为如果存储过程比较多,他会降低数据库的性能,毕竟使用应用服务器来降低数据库的压力是优化的常用手段。尽管使用存储过程可以减少应用服务器和数据库的交互,但是大量的存储过程不但会降低性能而且维护起来也不容易。
4、分表
这里分表是指横向分表,即把一张表的数据横向切分为几张表,这样就可以降低表中存储的数量,达到快速查询的目的。比如可以根据年份来分表,把 t_user 表分为 t_user_2014、t_user_2015、t_user_2016 等,这样查询的时候就可以把 年份作为参数参数查询
select * from t_user_${year}
5、mybatis 自带分页功能
mybatis 自带分页功能其实是使用了JDBC可滚动的结果集处理的, ResultSet 他是不会把所有的记录从数据库查询到应用服务器的,他是通过 fetchsize 批量获取数据放到 ResultSet,如果在 ResultSet 中 next ,数量已经超过 fetchsize 的话,jdbc 又会发送请求到数据库获取 fetchsize 的数据。因此如果采用可滚动的结果集时,一旦滚动的基数比较大,那么从数据库会查询大量的数据到应用服务器,此时其实是很耗内存的,甚至导致内存溢出都有可能。
所以,一般情况下我们都不使用 mybatis 自带的分页功能——RowBounds
而是,自己写分页插件或者手动写分页语句。
6、尽量降低数据库事务的执行时间
假设我们在一个方法上加上了事务,然而这个方法内部处理数据库的操作很少,其实这就浪费了数据库连接的资源,因为他持有数据库连接却没做多少事。面对这样的问题,如果这个方法持有关系的锁,则可能会导致很多数据操作阻塞。
解决这种问题的办法是,把耗时操作和数据库操作分离,比如数据导入,数据导出,远程服务等都可以单独处理,处理完成之后在调用数据库操作。
7、枚举的使用
对于数据库字段,如果是枚举类型,最好定义枚举,为什么呢?在《Effective Mysql》中提到枚举可以节省存储空间从而提高检索速度;从数据可读性来讲,的确枚举要比纯数字来得简单,但是如果使用枚举的话,必须自定义 Mybatis 的类型映射器,这个是无法接受的,没定义一个这样的枚举类就要定义一个这样的解析器,我觉得这种工作确实不好做啊。
8、多对多级联映射
虽然这种多对多的关联关系屡见不鲜,但是由于系统中很少使用JavaBean,所以这种配置对我们系统来说意义不大,就不记录了。简单来说就是 A中有B集合,B中有A集合。