xiuyangsong 2020-05-31
某一些情况下我们需要动态的改变Mybtis的执行的sql语句,有两种方法:1)使用拦截器,2)使用反射,拦截器的比较简单点,这里使用反射实现一次,有一点小坑,记录一下:
特别说明:环境配置就不列出来了,下面的所有操作是假设spring已经整合好了mybatis的基础上的。具体的代码连接见文章结尾:
重点在于org.apache.ibatis.builder.StaticSqlSource.getBoundSql(Object)
@Override public BoundSql getBoundSql(Object parameterObject) { return new BoundSql(configuration, sql, parameterMappings, parameterObject); } // 每次获得是一个新的对象,这里使用反射修改是无效的,所以需要直接修改 BoundSql 的 sql 子弹
代码:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration({"classpath:applicationContext2.xml"}) public class MapperTest { @Autowired private SqlSessionFactoryBean sqlSessionFactoryBean; // 动态修改sql // 1. 使用 mybatis 的插件来完成参考分页插件改变查询的SQL com.bart.plugins.MyBatisPagePlugi // 2. 使用反射修改MappedStatement的boundSql @Test public void testDynamicModifySQL2() throws Exception { SqlSessionFactory sessionFactory = sqlSessionFactoryBean.getObject(); Configuration configuration = sessionFactory.getConfiguration(); MappedStatement mappedStatement = configuration.getMappedStatement("com.bart.common.mapper.dao.EmployeeMapper.selectAll"); // org.apache.ibatis.scripting.defaults.RawSqlSource // 该 sqlSource 中还有一个 org.apache.ibatis.builder.StaticSqlSource 实例 // getSqlSource() 实际上是调用的内部的 StaticSqlSource#getSqlSource() 方法 // 而StaticSqlSource#getSqlSource()每次返回的是一个新的BoundSql对象直接修改这个 // 是无效的,所以我们需要使用反射直接修改那个 StaticSqlSource 中的 sql 字符串的值 SqlSource rowSqlSource = mappedStatement.getSqlSource(); System.out.println(String.format("修改前的SQL = %s", rowSqlSource.getBoundSql(null).getSql())); // 获得 private final SqlSource sqlSource; 对象 Field staticsqlSourceField = rowSqlSource.getClass().getDeclaredField("sqlSource"); staticsqlSourceField.setAccessible(true); Object staticsqlSourceObject = staticsqlSourceField.get(rowSqlSource); // 修改 sqlSource 的 sql 字段值 Field sqlField = staticsqlSourceObject.getClass().getDeclaredField("sql"); sqlField.setAccessible(true); String sqlFieldValue = (String)sqlField.get(staticsqlSourceObject); sqlField.set(staticsqlSourceObject, sqlFieldValue +" limit 1"); System.out.println(String.format("修改前的SQL = %s", rowSqlSource.getBoundSql(null).getSql())); System.out.println("============分割线==============="); List<Employee> list = employeeMapper.selectAll(); list.stream().forEach(System.out::println); // 查询出来就是一条了OK }