Mybatis是一个半自动的orm(sql语法模板);
Mybatis工作原理:先封装SQL,接着调用JDBC操作数据库,最后把数据库返回的表结果封装成Java类;
Mapper执行:通过动态代理去执行SQL。
————————————————————
JDBC:
通过 DriverManager(需要Java Spi 机制加载驱动) 或者DataSource 获得一个Conection连接之后 再通过Statement SQL语句的执行器去执行语句 再获得一个ResultSet
Connection:
一个Connection对象表示通过JDBC驱动与数据源建立的连接;
Connection对象表示客户端会话,因此它需要一些相关的状态信息,例如用户id、一组SQL语句和会话中使用的结果集以及事务隔离级别等信息;
Connection的获取可以从两个方面获取:
1、 JDBC API中提供的DriverManager类获取:
Connection connection = DriverManager.getConnection(
"jdbc:mysql://127.0.0.1:3306/data?user=root&password=123456");
2、 DataSource接口的实现类获取
DataSource dataSource = new UnpooledDataSource(
"com.mysql.cj.jdbc.Driver",
"jdbc:mysql://127.0.0.1:3306/data?user=root&password=123456&AllowPublicKeyRetrieval=true",
"root","qwer1234");
————————————————————
Statement
Statement 不支持输入参数,字符串拼接方式创建,有sql注入的风险;
PreparedStatement:增加了设置SQL参数的方法,可以把参数有?代替,preparedStatement承接出来;
CallableStatement:增加了调用存储过程以及检索存储过程调用结果的方法;(不常见)
不同Statement执行的方式
Connection connection = DriverManager.getConnection("");
String sql = "SELECT * FROM admin WHERE username = ? AND password = ?";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1,"username");
preparedStatement.setString(2,"password");
ResultSet resultSet = preparedStatement.executeQuery();
String sql2 = "SELECT * FROM admin WHERE username = 'username' AND password = 'password'";
Statement statement2 = connection.createStatement();
ResultSet resultSet2 = statement.executeQuery(sql);
可扩展组件:
1、Executor:是MyBatis的SQL执行器,MyBatis中对数据库所有的增删改查操作都是由Executor组件完成的。
2、StatementHandler组件:封装了对JDBC Statement的操作,例如设置Statement对象的fetchSize属性、设置查询超时时间、调用JDBC Statement与数据库交互等。
- SimpleStatementHandler :封装了JDBC的 Statement 对象
- PreparedStatementHandler:封装了JDBC的 PreparedStatement 对象 (可添加sql参数)
- CallableStatementHandler:封装了JDBC的 CallableStatement 对象
3、ParameterHandler组件:当MyBatis框架使用的Statement类型为CallableStatement和PreparedStatement时,ParameterHandler用于为Statement对象参数占位符设置值。
4、ResultSetHandler:封装了对JDBC中的ResultSet对象操作,当执行SQL类型为SELECT语句时,ResultSetHandler用于将查询结果转换成Java对象。
自定义转化处理器:
TypeHandler:处理JDBC类型与Java类型之间的转换
描述配置信息:
Configuration:用于描述MyBatis的主配置信息,其他组件需要获取配置信息时,直接通过Configuration对象获取。除此之外,MyBatis在应用启动时,将Mapper配置信息、类型别名、TypeHandler等注册到Configuration组件中,其他组件需要这些信息时,也可以从Configuration对象中获取。
MappedStatement:用于描述Mapper中的SQL配置信息,是对Mapper XML配置文件中<select|update|delete|insert>等标签或者@Select/@Update等注解配置信息的封装。
————————————————————
Mybatis描述文件的属性:
type | name | desc |
通用 | id | 在命名空间中唯一的标识符,可以被用来引用这条配置信息 |
parameterType | 用于指定这条语句的参数类的完全限定名或别名 | |
statementType | 参数可选值为STATEMENT、PREPARED或CALLABLE,这会让MyBatis分别使用Statement、PreparedStatement或CallableStatement与数据库交互,默认值为PREPARED。 | |
flushCache | 用于控制是否刷新缓存。如果将其设置为 true,则任何时候只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值为false。 | |
timeout | 驱动程序等待数据库返回请求结果的秒数,超时将会抛出异常。 | |
databaseId | (databaseIdProvider:根据不同数据库执行不同的sql语句) 如果配置了 databaseIdProvider,MyBatis会加载所有不带databaseId或匹配当前 databaseId 的语句 | |
selelct | resultType | 从这条语句中返回的期望类型的类的完全限定名或别名。注意,如果返回结果是集合类型,则resultType属性应该指定集合中可以包含的类型,而不是集合本身。 |
resultMap | 用于引用通过<resultMap>标签配置的实体属性与数据库字段之间建立的结果集的映射(注意:resultMap和resultType属性不能同时使用) | |
resultSetType | 参数可选值为FORWARD_ONLY、SCROLL_SENSITIVE或SCROLL_INSENSITIVE,用于设置ResultSet对象的特征 | |
useCache | 是否使用二级缓存。如果将其设置为 true,则会导致本条语句的结果被缓存在MyBatis的二级缓存中,对应<select>标签,该属性的默认值为true | |
fetchSize | 用于设置JDBC中 Statement对象的fetchSize属性,该属性用于指定SQL执行后返回的最大行数 | |
insert update | useGeneratedKeys | Statement对象的getGeneratedKeys()方法来取出由数据库内部生成的键值,例如MySQL自增主键。 |
KeyProperty | 用于将数据库自增主键或者<insert>标签中<selectKey>标签返回的值填充到实体的属性中,如果有多个属性,则使用逗号分隔。 |
————————————————————
#{}与${}参数占位符区别:
● 使用#{}参数占位符时,占位符内容会被替换成“?”,然后通过PreparedStatement对象的setXXX()方法为参数占位符设置值;而${}参数占位符内容会被直接替换为参数值。
● 使用#{}可以有效的防止SQL注入,提高系统安全性。当#{}参数占位符无法满足需求时,(排序、分页等)才考虑使用${}参数占位符。
(原因在于:预编译机制。预编译完成之后,SQL的结构已经固定,即便用户输入非法参数,也不会对SQL的结构产生影响,从而避免了潜在的安全风险。预编译是提前对SQL语句进行预编译,而其后注入的参数将不会再进行SQL编译。我们知道,SQL注入是发生在编译的过程中,因为恶意注入了某些特殊字符,最后被编译成了恶意的执行操作。而预编译机制则可以很好的防止SQL注入。)
————————————————————
Mapper
MyBatis中Mapper的配置分为两部分: Mapper接口和Mapper SQL配置。
MyBatis通过动态代理的方式创建Mapper接口的代理对象,MapperProxy类中定义了Mapper方法执行时的拦截逻辑,通过MapperProxyFactory创建代理实例,MyBatis启动时,会将MapperProxyFactory注册到Configuration对象中。另外,MyBatis通过MappedStatement类描述Mapper SQL配置信息,框架启动时,会解析Mapper SQL配置,将所有的MappedStatement对象注册到Configuration对象中。
通过Mapper代理对象调用Mapper接口中定义的方法时,会执行MapperProxy类中的拦截逻辑,将Mapper方法的调用转换为调用SqlSession提供的API方法。在SqlSession的API方法中通过Mapper的Id找到对应的MappedStatement对象,获取对应的SQL信息,通过StatementHandler操作JDBC的Statement对象完成与数据库的交互,然后通过ResultSetHandler处理结果集,将结果返回给调用者。
————————————————————
几种扩展的执行顺序:
Executor > ParameterHandler > StatementHandler Init > TypeHandler getResult Before > ResultSetHandler > StatementHandler Before > StatementHandler After > Executor
Executor ------> Start sql:[select * from `order` where sub_size = ? and amount = ?]
ParameterHandler ------> select * from `order` where sub_size = ** NOT SPECIFIED ** and amount = ** NOT SPECIFIED **
StatementHandler Init ------> query
TypeHandler getResult Before ------> {}
ResultSetHandler ------> [{"amount":333,"data":"{}","gmtCreate":1639716832000,"id":2,"jsonData":{},"subSize":333}]
StatementHandler Before ------> [{"amount":333,"data":"{}","gmtCreate":1639716832000,"id":2,"jsonData":{},"subSize":333}]
StatementHandler After ------> [{"amount":333,"data":"{\"StatementHandler\":\"Live\"}","gmtCreate":1639716832000,"id":2,"jsonData":{"StatementHandler":"Live"},"subSize":333}]
Executor ------> END [{"amount":333,"data":"{\"StatementHandler\":\"Live\"}","gmtCreate":1639716832000,"id":2,"jsonData":{"StatementHandler":"Live"},"subSize":333}]
————————————————————
MyBatis缓存:
一级缓存:
● 一级缓存默认是开启的,而且不能关闭。
● 一级缓存级别:参数 localCacheScope
SESSION:当指定localCacheScope参数值为SESSION时,缓存对整个SqlSession有效,只有执行DML语句(更新语句)时,缓存才会被清除
STATEMENT:当localCacheScope值为STATEMENT时,缓存仅对当前执行的语句有效,当语句执行完毕后,缓存就会被清空。
二级缓存:
● 默认二级缓存关闭
● 作用域为 Namespaces(xml文件)
● 当Namespaces内执行查询操作时,查询结果会缓存到二级缓存中,执行更新操作后,二级缓存会被清空。
第三方缓存:
● 支持使用第三方作为缓存
————————————————————
Mapper的生命周期
Mapper配置文件的读取和装载
Mapper代理的执行
——————————————————————————————————————
笔记内容来源:B站“小河神”