MybatisGenerator以及Mybatis配置和抽取反射进行分页查询并批量写入磁盘文件

本文主要是介绍MybatisGenerator以及Mybatis配置和抽取反射进行分页查询并批量写入磁盘文件,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

由于业务需要,需要运用java来抽取数据库中的几十张表的全表信息,之后进行特定分隔并写入以表名为文件名的文本文件。

1.使用MybatisGenerator进行表和mapper的映射。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfigurationPUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN""http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<!-- 配置生成器 -->
<generatorConfiguration><!-- 加载JDBC配置文件 --><properties resource="config/jdbc.properties"/><!-- 指定数据库驱动的jdbc驱动jar包的位置 --><classPathEntry location="${jdbc.driverLocation}" /><!-- context:生成一组对象的环境 --><context id="MyBatis" targetRuntime="MyBatis3" defaultModelType="flat"><!-- beginningDelimiter和endingDelimiter:指明数据库的用于标记数据库对象名的符号,比如ORACLE就是双引号,MYSQL默认是`反引号; --><property name="beginningDelimiter" value=""/><property name="endingDelimiter" value=""/><!-- 生成的model实现Serializable借口 --><plugin type="org.mybatis.generator.plugins.SerializablePlugin"><!--<property name="suppressJavaInterface" value="true"/>--></plugin><!-- 自动生成equals方法和hashcode方法 -->
<!--        <plugin type="org.mybatis.generator.plugins.EqualsHashCodePlugin"/>--><!-- 该插件给实体类添加toString() --><plugin type="org.mybatis.generator.plugins.ToStringPlugin"/><!--        <plugin type="org.mybatis.generator.plugins.CaseInsensitiveLikePlugin"/>-->
<!--        <plugin type="org.mybatis.generator.plugins.MapperAnnotationPlugin"/>--><!--        <plugin type="org.mybatis.generator.plugins.RowBoundsPlugin"/>--><!-- 不生成注解 --><commentGenerator><!-- 这个元素用来去除指定生成的注释中是否包含生成的日期 false:表示保护 --><!-- 如果生成日期,会造成即使修改一个字段,整个实体类所有属性都会发生变化,不利于版本控制,所以设置为true --><property name="suppressDate" value="true" /><!-- 是否去除自动生成的注释 true:是 : false:否 --><property name="suppressAllComments" value="true" /></commentGenerator><!--数据库链接URL,用户名、密码 --><jdbcConnection driverClass="${jdbc.driverClassName}"connectionURL="${jdbc.url}"userId="${jdbc.username}"password="${jdbc.password}"></jdbcConnection><!-- java类型处理器 --><javaTypeResolver><property name="forceBigDecimals" value="false" /></javaTypeResolver><!--  java模型创建器targetPackage:生成的类要放的包targetProject:目标项目,指定一个存在的目录下,生成的内容会放到指定目录中--><!-- 生成模型的包名和位置 文件夹自己定义 --><javaModelGenerator targetPackage="com.simon.audit.pojo"targetProject="src/main/java"><!-- 在targetPackage的基础上,根据数据库的schema再生成一层package,最终生成的类放在这个package下,默认为false --><property name="enableSubPackages" value="false" /><!-- 设置是否在getter方法中,对String类型字段调用trim()方法 --><property name="trimStrings" value="true" /></javaModelGenerator><!-- 生成映射文件的包名和位置 文件夹自己定义--><sqlMapGenerator targetPackage="com.simon.audit.mapper"targetProject="src/main/java"><property name="enableSubPackages" value="false" /></sqlMapGenerator><!-- 生成DAO的包名和位置 文件夹自己定义--><javaClientGenerator type="XMLMAPPER"targetPackage="com.simon.audit.mapper"targetProject="src/main/java"><property name="enableSubPackages" value="false" /></javaClientGenerator><!-- 要生成哪些表 , %表示生成全部的表--><!-- 基表代码表--><table schema="xxxxx" tableName="yyyyy" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table></context>
</generatorConfiguration>

2.在resource目录下新建conf/jdbc.properties

2.将需要生成的表填到<table>标签下,运行Maven下的mybatis-generator即可生成pojo、Mapper.java和Mapper.xml

3.引入Mybatis的Maven依赖并配置Mybatis.xml

 <dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.5</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.6</version></dependency><dependency><groupId>com.oracle</groupId><artifactId>ojdbc14</artifactId><version>10.2.0.3.0</version></dependency><dependency><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-maven-plugin</artifactId><version>1.3.5</version></dependency>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><!-- 导入数据库相关配置文件(*注意:最多只能有一个) --><properties resource="config/jdbc.properties" /><!-- 全局变量配置 --><settings><!-- 开启驼峰命名法转换 --><setting name="mapUnderscoreToCamelCase" value="true"/><!-- 添加改行配置即可 --><setting name="logImpl" value="LOG4J"/></settings><!-- 不使用权限定名称时配置简称(两种方式,1.直接配置包名称;2.为每一个DO配置简称) --><typeAliases><package name="com.**.pojo"/></typeAliases><!-- 配置数据源环境(可多个,但必须配置default数据源) --><environments default="development"><!-- 第一个数据源 --><environment id="development"><transactionManager type="JDBC"/><dataSource type="com.simon.audit.dataSource.DuridDataSourceFactory">
<!--                <property name="driverClassName" value="${jdbc.driverClassName}"/>--><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/><property name="initialSize" value="1"/><property name="maxActive" value="20" /><!-- 配置获取连接等待超时的时间 --><property name="maxWait" value="60000" /></dataSource></environment><!-- 第二个数据源 -->
<!--        <environment id="dataSource2">-->
<!--            <transactionManager type="JDBC" />-->
<!--            <dataSource type="POOLED">-->
<!--                <property name="driver" value="${DS-2.driver}" />-->
<!--                <property name="url" value="${DS-2.url}"/>-->
<!--                <property name="username" value="${DS-2.user}"/>-->
<!--                <property name="password" value="${DS-2.password}"/>-->
<!--            </dataSource>-->
<!--        </environment>--></environments><!-- 将mapper.xml映射到mybatis中(这里的xml文件如果是放在resource目录下面的话就必须老老实实配置每一个xml文件,如果是放在src下面某一个包内,可以用package指定包路径) --><mappers><package name="com.simon.audit.mapper"/></mappers>
</configuration>

4.Mybatis.xml中数据源用的是Druid,配置数据源

public class DuridDataSourceFactory extends UnpooledDataSourceFactory {public DuridDataSourceFactory() {dataSource = new DruidDataSource();}
}

5.配置SqlSessionFactory

public class MyBatisSqlSessionUtil {/*** mybatis相关参数*/private final static String CONFIG_PATH = "config/mybatis.xml";private static InputStream input;private SqlSession sqlSession;private void init(String environment){try {input = Resources.getResourceAsStream(CONFIG_PATH);} catch (IOException e) {e.printStackTrace();}// 通过mybatis配置文件和datasource名称获取sqlSessionFactorySqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(input, environment);// 设置自动提交sqlSession = sqlSessionFactory.openSession(true);}/*** 使用默认datasource环境的构造器*/public MyBatisSqlSessionUtil(){init(null);}/*** 使用指定datasource环境的构造器*/public MyBatisSqlSessionUtil(String environment){init(environment);}/*** 创建Mapper实例*/public <T> T getMapper(Class<T> clazz){return sqlSession.getMapper(clazz);}/***     关闭连接,使用结束后必须执行*/public void close(){if (null != sqlSession) {sqlSession.close();}if (null != input) {try {input.close();} catch (IOException e) {e.printStackTrace();}}}

6.在生成的所有Mapper.xml和Mapper.java中添加公共方法

    List<XXXXXX> selectAll(Map<String, Integer> map);int selectCount();
  <select id="selectCount" resultType="int">select count(0)from xxxx.XXXXXXX</select><select id="selectAll" parameterType="map" resultMap="BaseResultMap">select<include refid="Base_Column_List"/>from xxxxx.XXXXXXXwhere 1=1<![CDATA[and rownum > #{start}]]><![CDATA[and rownum <= #{end}]]></select>

7.进行反射抽取以及分页查询和批量写入

 getResult方法传入需要写入文件的文件名称fileName(表名),和需要反射的xxxMapper.class。进行getClass().getMethods()的方法全量反射。这里反射的是Mapper.java接口中定义的insert、update、select等方法和对应实体类的toString、hashcode、equals等方法。所有不需要用到的方法尽量可以删去,提高效率。

如果匹配"selectCount"就用该method进行invoke,得到该表的count值。

如果count值大于设定值(比如10w或者100w)需要进行分页查询,否则select * 很难查出来,更有可能导致OOM。此时需要重新开启一个SqlSession,如果一直用之前创建的SQLSession不关闭会导致Mybatis一级缓存得不到释放,内存溢出。如果查询一次就关闭也会导致循环条件下Session关闭报错。所有在适当的条件下进行SQLSession的重新创建并对之前创建的对象进行手动垃圾回收System.gc。

在满足大于设定值的情况下,针对Sql进行分页查询。例如每次查询1w条,并将查询结果添加到allList中,allList集合满足10w条记录就往磁盘写一次。磁盘文件文件写满100w条就创建下一个磁盘文件再次进行写入。

 public <T, E> List<E> getResult(String fileName,Class<T> t) {MyBatisSqlSessionUtil myBatisSqlSessionUtil = new MyBatisSqlSessionUtil();T myBatisSqlSessionUtilMapper = myBatisSqlSessionUtil.getMapper(t);Method[] methods = myBatisSqlSessionUtilMapper.getClass().getMethods();List<E> list = null;List<Object> allList=new ArrayList<>();int count = 0;boolean endFlag = false;int fileCount = 0;Map<String, Integer> map = new HashMap<>();Method selectCountMethod = null;Method selectAllMethod = null;String nowFileName = fileName;for (Method method : methods) {if ("selectCount".equals(method.getName())) {selectCountMethod = method;}if ("selectAll".equals(method.getName())) {selectAllMethod = method;}}try {count = (int) selectCountMethod.invoke(myBatisSqlSessionUtilMapper);} catch (IllegalAccessException | InvocationTargetException e) {e.printStackTrace();}try {if (count > Constant.PAGE_LINE_COUNT) {MyBatisSqlSessionUtil myBatisSqlSessionUtil1 = myBatisSqlSessionUtil;T tMapper = myBatisSqlSessionUtilMapper;for (int i = 0; i < count; i += Constant.SELECT_EVERY_COUNT) {//重新定义session,,便于关闭Mybatis缓存map.put("start", i);map.put("end", i + Constant.SELECT_EVERY_COUNT);if (i + Constant.SELECT_EVERY_COUNT >= count) {map.put("end", count);endFlag = true;}allList.addAll((List<E>) selectAllMethod.invoke(tMapper, map));if(allList.size() >= Constant.WRITE_TIME_FILE_COUNT || endFlag){if(fileCount >= Constant.WRITE_NEXT_FILE_COUNT){String[] s = nowFileName.split("#");if(s.length == 2){nowFileName =s[0]+"#"+(Integer.valueOf(s[1])+1);MergeFile.createFileNum(Integer.valueOf(s[1])+1);}else {nowFileName = nowFileName+"#"+1;MergeFile.createFileNum(1);}writeResult(nowFileName,allList);fileCount = 0;allList.clear();//关闭session ,清除一级缓存myBatisSqlSessionUtil1.close();//手动进行垃圾回收System.gc();// 因为finalize方法优先级很低,所以暂停0.5秒以等待它Thread.sleep(500);myBatisSqlSessionUtil1 = new MyBatisSqlSessionUtil();tMapper = myBatisSqlSessionUtil1.getMapper(t);}else{//批量写入writeResult(nowFileName,allList);fileCount += Constant.WRITE_TIME_FILE_COUNT;allList.clear();}}}handleFiles(fileName);} else {map.put("start", 0);map.put("end", count);list = (List<E>) selectAllMethod.invoke(myBatisSqlSessionUtilMapper, map);writeResult(fileName, (List<Object>) list);}} catch (IllegalAccessException | InterruptedException | InvocationTargetException ex) {ex.printStackTrace();}myBatisSqlSessionUtil.close();return list;}

8.最后处理文件handleFiles()

  遍历生成文件的flieCount数(比如生成了13个带#的临时文件),将infile中的文件内容追加合并到outfile文件中。利用nio的FileChannel管道进行读写最后将所有文件归集到不带#的文件中,即最后需要的文件。切记最后一定要关闭流和手动垃圾回收。否则后面的deleteTempFile方法不能完全删除临时文件。

    private void handleFiles(String fileName) {System.out.println("-------------------开始合并文件-------------------");MergeFile.merger(fileName);MergeFile.deleteTempFile(fileName);System.out.println("-------------------完成合并文件-------------------");}public static void merger(String fileName){String infile;String outfile;try {for (int i= fileCount; i > 0; i--) {infile = Constant.PATH + Constant.FILE_NAME_START + Constant.SEPARATION + fileName+"#"+i + Constant.SEPARATION + Constant.FILE_NAME_END + Constant.TXT_SUFFIX;outfile = Constant.PATH + Constant.FILE_NAME_START + Constant.SEPARATION + fileName+"#"+(i-1) + Constant.SEPARATION + Constant.FILE_NAME_END + Constant.TXT_SUFFIX;if(i == 1){outfile = Constant.PATH + Constant.FILE_NAME_START + Constant.SEPARATION + fileName+ Constant.SEPARATION + Constant.FILE_NAME_END + Constant.TXT_SUFFIX;}// 获取源文件和目标文件的输入输出流FileInputStream fin = new FileInputStream(infile);FileOutputStream fout = new FileOutputStream(outfile,true);// 获取输入输出通道FileChannel  fcin = fin.getChannel();FileChannel  fcout = fout.getChannel();// 创建缓冲区ByteBuffer buffer = ByteBuffer.allocate(1024);while (true) {// clear方法重设缓冲区,使它可以接受读入的数据buffer.clear();// 从输入通道中将数据读到缓冲区int r = fcin.read(buffer);// read方法返回读取的字节数,可能为零,如果该通道已到达流的末尾,则返回-1if (r == -1) {break;}// flip方法让缓冲区可以将新读入的数据写入另一个通道buffer.flip();// 从输出通道中将数据写入缓冲区fcout.write(buffer);}fin.close();fout.close();fcin.close();fcout.close();buffer.clear();}} catch (IOException e) {e.printStackTrace();}finally {System.gc();}}public static void deleteTempFile(String fileName){try {for (int i = 1; i <= fileCount; i++) {String deleteFilePath = Constant.PATH + Constant.FILE_NAME_START + Constant.SEPARATION + fileName + "#" + i + Constant.SEPARATION + Constant.FILE_NAME_END + Constant.TXT_SUFFIX;// 获取源文件和目标文件的输入输出流File file = new File(deleteFilePath);file.delete();Thread.sleep(2000);}} catch (InterruptedException e) {e.printStackTrace();}}

如果需要全部代码可以进行下载:

https://download.csdn.net/download/simon_09010817/11716181

这篇关于MybatisGenerator以及Mybatis配置和抽取反射进行分页查询并批量写入磁盘文件的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/503752

相关文章

java中反射Reflection的4个作用详解

《java中反射Reflection的4个作用详解》反射Reflection是Java等编程语言中的一个重要特性,它允许程序在运行时进行自我检查和对内部成员(如字段、方法、类等)的操作,本文将详细介绍... 目录作用1、在运行时判断任意一个对象所属的类作用2、在运行时构造任意一个类的对象作用3、在运行时判断

SQL Server配置管理器无法打开的四种解决方法

《SQLServer配置管理器无法打开的四种解决方法》本文总结了SQLServer配置管理器无法打开的四种解决方法,文中通过图文示例介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录方法一:桌面图标进入方法二:运行窗口进入检查版本号对照表php方法三:查找文件路径方法四:检查 S

MyBatis-Plus 中 nested() 与 and() 方法详解(最佳实践场景)

《MyBatis-Plus中nested()与and()方法详解(最佳实践场景)》在MyBatis-Plus的条件构造器中,nested()和and()都是用于构建复杂查询条件的关键方法,但... 目录MyBATis-Plus 中nested()与and()方法详解一、核心区别对比二、方法详解1.and()

从入门到精通MySQL联合查询

《从入门到精通MySQL联合查询》:本文主要介绍从入门到精通MySQL联合查询,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下... 目录摘要1. 多表联合查询时mysql内部原理2. 内连接3. 外连接4. 自连接5. 子查询6. 合并查询7. 插入查询结果摘要前面我们学习了数据库设计时要满

MySQL查询JSON数组字段包含特定字符串的方法

《MySQL查询JSON数组字段包含特定字符串的方法》在MySQL数据库中,当某个字段存储的是JSON数组,需要查询数组中包含特定字符串的记录时传统的LIKE语句无法直接使用,下面小编就为大家介绍两种... 目录问题背景解决方案对比1. 精确匹配方案(推荐)2. 模糊匹配方案参数化查询示例使用场景建议性能优

mysql表操作与查询功能详解

《mysql表操作与查询功能详解》本文系统讲解MySQL表操作与查询,涵盖创建、修改、复制表语法,基本查询结构及WHERE、GROUPBY等子句,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随... 目录01.表的操作1.1表操作概览1.2创建表1.3修改表1.4复制表02.基本查询操作2.1 SE

Linux中SSH服务配置的全面指南

《Linux中SSH服务配置的全面指南》作为网络安全工程师,SSH(SecureShell)服务的安全配置是我们日常工作中不可忽视的重要环节,本文将从基础配置到高级安全加固,全面解析SSH服务的各项参... 目录概述基础配置详解端口与监听设置主机密钥配置认证机制强化禁用密码认证禁止root直接登录实现双因素

嵌入式数据库SQLite 3配置使用讲解

《嵌入式数据库SQLite3配置使用讲解》本文强调嵌入式项目中SQLite3数据库的重要性,因其零配置、轻量级、跨平台及事务处理特性,可保障数据溯源与责任明确,详细讲解安装配置、基础语法及SQLit... 目录0、惨痛教训1、SQLite3环境配置(1)、下载安装SQLite库(2)、解压下载的文件(3)、

Golang如何对cron进行二次封装实现指定时间执行定时任务

《Golang如何对cron进行二次封装实现指定时间执行定时任务》:本文主要介绍Golang如何对cron进行二次封装实现指定时间执行定时任务问题,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录背景cron库下载代码示例【1】结构体定义【2】定时任务开启【3】使用示例【4】控制台输出总结背景

Golang如何用gorm实现分页的功能

《Golang如何用gorm实现分页的功能》:本文主要介绍Golang如何用gorm实现分页的功能方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录背景go库下载初始化数据【1】建表【2】插入数据【3】查看数据4、代码示例【1】gorm结构体定义【2】分页结构体