如何批量测试Mybatis项目中SQL是否正确

去Oracle行动

最近公司要发展海外项目,所以要将现有的系统全部平移过去,另外数据库也要从原来的Oracle变为Mysql。公司的数据库交互层面使用的是Mybatis,而Oracle与Mysql也有一些语法上的不同。所以在项目中的Sql要改动,但是多个项目中涉及到的Sql非常多,如果仅凭人工一条一条辨别的话,工作量有点大。

所以就萌发出了直接将数据源变为Mysql,利用反射批量执行Mapper中的方法,然后如果有参数的话,就设置为默认的初始值,然后记录下来成功的数据和失败的数据,这样就可以根据失败原因进行修改。能够节省很大的时间。

执行效果

代码介绍

总体思路就三步

  • 通过反射获得要执行的Mapper类的所有方法
  • 获得方法中的参数,并赋值
  • 执行
AutoTestMapper autoTestMapper = new AutoTestMapper("存放Mapper全路径名");
autoTestMapper.openSqlSession(sqlSessionFactory);

在构造函数中传入全路径名后,进行解析,解析出包名和所有的文件名并存储起来

    public AutoTestMapper(String path) throws IOException, ClassNotFoundException {
        String mapperContent = getFileContent(path);
        String pathPattern = "import [a-z,A-Z,/.]+;";
        String[] pathArr = matchMethod(pathPattern, mapperContent).split(";");
        for (int i = 0; i < pathArr.length; i++) {
            pathArr[i] = pathArr[i].replaceAll("import ", "");
            Class cls = Class.forName(pathArr[i]);
            if (!cls.isInterface()) {
                TYPE_ARRAY.add(cls);
            }
        }
        //获得全路径名的前缀
        String packPattern = "package [a-z,A-Z,/.]+;";
        String[] packPathArr = matchMethod(packPattern, mapperContent).split(";");
        String packPath = packPathArr[0].replaceAll("package ", "").replaceAll(";", "");
        this.PACK_PATH = packPath;
    }

然后调用openSqlSession的方法,传入SqlSessionFactory参数

        List<Map<Class, Object>> list = new ArrayList<>();
        List<String> invokeSuccess = new ArrayList<>();
        List<String> invokeFail = new ArrayList<>();
        for (String fileName : FILE_NAME) {
            Class cls = Class.forName(PACK_PATH + "." + fileName);
            //添加Mapper
            if (!sqlSessionFactory.getConfiguration().hasMapper(cls)){
                sqlSessionFactory.getConfiguration().addMapper(cls);
            }
            //获得Mapper
            Object mapper = sqlSessionFactory.openSession().getMapper(cls);
            //反射执行Mapper的方法
            Map<String, List<String>> resultMap = autoTestInvoke(cls, mapper);
            invokeSuccess.addAll(resultMap.get(SUCCESS_FLG));
            invokeFail.addAll(resultMap.get(FAIL_FLG));
        }

然后通过Mybatyis提供的方法getMapper()传入类名获得所要Mapper类。核心方法就是autoTestInvoke()方法了

      private Map<String, List<String>> autoTestInvoke(Class c, Object o)
     {
        Method[] declaredMethods = c.getDeclaredMethods();
        String fileName = c.getName().substring(c.getName().lastIndexOf("."));
        List<String> invokeSuccess = new ArrayList<>();
        List<String> invokeFail = new ArrayList<>();
        Map<String, List<String>> resultMap = new HashMap<>();
        //给参数赋初始值
        for (Method method : declaredMethods) {
            List<Object> list = new ArrayList<>();
            for (Class cls : method.getParameterTypes()) {
                Object par = new Object();
                if (TYPE_ARRAY.contains(cls)) {
                    if (cls.equals(String.class)) {
                        par = "1";
                    } else {
                        try {
                            par = cls.newInstance();
                            assignment(cls, par);
                        } catch (InstantiationException e) {
                            if (cls.isPrimitive()) {
                                cls = primitiveClazz.get(cls.getName());
                            }
                            try {
                                par = cls.getDeclaredConstructor(String.class).newInstance("1");

                            }catch (NoSuchMethodException e1){
                                System.out.println(cls.getName()+e);
                            }
                        }
                    }
                }else if ("java.util.Map".equals(cls.getName())){
                    par = getMapData(c.getName()+"."+method.getName());
                }
                list.add(par);
            }
            try {
                method.invoke(o, list.toArray());
                invokeSuccess.add("Success: " + fileName + "." + method.getName());
            } catch (Exception e) {
                invokeFail.add("Error:" + method.getName() + "   Error Info:" + e);
            }
        }
        resultMap.put(SUCCESS_FLG, invokeSuccess);
        resultMap.put(FAIL_FLG, invokeFail);
        return resultMap;
    }

