2015-09-09 114 views
2

有沒有機會從Spring DataSource或類似的程序中以某種方式獲取MyBatis中的當前sql語句?不幸的是,MyBatisExceptionTranslator只將語句放在消息中,這使得它很難使用。此外,它似乎並沒有把實際參數放在某個地方。MyBatis-Spring PersistenceExceptionTranslator - SQL語句?

我想要做的是爲MyBatis/Oracle編寫一個PersistenceExceptionTranslator,它能夠使用當前語句和賦予該語句的參數來確定最終的Exception,從而允許更好的錯誤消息。有沒有這樣做的機會?

有沒有機會這樣做?

+0

你讀過的MyBatis文檔中的內容? https://mybatis.github.io/mybatis-3/logging.html –

+0

我知道如何記錄生成的查詢,這不是問題。我只是沒有任何想法在錯誤處理過程中獲取這些信息,特別是在可以同時運行數十個查詢的多用戶設置中。 –

回答

1

所以,雖然我還沒有找到一個完美的答案,但(仍希望),我已經至少發現了一種可能性:

通過使用Spring AOP我可以環繞每個映射方法方面(使用映射器接口)。然後,這個方面可以判斷,由映射器類名和調用的方法名,語句的ID,例如...

com.example.mappers.SomeMapper.findSomethingById 

的看點可以使用配置(通過注入SqlSessionFactory)趕上的PersistenceException通過MyBatis的拋出,並得到MappedStatement並提供給映射器的放慢參數(S)擁有的所有有關語句的細節(SQL +參數):

@Around("execution(* com.example.mappers..*(..))") 
    public Object beforeTransactional(final ProceedingJoinPoint joinPoint) throws Throwable { 

    try { 
     return joinPoint.proceed(); 
    } catch (final PersistenceException ex) { 
     final MethodSignature signature = (MethodSignature) joinPoint.getSignature(); 
     final Class<?> mapperInterface = findMapper(joinPoint.getTarget()); 

     // StatementInfo : simple bean to store sql statement and parameter object 
     final StatementInfo info = findMappedStatement(signature.getMethod(), mapperInterface, joinPoint.getArgs()); 

     // a custom Exception extends PersistenceException 
     throw new CustomPersistenceException(info, ex); 
    } 

protected SQLException findSqlException(Throwable ex) { 
    while (ex != null && !(ex instanceof SQLException)) { 
     ex = ex.getCause(); 
    } 
    return (SQLException) ex; 
} 

protected StatementInfo findMappedStatement(final Method method, final Class<?> mapperInterface, final Object[] args) { 

    final String statementId = mapperInterface.getPackage().getName() + "." + mapperInterface.getSimpleName() + "." + method.getName(); 
    final MappedStatement mappedStatement = this.configuration.getMappedStatement(statementId); 

    final Object arg = args == null || args.length == 0 ? null : args[0]; 

    final BoundSql boundSql = mappedStatement.getBoundSql(arg); 

    final String sql = StringUtils.normalizeSpace(boundSql.getSql()); 

    return new StatementInfo(sql, arg); 
} 

不過,該解決方案是遠遠不夠完善,因爲它不允許我獲取實際創建錯誤的sql語句的sql代碼,只是調用「父」sql語句。例如:

如果我的(父)語句調用各種其他(子)語句,例如關聯或集合,並且其中一個會創建一個錯誤,那麼我的解決方案僅提供有關父語句而不是子語句的信息這實際上會導致錯誤。所以,另一種解決方案將是可取的。

另外我不能使用乾淨的PersistenceExceptionTranslator,因爲在mapper方法結束之前調用翻譯器,這是不幸的,因爲這意味着我將不得不通過AOP重新發明整個異常轉換。