首先来回顾一下JDBC的执行过程
- 获取连接
- 预编译SQL
- 执行SQL
- 读取结果
![8c874d51cc74bd2edd4e0073d33b4d06.png](https://i-blog.csdnimg.cn/blog_migrate/a08d1cbd9b0fc02e1c8440b149c6bae8.png)
预编译SQL Statement
- 提供了执行静态SQL的功能
String
- 批处理、设置加载行数
![08aa749bcf90e2e46eabdd66776322c2.png](https://i-blog.csdnimg.cn/blog_migrate/ac3d22d26cc687be6c1b2afc2f0887cd.png)
批处理:调用addBatch方法把SQL全部放在内存中后再全部发送给数据库(批处理传输)
数据库查询的数据返回比较大:假设查询1000条100M的数据,这时如果全部返回的话就需要全部放到内存中,这可能会导致内存的溢出。可以通过setFetchSize设置从数据库读取的时,读取多少行。(Oracle默认10行,MySQL不支持)可减少与数据库通信的次数。
@Test
单挑执行时间:
![bfe6c9af675024ca97e886308c701be4.png](https://i-blog.csdnimg.cn/blog_migrate/11b584ad29e61be358e743ee82bae919.png)
批量执行时间:
![3a973347df5650f4de015271471272e2.png](https://i-blog.csdnimg.cn/blog_migrate/fe7679554beff2942b296b7fba19085a.png)
从Diagram中可以看到,PreparedStatement继承Statement
![59675ec1b1f621d60260dfd6c49c1908.png](https://i-blog.csdnimg.cn/blog_migrate/c88052788a406fde926dd0922b55a950.png)
PrepareStatement通过添加设置预编译参数来预防SQL注入
![f1e1c6180483ef7b20bf38e11050c506.png](https://i-blog.csdnimg.cn/blog_migrate/beaddd5fa402ac8a1073dd692d4647f4.png)
那么首先来看一下什么是SQL注入:
// sql注入测试
测试代码:
@Test
![079471dd4143e7d914cefa92348e6408.png](https://i-blog.csdnimg.cn/blog_migrate/4d63e41db79579f988815fa00668b136.png)
如果此时想查询一个名字叫做:“小明 or 1=1”的用户
@Test
会将数据库中的所有数据都会被查出来
![d639af38e3d215dcff6094df51997bdc.png](https://i-blog.csdnimg.cn/blog_migrate/39c00b6321e1d93227535303112e4039.png)
这就是SQL注入问题,那么之前说过了通过PrepareStatement可以防止SQL注入,是如何防治的呢?
通过转换符来防治SQL注入
//PreparedStatement防止 sql注入测试
测试代码:
@Test
![92d82bacfbcae33e1ff97704d005d545.png](https://i-blog.csdnimg.cn/blog_migrate/739d937f1e582a204696af72917c4fba.png)
所有的转义操作是在数据库中执行的,并不是在应用程序中执行的
![b17cfe4865edeff2aa3a42ffe9c2590e.png](https://i-blog.csdnimg.cn/blog_migrate/cafc8a77b84611e85fb4f28716e31e76.png)
- Statement发出的是一条条的SQL语句
例如:
SELECT * FROM users WHERE `name`='小明';
SELECT * FROM users WHERE `name`='小红';
SELECT * FROM users WHERE `name`='小强';
- PreparedStatement发出的是一条SQL和参数
例如:
SELECT * FROM users WHERE `name`=?;
小明
小红
小强
所以说PreparedStatement发送的信息更小一些,性能更优一些
CallableStatement继承PrepareStatement
![ee4111bb91f6e96e37431e2d7256f282.png](https://i-blog.csdnimg.cn/blog_migrate/0c56574e45b11564e213d54da260380c.png)
MyBatis执行过程
SQLSession:提供基本的API操作,不能跨线程使用
![3b4e7e7bf980c703c4d709c0f614bc6c.png](https://i-blog.csdnimg.cn/blog_migrate/d43b2a762dc7803fe09ce8bd9245f79e.png)
返回结果的区别:
![fc4db3475c772d28efc3126a91631972.png](https://i-blog.csdnimg.cn/blog_migrate/4c52e0bc6c12519cd40bd3318c69eea6.jpeg)
其中返回结果为void作用为刷新缓存的作用
参数讲解:
- String:StatementID去找到SQL的配置和映射
- Object:参数
- ResultHandler:对结果集进行自定义
- RowBounds:设置返回范围(分页)
门面模式:方便我们调用(重载)
![63fdae7780ddf38f3ccb25dd37d49ca1.png](https://i-blog.csdnimg.cn/blog_migrate/2eaca1ab15cba49d039f7fc049c440c3.png)
辅助API:提交、关闭会话
一个SqlSession只能被一个线程所调用(单线程,不保证线程安全)所以使用后要立马把SqlSession关闭。SqlSession只提供SQL会话,不去执行具体的请求,具体的请求交给Executor来处理
![f305a5a951c6a58fde9f7aa933822159.png](https://i-blog.csdnimg.cn/blog_migrate/6cfa8e95904c125195b2b19693acf9cc.png)
Executor 提供的基本功能:查、改(没有增、删)、维护缓存、事务管理,不能跨线程使用
![5b61df6ef99ac90c0abf844ee9d8ef3b.png](https://i-blog.csdnimg.cn/blog_migrate/ecd9490baaa25f3e99eff39811eb0d2d.jpeg)
对于批处理刷新功能:最终去执行executeUpdate时就是执行flushstatement,批处理执行完之后一定要执行flushstatement(commit)才能把数据提交
真正处理数据完成功能的是StatementHandler(使用JDBC),Executor负责分配任务
StatementHandler就是JDBC中的Statement
![eeeac4bc8836c268676dfe8bca66bbb8.png](https://i-blog.csdnimg.cn/blog_migrate/c2c011a0791ad2fa12888fc0179ce652.jpeg)
JDBC和Executor进行对比:
![fe650193221a2b273318da4e5a7f391a.png](https://i-blog.csdnimg.cn/blog_migrate/15319409f6180a7f38863257fec3f425.png)
- Statement -> SimpleStatementHandler
- PreparedStatement -> PreparedStatementHandler
- CallableStatement -> CallableStatementHandler
比例关系:
![a4f1c41bbe4c821a54abae6f3ee9eaa2.png](https://i-blog.csdnimg.cn/blog_migrate/0063a0912344c9d1ec13c9dd37fd6b43.jpeg)
一个sql对应一个statemetHandler
Executor执行器体系
![0005a0f4eabed7bae02d695d7022ab2e.png](https://i-blog.csdnimg.cn/blog_migrate/c736929044d1fa7634192064830b699e.png)
public
SimpleExecutor
// 简单执行器测试
执行两次查询操作发现:
![ab58e4d947f4f2cdeb03a7cbce5f6b12.png](https://i-blog.csdnimg.cn/blog_migrate/c36d6cb98f8c98e4a86441c6825aa15f.jpeg)
相同的SQL语句没有必要编译两次执行两次,我们想要的应该是编译一次执行两次。
ReuseExecutor
PreparedStatement:一次编译多次执行
public
MyBatis中通过ReuseExecutor使用PreparedStatement,会帮我们把语句(Statement)进行缓存,一个SQL语句对应一个PrepareStatement
@Test
执行结果:
![e4cc93659fa73cc40818c6d1f775f110.png](https://i-blog.csdnimg.cn/blog_migrate/511dfc9858eb8683056c8bba53abfd54.png)
在Executor中真正执行操作的是StatementHandler
![c8dc1349d357a8a1f1924408b95bb11e.png](https://i-blog.csdnimg.cn/blog_migrate/7733c76cd45cc148039d21446526279f.png)
通过Map实现一次编译多次执行
![f6c8aaad20fd49604c234463dbc63b4d.png](https://i-blog.csdnimg.cn/blog_migrate/9c255e6aad01a342395dc9a70e31d7ee.png)
BatchExecutor
批处理:只对修改有效,对查询无效
// 批处理执行器
执行结果:
![a3f9e561238cfc65dc2161bc3257154c.png](https://i-blog.csdnimg.cn/blog_migrate/95e60bc53f2dc630c95a5e032c5a8160.png)
ReuseExecutor VS BatchExecutor
ReuseExecutor 设置一次参数执行一次查询获取一次结果
BatchExecutor 一次性把参数发送给数据库执行修改获取结果
缓存维护和事务管理由BaseExecutor
![98121d85a6a10e409c7adf3397232074.png](https://i-blog.csdnimg.cn/blog_migrate/59de13d173bd359806f9892ce2699e08.png)
![ff9ef8ac995ac6e38b8c29a2e1d355bd.png](https://i-blog.csdnimg.cn/blog_migrate/91a9f3329f0edfdc2f46978388225d00.png)
BaseExecutor只对应一级缓存,对于二级缓存使用Caching Executor(装饰者模式)
![149d71faf2dedc4cbfaac94879f2691b.png](https://i-blog.csdnimg.cn/blog_migrate/0ef525b3b05049f3a52adc694f0e99e0.jpeg)
delegate为了重写query和update添加新功能
@Test
![60efb1774c05c888f01cf41f1897d773.png](https://i-blog.csdnimg.cn/blog_migrate/d20dee00b5fabd5a59f927b158d5c992.png)
开启二级缓存:
![59261190bb39b25d4846f0b0afedf234.png](https://i-blog.csdnimg.cn/blog_migrate/0f4737bfa33cb5fd12fd29b37ed83451.png)
如果不提交的话:
![8add24a83c6b41ede23c3c6d7fafd8e6.png](https://i-blog.csdnimg.cn/blog_migrate/18950b6e0187dc4d498c69a61fb70f55.png)
完整查询步骤:
![6a1255381b86b1c3bfda8f8dab8396b0.png](https://i-blog.csdnimg.cn/blog_migrate/f2637aa9234c1e1b96b319101fad5360.png)
Q:为什么调用selectList而不是select?
A:门面模式,方便我们调用,提供各种查询方法。
![3474c0531186f488dbda9593979bbce4.png](https://i-blog.csdnimg.cn/blog_migrate/519ff81686f79c6a132a59eccfd00243.jpeg)
我们只能控制Simple Executor、Reuse Executor、Batch Executor,至于Caching Executor我们是控制不了的
@Test
![a21c864eeccf7d08b6d18fdf105c4fe7.png](https://i-blog.csdnimg.cn/blog_migrate/68311de00c8746d1848368d255ae6ddd.jpeg)