Mybatis反射修改SQL值

xiuyangsong 2020-05-31

Mybatis反射修改SQL值

某一些情况下我们需要动态的改变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
		
	}

代码具体实现

相关推荐