你不知道的MyBatis自带实用工具类

564 阅读3分钟

mybatis内部提供了很多使用的工具,如果不仔细研究mybatis,平时的一些工作往往会重复造轮子,比如下面的几种情况

  1. 字符串拼接SQL
  2. 反射获取对象属性并设置值
  3. 反射判断对象是否包含某个方法,是否包含构造方法,获取Class中的某个属性的类型

下面就来看一下mybatis提供的实用工具类怎么快速的解决这些问题吧~再也不用重复造轮子了。

拼接SQL

之前项目里这么拼接SQL

@Test
public void noMybatisSQL(){
    StringBuilder sb = new StringBuilder();
    String table = "user";
    String sql = sb.append("select * ").append("distinct id ")
            .append("from ").append(table).append(...........省略)
}

这种写法写的快恶心吐了,可读性还差,得思考好久才能知道SQL写的啥,而且项目里远远要复杂我上面的这个例子,比如项目里把查询的表,过滤的条件等都存在了数据库中,都需要变量接收然后再做拼接。后来发现mybatis自带的工具类可以拼接SQL而且可读性非常好。并且无须关心关键字之间的空格问题,看即上手.

而且动态拼接SQL的可读性也非常好。

@Test
public void testSQL() {
    String name = "张三";
    String sql = new SQL() {{
        SELECT("*");
        FROM("user u");
        INNER_JOIN("role r on u.id = r.id ");
        if (name != null) {
            WHERE("uname='" + name + "'");
        }
    }}.toString();
    System.out.println(sql);
}

API我放这里了

image.png

image.png

MetaObject反射工具

mybatis提供了一个反射工具类MetaObject,它帮我们屏蔽掉了反射的复杂细节,通过SystemMetaObject.forObject方法返回的对象,就可以通过属性名称来获取属性值与设置属性值,非常简单,如果属性是另外一个对象可以通过a.b.c.d的形式无限递归的获取属性,用法如下。

@Test
public void test() {
    User user = new User();
    MetaObject metaObject = SystemMetaObject.forObject(user);
    metaObject.setValue("name", "zhangsan");
    Integer age = (Integer) metaObject.getValue("age");
    System.out.println(user);
    System.out.println(age);
}

MetaClass工具类

上面说到的MetaObject是用来获取对象的属性,其中的操作是针对对象而言的。

MetaClass是针对class类型进行操作的,它可以获得class类型的getter方法、setter方法、构造函数,属性的类型等等。用法如下

// 先定义一个POJO
public class User1 {
    private String name;
    private Integer age = 18;
    private String p;

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

 @Test
public void test2() throws InvocationTargetException, IllegalAccessException {
    MetaClass metaClass = MetaClass.forClass(User1.class);
    System.out.println(metaClass.hasGetter("name")); // false
    System.out.println(metaClass.hasDefaultConstructor()); // true
    System.out.println(metaClass.getSetterType("age")); // class java.lang.Integer
    // 获取getter方法
    Invoker ageGetInv = metaClass.getGetInvoker("age");
    Object invoke = ageGetInv.invoke(new User1(), null); // 调用反射方法
    System.out.println(invoke); // 输出该方法原本的返回类型
    // 获取setter方法并调用
    User1 user1 = new User1();
    Invoker nameSetInv = metaClass.getSetInvoker("name");
    nameSetInv.invoke(user1,new Object[]{"李四"});
    System.out.println(user1);
}

输出结果

true
true
class java.lang.Integer
18
User{name='李四', age=18}

可以看到通过MetaClass可以很方便的获取到对象内部的getter/setter/默认构造方法,属性类型。比使用Class对象获取方法要简单很多。所以再涉及到反射的操作可以使用该对象方便开发。

总结

  1. 拼接SQL使用mybatis自带的SQL工具类可以使得代码的可读性非常好而不影响效率,并且无须关心关键字之间的空格
  2. 反射操作使用MetaObject MetaClass 这两个工具类可以很方便的判断一个Class是否有某个方法,获取Class的方法并反射执行,获取对象的属性,反射直接设置对象的属性值。