这里面完成为参数赋初始值,和执行的逻辑。

使用说明

自动测试Mapper除了传参为List和Set,其余都能测到。在xml中所有的if条件都会拼接到。

将AutoTestMapper拷贝到测试模块中。如图所示

在resources模块中加入mybatis-config.xml文件,如图所示

mybatis-config.xml内容如下

<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="dev">
        <environment id="dev">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="连接地址"/>
                <property name="username" value="账号"/>
                <property name="password" value="密码"/>
            </dataSource>
        </environment>
    </environments>
</configuration>

在根目录创建lib文件夹,并将测试的Mybatis版本放入其中,并在Gradle中引入此包

compile files(‘../lib/mybatis-3.5.0-hupengfeiTest.jar‘)此处路径填写相对路径

如果目录结构如下,那么就compile files(‘lib/mybatis-3.5.0-hupengfeiTest.jar‘)

mybatis-3.5.0-hupengfeiTest.jar在github下面的lib目录中

-lib
    -- mybatis-3.5.0-hupengfeiTest.jar
-build.gradle

如果目录结构如下,那么就compile files(‘../lib/mybatis-3.5.0-hupengfeiTest.jar‘)

-lib
    -- mybatis-3.5.0-hupengfeiTest.jar
-service
    -- build.gradle

在单元测试中编写代码,进行测试

@RunWith(SpringJUnit4Cla***unner.class)
@SpringBootTest(classes = { AirApplication.class })//此处AirApplication.class为项目中的启动类,自行修改
public class TestMapper {

    @Test
    public void testCeshi()
            throws IllegalAccessException, IntrospectionException, InvocationTargetException, NoSuchMethodException,
            InstantiationException, IOException, ClassNotFoundException {
        //读取Mybatis配置
        Reader resourceAsReader = Resources.getResourceAsReader("mybatis-config.xml");
        //生成SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsReader);
        resourceAsReader.close();
        AutoTestMapper autoTestMapper = new AutoTestMapper(存放Mapper的Java文件夹的全路径名);
        //执行测试方法
        autoTestMapper.openSqlSession(sqlSessionFactory);
    }
}

就会在控制台中打印出执行失败的Mapper以及其原因。如下图所示

原文地址:https://blog.51cto.com/14230003/2445963

时间: 2024-10-29 14:04:39

如何批量测试Mybatis项目中SQL是否正确的相关文章

详解Java的MyBatis框架中SQL语句映射部分的编写

这篇文章主要介绍了Java的MyBatis框架中SQL语句映射部分的编写,文中分为resultMap和增删查改实现两个部分来讲解,需要的朋友可以参考下 1.resultMap SQL 映射XML 文件是所有sql语句放置的地方.需要定义一个workspace,一般定义为对应的接口类的路径.写好SQL语句映射文件后,需要在MyBAtis配置文件mappers标签中引用,例如: ? 1 2 3 4 5 6 <mappers>   <mapper resource="com/limi

SpringBoot Mybatis项目中的多数据源支持

