Mybatis的缺陷

Mybatis是业界很是流行的持久层框架,轻量级、易用,在金融IT领域彻底是领军地位,比Hibernate更受欢迎,优点很是多,也是很是值得咱们学习的。但Mybatis并不尽善尽美,其自身的设计、编码也还有许多不足,甚至是缺陷,这篇文章来简要讨论一下这些缺陷:sql

1.Mybatis使用DTD做为XML配置文件的校验文件,可是很明显,DTD差很少是快被淘汰的技术了,功能很是有限,扩展性很是差,扩展性很是差,扩展性很是差,可读性也很差,Spring可以从DTD到XSD华丽转身,但Mybatis始终没这个魄力。数据库

2.版本兼容性作的很差,就拿3.3.0—>3.4.0来讲,按业界通用规范,第2级版本号升级,能够添加功能,可是要保证向下兼容性,然而Mybatis的作法并不彻底是这样的,看一下关键接口StatementHandler的关键方法prepare:缓存

// 3.3.0
Statement prepare(Connection connection)
      throws SQLException;

// 3.4.0
Statement prepare(Connection connection, Integer transactionTimeout)
      throws SQLException;

这里没有添加一个方法,而是直接在原方法中添加了一个参数!相似例子还有很多,就不一一列举了。app

3.Mybatis的插件,采用一个通用的Interceptor接口,配以@Intercepts、@Signature等注解,实现对多个组件的多种方法的拦截,看似很是灵活,在我看来实际上是结构不够清晰,实际开发时,你会把对StatementHandler和ResultSetHandler的拦截加强放在一个类里面吗?不会是吧(会?你当单一职责原则、开闭原则都是狗屎吗),那有什么必要强制使用同一个接口呢?框架

另外,使用@Signature注解来设别须要被拦截的组件方法,若是注解有错,编译也是不会报错的,而只能等到运行时才能发现,再看上面的例子:dom

假设我针对3.3.0版本实现了一个插件:ide

@Intercepts({ 
    @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class })
})
public class StatementHandlerInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        
    }
}

而后,升级为3.4.0,结果呢,编译一直正常,可是等到运行,却抛出异常了。函数

4.Mybatis的缓存简直就是鸡肋,并且无论有没有配置须要使用缓存、是否更新缓存,都要去计算CacheKey,不使用缓存、也不更新缓存的状况下,这种计算彻底是浪费。学习

5.Mybatis的批量执行,看下面的一个JDBC例子:this

public void testJdbcBatch(Connection conn) throws Exception {

try{ conn.setAutoCommit(false); batchUpdate(conn); clearTestData(conn); conn.commit(); conn.setAutoCommit(true); }catch(Exception e){ conn.rollback(); throw e; } } private void clearTestData(Connection conn) throws SQLException { PreparedStatement ps = null; try{ ps = conn.prepareStatement("delete TABLE_NAME1 where FIELD_NAME1 = ? "); ps.setString(1, "TEST"); int d = ps.executeUpdate(); System.out.println("delete counts : " + d); }finally{ try{ ps.close(); }catch(Exception e){} } } private void batchUpdate(Connection conn) throws SQLException { PreparedStatement ps = null; try{ String sql = "INSERT INTO TABLE_NAME2(FIELD_NAME1, FIELD_NAME2, FIELD_NAME2)VALUES(?,?,?)"; ps = conn.prepareStatement(sql); for(int i = 0; i < 10; i++){ String random = RandomStringUtils.randomAlphabetic(8); ps.setString(1, "TEST");//FIELD_NAME1 ps.setString(2, "数据" + random);//FIELD_NAME2 ps.setString(3, "参数" + random);//FIELD_NAME3 ps.addBatch(); } int[] rs = ps.executeBatch(); }finally{ try{ ps.close(); }catch(Exception e){} } }

代码没有什么违和感,可以执行正常,也能够按预期的回滚,也就是说同一个事务中的同一个connection,能够同时运行普通sql和batch,可是你在同一个事务的SqlSession中试试,反馈给你的是——不能在同一个事务中切换执行方式!

六、数据库产品的兼容性:Mybatis把SQL的控制权交给了开发人员,因而从道德上占据了制高点——你写的不兼容,那是你本身的水平不行!但,这是一个真正的优秀框架的正确姿式吗?为何就不能提供一些辅助性的兼容实施?好比说在Oracle中被奉为神明的DECODE函数,是否能够在SqlMapper中提供一个<decode>标签,在后面默默的修改为CASE WHEN?或者说,官方不提供没有关系,但你得提供扩展方式啊,因而又回到了:扩展性很是差,扩展性很是差,扩展性很是差。重要的事说三遍,但,我已经说六遍了。

相关文章
相关标签/搜索