executeupdate不执行_MyBatis#Executor执行体系(一)

首先来回顾一下JDBC的执行过程

  • 获取连接
  • 预编译SQL
  • 执行SQL
  • 读取结果

8c874d51cc74bd2edd4e0073d33b4d06.png

预编译SQL Statement

  • 提供了执行静态SQL的功能
String 
  • 批处理、设置加载行数

08aa749bcf90e2e46eabdd66776322c2.png
批处理:调用addBatch方法把SQL全部放在内存中后再全部发送给数据库(批处理传输)
数据库查询的数据返回比较大:假设查询1000条100M的数据,这时如果全部返回的话就需要全部放到内存中,这可能会导致内存的溢出。可以通过setFetchSize设置从数据库读取的时,读取多少行。(Oracle默认10行,MySQL不支持)可减少与数据库通信的次数。
@Test
    

单挑执行时间:

bfe6c9af675024ca97e886308c701be4.png

批量执行时间:

3a973347df5650f4de015271471272e2.png

从Diagram中可以看到,PreparedStatement继承Statement

59675ec1b1f621d60260dfd6c49c1908.png

PrepareStatement通过添加设置预编译参数来预防SQL注入

f1e1c6180483ef7b20bf38e11050c506.png

那么首先来看一下什么是SQL注入:

// sql注入测试

测试代码:

@Test

079471dd4143e7d914cefa92348e6408.png

如果此时想查询一个名字叫做:“小明 or 1=1”的用户

@Test

会将数据库中的所有数据都会被查出来

d639af38e3d215dcff6094df51997bdc.png

这就是SQL注入问题,那么之前说过了通过PrepareStatement可以防止SQL注入,是如何防治的呢?

通过转换符来防治SQL注入
//PreparedStatement防止 sql注入测试

测试代码:

@Test

92d82bacfbcae33e1ff97704d005d545.png
所有的转义操作是在数据库中执行的,并不是在应用程序中执行的

b17cfe4865edeff2aa3a42ffe9c2590e.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

MyBatis执行过程

SQLSession:提供基本的API操作,不能跨线程使用

3b4e7e7bf980c703c4d709c0f614bc6c.png

返回结果的区别:

fc4db3475c772d28efc3126a91631972.png
其中返回结果为void作用为刷新缓存的作用

参数讲解:

  • String:StatementID去找到SQL的配置和映射
  • Object:参数
  • ResultHandler:对结果集进行自定义
  • RowBounds:设置返回范围(分页)

门面模式:方便我们调用(重载)

63fdae7780ddf38f3ccb25dd37d49ca1.png

辅助API:提交、关闭会话

一个SqlSession只能被一个线程所调用(单线程,不保证线程安全)所以使用后要立马把SqlSession关闭。SqlSession只提供SQL会话,不去执行具体的请求,具体的请求交给Executor来处理

f305a5a951c6a58fde9f7aa933822159.png

Executor 提供的基本功能:查、改(没有增、删)、维护缓存、事务管理,不能跨线程使用

5b61df6ef99ac90c0abf844ee9d8ef3b.png

对于批处理刷新功能:最终去执行executeUpdate时就是执行flushstatement,批处理执行完之后一定要执行flushstatement(commit)才能把数据提交

真正处理数据完成功能的是StatementHandler(使用JDBC),Executor负责分配任务

StatementHandler就是JDBC中的Statement

eeeac4bc8836c268676dfe8bca66bbb8.png

JDBC和Executor进行对比:

fe650193221a2b273318da4e5a7f391a.png
  • Statement -> SimpleStatementHandler
  • PreparedStatement -> PreparedStatementHandler
  • CallableStatement -> CallableStatementHandler

比例关系:

a4f1c41bbe4c821a54abae6f3ee9eaa2.png
一个sql对应一个statemetHandler

Executor执行器体系

0005a0f4eabed7bae02d695d7022ab2e.png
public 

SimpleExecutor

// 简单执行器测试

执行两次查询操作发现:

ab58e4d947f4f2cdeb03a7cbce5f6b12.png

相同的SQL语句没有必要编译两次执行两次,我们想要的应该是编译一次执行两次。

ReuseExecutor

PreparedStatement:一次编译多次执行

public 

MyBatis中通过ReuseExecutor使用PreparedStatement,会帮我们把语句(Statement)进行缓存,一个SQL语句对应一个PrepareStatement

@Test

执行结果:

e4cc93659fa73cc40818c6d1f775f110.png

在Executor中真正执行操作的是StatementHandler

c8dc1349d357a8a1f1924408b95bb11e.png

通过Map实现一次编译多次执行

f6c8aaad20fd49604c234463dbc63b4d.png

BatchExecutor

批处理:只对修改有效,对查询无效

// 批处理执行器

执行结果:

a3f9e561238cfc65dc2161bc3257154c.png

ReuseExecutor VS BatchExecutor

ReuseExecutor 设置一次参数执行一次查询获取一次结果

BatchExecutor 一次性把参数发送给数据库执行修改获取结果

缓存维护和事务管理由BaseExecutor

98121d85a6a10e409c7adf3397232074.png

ff9ef8ac995ac6e38b8c29a2e1d355bd.png

BaseExecutor只对应一级缓存,对于二级缓存使用Caching Executor(装饰者模式)

149d71faf2dedc4cbfaac94879f2691b.png

delegate为了重写query和update添加新功能

@Test

60efb1774c05c888f01cf41f1897d773.png

开启二级缓存:

59261190bb39b25d4846f0b0afedf234.png

如果不提交的话:

8add24a83c6b41ede23c3c6d7fafd8e6.png

完整查询步骤:

6a1255381b86b1c3bfda8f8dab8396b0.png

Q:为什么调用selectList而不是select?

A:门面模式,方便我们调用,提供各种查询方法。

3474c0531186f488dbda9593979bbce4.png

我们只能控制Simple Executor、Reuse Executor、Batch Executor,至于Caching Executor我们是控制不了的

@Test

a21c864eeccf7d08b6d18fdf105c4fe7.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值