MyBatis流式查询的项目实践

本文主要介绍了MyBatis流式查询的项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

1.应用场景说明 MyBatis

preview: JDBC三种读取方式:
1.一次全部(默认):一次获取全部。
2.流式:多次获取,一次一行。
3.游标:多次获取,一次多行。

在开发中我们经常需要会遇到统计数据,将数据导出到excel表格中。由于生成报表逻辑要从数据库读取大量数据并在内存中加工处理后再生成Excel返回给客户端。如果数据量过大,采用默认的读取方式(一次性获取全部)会导致内存飙升,甚至是内存溢出。而导出数据又需要查询大量的数据,因此采用流式查询就比较合适了。

2.模拟excel导出场景

1.创建海量数据的sql脚本

CREATE TABLE dept( /*部门表*/ deptno MEDIUMINT   UNSIGNED  NOT NULL  DEFAULT 0, dname VARCHAR(20)  NOT NULL  DEFAULT "", loc VARCHAR(13) NOT NULL DEFAULT "" ) ; #创建表EMP雇员 CREATE TABLE emp (empno  MEDIUMINT UNSIGNED  NOT NULL  DEFAULT 0, /*编号*/ ename VARCHAR(20) NOT NULL DEFAULT "", /*名字*/ job VARCHAR(9) NOT NULL DEFAULT "",/*工作*/ mgr MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,/*上级编号*/ hiredate DATE NOT NULL,/*入职时间*/ sal DECIMAL(7,2)  NOT NULL,/*薪水*/ comm DECIMAL(7,2) NOT NULL,/*红利*/ deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0 /*部门编号*/ ) ; #工资级别表 CREATE TABLE salgrade ( grade MEDIUMINT UNSIGNED NOT NULL DEFAULT 0, losal DECIMAL(17,2)  NOT NULL, hisal DECIMAL(17,2)  NOT NULL ); #测试数据 INSERT INTO salgrade VALUES (1,700,1200); INSERT INTO salgrade VALUES (2,1201,1400); INSERT INTO salgrade VALUES (3,1401,2000); INSERT INTO salgrade VALUES (4,2001,3000); INSERT INTO salgrade VALUES (5,3001,9999); delimiter $$ #创建一个函数,名字 rand_string,可以随机返回我指定的个数字符串 create function rand_string(n INT) returns varchar(255) #该函数会返回一个字符串 begin #定义了一个变量 chars_str, 类型  varchar(100) #默认给 chars_str 初始值   'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ' declare chars_str varchar(100) default 'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ'; declare return_str varchar(255) default ''; declare i int default 0; while i 

2.MyBatis流式查询

1.创建src\main\java\com\llp\llpmybatis\entity\Emp.java

@Data public class Emp { private Integer empno; private String ename; private String job; private Integer mgr; private Date hiredate; private BigDecimal sal; private BigDecimal comm; private Integer deptno; } 

2.创建src\main\java\com\llp\llpmybatis\vo\EmpVo.java

@Data public class EmpVo { @ExcelProperty("员工编号") private Integer empno; @ExcelProperty("员工姓名") private String ename; @ExcelProperty("员工工种") private String job; @ExcelProperty("主管编号") private Integer mgr; @ExcelProperty("入职日期") private Date hiredate; @ExcelProperty("工资") private BigDecimal sal; @ExcelProperty("通讯") private BigDecimal comm; @ExcelProperty("部门编号") private Integer deptno; } 

3.创建src\main\java\com\llp\llpmybatis\controller\EmpController.java