1.概述 有时项目里里需要抽取不同系统中的数据源,需要访问不同的数据库,本文介绍在Springboot+Mybatis项目中如何支持多数据源操作. 有需要的同学可以下载 示例代码 2.建数据源 首先,我们建两个测试库 test1 test2,分别建两个表,分别添加一些测试数据 CREATE TABLE `groupidinfo` ( `id` int(11) NOT NULL AUTO_INCREMENT, `groupId` varchar(255) DEFAULT NULL, `versio

使用junit4测试spring项目中service方法

使用junit4测试项目中service方法 1 import java.util.HashMap; 2 import java.util.List; 3 import java.util.Map; 4 5 import javax.annotation.Resource; 6 7 import org.junit.Test; 8 import org.junit.runner.RunWith; 9 import org.springframework.test.context.ContextC

项目中 SimpleDateFormat 的正确使用

项目中 SimpleDateFormat 的正确使用 日常开发中,我们经常需要使用时间相关类,说到时间相关类,想必大家对 SimpleDateFormat 并不陌生.主要是用它进行时间的格式化输出和解析,挺方便快捷的,但是 SimpleDateFormat 并不是一个线程安全 的类.在多线程情况下,会出现异常,想必有经验的小伙伴也遇到过.下面我们就来分析分析SimpleDateFormat为什么不安全?是怎么引发的?以及多线程下有那些SimpleDateFormat的解决方案? 先看看<阿里巴巴

在springboot 和 mybatis 项目中想要显示sql 语句进行调试

在springBoot+Mybatis日志显示SQL的执行情况的最简单方法就是在properties新增: logging.level.com.dy.springboot.server.mapper=debug 注意:其中com.dy.springboot.server.mapper是要打印sql 语句的包,logging.level.com.你的Mapper包=日志等级 原文地址:https://www.cnblogs.com/zhaopengcheng/p/9592096.html

Spring+MyBatis框架中sql语句的书写,数据集的传递以及多表关联查询

在很多Java EE项目中,Spring+MyBatis框架经常被用到,项目搭建在这里不再赘述,现在要将的是如何在项目中书写,增删改查的语句,如何操作数据库,以及后台如何获取数据,如何进行关联查询,以及MyBatis的分页问题. 首先先看看项目的架构,方便后边叙述. 这个项目中是一个Sping+MyBatis的完整demo(这边将页面没有展示.)这次的主题主要是后台数据处理逻辑.接下来为大家逐一介绍各个文件, org.config   Spring配置包括数据库的链接信息 org.control

Spring+Mybatis项目中通过继承AbstractRoutingDataSource实现数据库热切换

在做ERP项目的时候有个需求是能够管理和切换账套,一个账套就是一个数据库,那么就需要实现数据库的热切换.网上找了很多资料再结合项目的具体需求实现了一个还算比较好用的数据库热切换. 原理是首先继承AbstractRoutingDataSource并实现determineCurrentLookupKey方法,方法的内容为 protected Object determineCurrentLookupKey() {     return DataSourceContextHolder.getDataS

批量产生ssh2项目中hibernate带注解的pojo类的快捷方法

近几个月一直在忙于项目组的ios应用项目的开发,没有太多时间去研究web应用方面的问题了.刚好,昨天有网友问到如何批量产生hibernate带注解的pojo类的快捷方法,所谓批量就是指将当前数据库中所有数据表全部一次性生成带注解的pojo类,假设当前数据库friend有50个数据表,如果一个个的新建产生pojo类的话,那就是说要手工输入新建50个pojo类后,还有输入每个类带注解的代码,并且还要写好有关联的类之间的映射关系,虽然,从学习的角度来说,手工写是个不错的主意,但是从开发效率和开发成本来

mybatis.xml中sql编写规范

一.越少的代码,越强悍的功能,xml里面应该6个sql语句就够用了,修改,维护成本很低,见下表 下载 英文名 方法名称 核心点 建议 insert 1.新增数据 如果是自增主键,应该返回主键ID deleteById 2. 根据主键ID删除数据 sql默认加limit 1,防止多删数据 此方法不建议有,建议逻辑删除 updateById 3. 根据主键ID修改数据 sql默认加limit 1,防止多修改数据 selectById 4. 根据主键查询数据 查询一条数据 selectByIdForU