mybatis详解(2)
1 #和$的区别
# | $ |
---|---|
PreparedStatement | Statement |
? | 拼接 |
解决了SQL注入漏洞 | SQL注入漏洞( OR 1=‘1’) |
#{title} —>book.getTitle() | ORDER BY ${price} -->将传入的price拼接在ORDER BY 的后面 |
1.1 例子
1.1.1 第一步:在接口中写方法
1.1.2 第二步:写sql语句
1.1.3 第三步:测试
使用$的测试,可以看到成功查询,并且以价格高到低排序
1.1.4 补充:如果在第二步用#{price}代替${price}
- #是注入book.get()方法的值,而book中并没有book_price DESC 这个属性,自然也就调用不了get方法。
- 因此,如果使用#,就只会做全查询
2 缓存问题
2.1 用一个查询测试
@Test
public void testFindById() throws IOException {
// 这里先把before和after注释
// 1.读取mybatis配置文件,变成字符流对象
Reader in = Resources.getResourceAsReader("resources/mybatisConfig/mybatis-config.xml");
// 2.创建SqlSessionFactory工厂,管理多个数据库操作会话
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
// 3.开启一次sql会话
sqlSession = sqlSessionFactory.openSession();
// 4.创建数据库操作接口对象
IBookMapper mapper = sqlSession.getMapper(IBookMapper.class);
// 5.接口操作,调用接口方法
Book book = mapper.findById(3);
System.out.println(book);
// 6.事务提交
sqlSession.commit();
sqlSession.close();
}
2.1.1 逐行解释
- DEBUG - Opening JDBC Connection 打开jdbc连接,从数据源中取得Connection对象
- INFO - {dataSource-1} inited 初始化数据源
- DEBUG - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@73d4cc9e] 将事务的自动提交设置为false
- DEBUG - ==> Preparing: SELECT * FROM book_tab WHERE book_id = ? PreparedStatment 读取SQL语句
- DEBUG - ==> Parameters: 3(Integer) 给?号注入值
- 影响行数
- 查询的数据
- DEBUG - Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@73d4cc9e] 将事务的自动提交设置为真
- DEBUG - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@73d4cc9e] 将连接对象Connection重新放入数据源连接池中
2.2 第二次测试
可以发现如果book的id不同,并没有发生不同的事
2.3 第三次测试
当book的id一样时,可以发现sql语句只执行了一次,就查询到两个Book对象的数据。证明了mybatis是存在缓存的。
2.4 一级缓存
通过上面三个测试,可以发现mybatis是有缓存的。
mybatis内置一个缓存,SqlSession对象- 一级缓存(运行速度块,空间小),内置的,用户不能手动关闭。
- 在sqlSession.close() ,已经关闭SqlSession对象,缓存也自然关闭了
- sqlSession.clearCache() , 则是清空缓存
2.5 二级缓存
二级缓存,客户选择实现,默认是关闭状态 ,针对SqlSessionFactory
2.5.1 设置二级缓存
2.5.2 二级缓存的效果
设置了二级缓存,即使关闭了SqlSession,它的缓存依旧存在,二级缓存的存储时间很长。
2.5.3 二级缓存需要注意的事
因为这里缓存了Book对象,所以对象需要序列化