@RestController public class EmpController { @Autowired private EmpService empService; /** * 导出员工数据到excel */ @RequestMapping("/export") public void exportEmp(){ StopWatch watch = new StopWatch(); watch.start(); List empList = empService.exportEmp(); //将数据分sheet进行导出 EasyExcleUtil.excelExportDivisionBySheet(EmpVo.class, "员工信息_"+System.currentTimeMillis(), empList); watch.stop(); long totalTimeMillis = watch.getTotalTimeMillis(); System.out.println("共计耗时:"+totalTimeMillis+"毫秒"); } /** * 导入excel数据到员工表 * @param file */ @RequestMapping("/import") public void importEmp(@RequestParam(name = "file") MultipartFile file){ //这里我们在导入时传入回调接口的匿名内部类实现,在ExcleDataListener easyExcel读取监听器中对接口进行赋值 //在监听器中doAfterAllAnalysed,在所有数据解析完之后回调用这个方法,我们在方法中对导出的数据集进行赋值 EasyExcleUtil.importExcel(file, EmpVo.class, new ExcleFinshCallBack(){ @Override public void doAfterAllAnalysed(List result) { empService.exportEmp(); } }); } } 

4.创建src\main\java\com\llp\llpmybatis\service\EmpService.java

public interface EmpService { List exportEmp(); } 

5.创建src\main\java\com\llp\llpmybatis\service\impl\EmpServiceImpl.java(重点)

@Service public class EmpServiceImpl implements EmpService { @Resource private EmpDao empdao; /** * mybatis流式查询导出员工数据 * @return */ @Override public List exportEmp() { StopWatch stopWatch = new StopWatch(); stopWatch.start(); List empList = new ArrayList<>(); empdao.getAll(new ResultHandler() { /** * mybatis流失查询会回调处理逻辑 * @param resultContext */ @Override public void handleResult(ResultContext resultContext) { empList.add(resultContext.getResultObject()); } }); stopWatch.stop(); System.out.println("查询共计耗费"+stopWatch.getTotalTimeMillis()+"毫秒"); return empList; } } 

6.创建src\main\java\com\llp\llpmybatis\dao\EmpDao.java(重点)

@Repository public interface EmpDao { void getAll(ResultHandler handler); } 

这里dao层没有返回值,但是在还是需要指定resultMap,因为查询的数据要映射到回调函数的resultContext中,此外还需要设置:resultSetType=“FORWARD_ONLY” 、fetchSize=“-2147483648”

EmpDao.xml

  

至此mybatis流式查询就完成了

3.Excel通用导出工具类

1.Excel导入导出工具类

/** * excel读取监听器 */ public class ExcleDataListener extends AnalysisEventListener { //定义一个保存Excel所有记录的集合 private List list = new LinkedList<>(); //回调接口 private ExcleFinshCallBack callBack; /** * 构造注入ExcleFinshCallBack * @param callBack */ public ExcleDataListener(ExcleFinshCallBack callBack) { this.callBack = callBack; } /** * 这个每一条数据解析都会来调用 * 我们将每一条数据都保存到list集合中 * @param data    one row value. Is is same as {@link AnalysisContext#readRowHolder()} * @param context */ @Override public void invoke(Object data, AnalysisContext context) { list.add(data); } /** * 所有数据解析完成了 都会来调用这个方法 * 在 * @param context */ @Override public void doAfterAllAnalysed(AnalysisContext context) { this.callBack.doAfterAllAnalysed(this.list); } } 

2.Excel数据读取监听器

/** * excel读取监听器 */ public class ExcleDataListener extends AnalysisEventListener { //定义一个保存Excel所有记录的集合 private List list = new LinkedList<>(); //回调接口 private ExcleFinshCallBack callBack; /** * 构造注入ExcleFinshCallBack * @param callBack */ public ExcleDataListener(ExcleFinshCallBack callBack) { this.callBack = callBack; } /** * 这个每一条数据解析都会来调用 * 我们将每一条数据都保存到list集合中 * @param data    one row value. Is is same as {@link AnalysisContext#readRowHolder()} * @param context */ @Override public void invoke(Object data, AnalysisContext context) { list.add(data); } /** * 所有数据解析完成了 都会来调用这个方法 * 在 * @param context */ @Override public void doAfterAllAnalysed(AnalysisContext context) { this.callBack.doAfterAllAnalysed(this.list); } } 

4.Excel读取数据完成回调接口

/** * excel读取数据完成回调接口 */ public interface ExcleFinshCallBack { void doAfterAllAnalysed(List result); } 

5.拆分List集合工具类

/** * 拆分List集合 */ public class SplitListUtil { /** * * @param list 待切割集合 * @param len  集合按照多大size来切割 * @param  * @return */ public static  List> splitList(List list, int len) { if (list == null || list.size() == 0 || len <1) { return null; } List> result = new ArrayList>(); int size = list.size(); int count = (size + len - 1) / len; for (int i = 0; i  subList = list.subList(i * len, ((i + 1) * len > size ? size : len * (i + 1))); result.add(subList); } return result; } /** * @param source 源集合 * @param n      分成n个集合 * @param     集合类型 * @return * @description 集合平均分组 */ public static  List> groupList(List source, int n) { if (source == null || source.size() == 0 || n <1) { return null; } if (source.size() > result = new ArrayList>(); int number = source.size() / n; int remaider = source.size() % n; // 偏移量,每有一个余数分配,就要往右偏移一位 int offset = 0; for (int i = 0; i  list1 = null; if (remaider > 0) { list1 = source.subList(i * number + offset, (i + 1) * number + offset + 1); remaider--; offset++; } else { list1 = source.subList(i * number + offset, (i + 1) * number + offset); } result.add(list1); } return result; } } 

4.测试结果

sheet1

sheet2

sheet3

5.遗留问题,待处理

这个问题时由于excelWriter.finish();去关闭连接时,发现连接已经被终止了导致的,对数据导出的完整性并没有影响

 到此这篇关于MyBatis流式查询的项目实践的文章就介绍到这了,更多相关MyBatis流式查询内容请搜索0133技术站以前的文章或继续浏览下面的相关文章希望大家以后多多支持0133技术站!

以上就是MyBatis流式查询的项目实践的详细内容,更多请关注0133技术站其它相关文章!

赞(0) 打赏
未经允许不得转载:0133技术站首页 » Java