前言
最近项目里想要进行大表横向分表。
对于切分的表需要有一个查询的方案。
这种方案类似于将log文件定期切分存入表进行管理。
但是动态的建表我还未研究,本次先记录动态的选择表进行查询相关的知识点。
总共有2点:
- 多参数输入
- statementType=“STATEMENT” 和 ${} 方式
示例代码
下方mapper相关的示例代码就是包含了两个知识点。
XXXmapper.xml
<select id="findUserByIdFromTable"
resultType="TestUser"
statementType="STATEMENT"
>
SELECT
*
FROM
${table_name} tu
WHERE
tu.user_id = ${user_id}
</select>
XXXmapper.java
//测试动态查询
public List< TestUser >findUserByIdFromTable (@Param("table_name")String table_name ,@Param("user_id") Integer user_id) throws Exception;
test.java
//通用测试函数组1
public static void test() throws Exception {
//testSearchById2();
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
SqlSession sqlSession= sqlSessionFactory.openSession();
TestMapper mapper = sqlSession.getMapper(TestMapper.class);
//4.调用Mapper对象的API
//List<OrderEx> orders= mapper.findOrdersAndUserRstType();
//List<OrderEx> orders= mapper.findOrdersAndUserRstMap();
//List<UserEx> userEx= mapper.findUsersAndOrderRstMap();
List<TestUser> users= mapper.findUserByIdFromTable("test_user",1);
System.out.println(users);
//5. 打印结果
System.out.println("test over");
//6. 释放资源
sqlSession.close();
in.close();
}
多参数输入:@param注解
多参数输入有多种方案,常用的一种办法为将需要输入的多个参数封装成一个类,封装完毕后,将整个对象作为一个参数输入。
另一个方案为本次介绍的注解方案,也很常用。
使用方法为:
将@param
注解添加name属性,属性的值作为键值在xml文件中以{name}
的方式使用。那么以这种注解修饰的参数就会填入目标的位置,而在{name}
前是选择 #
还是$
则根据需求来定。
(举例略,见上方的例子)
statementType=“STATEMENT” 和 ${} 方式
重点
- 当配置
statementType="STATEMENT"
(非预编译)参数只能使用${}
方式而不能使用#{}
方式。 ${}
方式输入参数需要注意防止SQL注入(输入的参数作为拼合SQL时破坏原本结构,导致未知后果)
PreparedStatement
Mybatis 默认情况下,将对所有的 sql 进行预编译处理。Mybatis中使用 statementType
来设置编译类型,默认是PreparedStatement
(预编译)。
由于预编译时数据库会进行词法和语义的解析、生成执行计划,因此占位符只能占位SQL语句中的普通值,而表名、列名、关键字等影响编译的部分是不可以使用占位符的(也就是不能使用#{}
传参,而是需要使用${}
传参)。
因此上方举例代码可以改为如下也不影响功能:
<select id="findUserByIdFromTable"
resultType="TestUser"
>
SELECT
*
FROM
${table_name} tu
WHERE
tu.user_id = #{user_id}
</select>
(尽量使用#{}
传参,用预编译类型)
statementType=“STATEMENT”
当配置为非预编译时,则需要在整个语句中都采用${}
,而不能采用#{}
。
在通常情况下,都可以采用将整体配置为预编译的模式,然后针对需要不可以使用占位符的区域采用${}
来传入参数,比如表名、列名、关键字等。
非预编译和预编译的区别在于:
- 非预编译没有缓存,每一次都要重新组合。
- 预编译有占位符能防止SQL注入,非预编译没有
结语
原本是尝试一下怎么把表名输进去的,然后稍微了解了一下预编译和非预编译。结论就是尽量使用预编译功能,不论是性能和安全性。对此我存疑,如何对于不能使用预编译功能的输入参数进行管理呢。
后续如果找到了方案我会在此更新: