1、#{} 与 ${} 的区别?
(1)#{}是预编译处理,$ {}是字符串替换。(2)mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;mybatis在处理 $ { } 时,就是把 ${ } 替换成变量的值。(3)使用 #{} 可以有效的防止SQL注入,提高系统安全性。
2、Mybatis的实现原理?
先放一张图,让大家简单认识一下:
- 读取 MyBatis 配置文件:mybatis-config.xml 为 MyBatis 的全局配置文件,配置了 MyBatis 的运行环境等信息,例如数据库连接信息。
- 加载映射文件:映射文件即 SQL 映射文件,该文件中配置了操作数据库的 SQL 语句,需要在 MyBatis 配置文件 mybatis-config.xml 中加载。mybatis-config.xml 文件可以加载多个映射文件,每个文件对应数据库中的一张表。
- 构造会话工厂:通过 MyBatis 的环境等配置信息构建会话工厂 SqlSessionFactory。
- 创建会话对象:由会话工厂创建 SqlSession 对象,该对象中包含了执行 SQL 语句的所有方法,是一个既可以发送sql执行并返回结果的,也可以获取mapper的接口
- Executor 执行器:MyBatis 底层定义了一个 Executor 接口来操作数据库,它将根据 SqlSession 传递的参数动态地生成需要执行的 SQL 语句,同时负责查询缓存的维护。
- MappedStatement 对象:在 Executor 接口的执行方法中有一个 MappedStatement 类型的参数,该参数是对映射信息的封装,用于存储要映射的 SQL 语句的 id、参数等信息。
- 输入参数映射:输入参数类型可以是 Map、List 等集合类型,也可以是基本数据类型和 POJO 类型。输入参数映射过程类似于 JDBC 对 preparedStatement 对象设置参数的过程。
- 输出结果映射:输出结果类型可以是 Map、 List 等集合类型,也可以是基本数据类型和 POJO 类型。输出结果映射过程类似于 JDBC 对结果集的解析过程。
MyBatis基本构成
SqlSessionFactoryBuilder:
SqlSessionFactoryBuilder是利用XML或者Java编码获得资源来构建SqlSessionFactory的,通过它可以构建多个SessionFactory。 它的作用就是一个构建器,一旦我们构建了SqlSessionFactory,它的作用就已经完结,失去了存在的意义,这时我们就应该毫不犹豫的废弃它,将它回收。所以它的生命周期只存在于方法的局部,它的作用就是生成SqlSessionFactory对象。
SqlSessionFactory
作用:创建sqlSession,sqlSession是一个会话,相当于jdbc中的Connection对象每次访问数据库就要通过SqlSessionFactory创建sqlSession,所以SqlSessionFactory会在mybatis整个生命周期都会使用。如果多次创建同一个数据库的SqlSessionFactory,每次创建SqlSessionFactory会打开更多的数据库连接资源,连接资源会被耗尽,所以这个采用单例模式。一个数据库只对应一个SqlSessionFactory。
SqlSession
官方说法:sqlSession是一个外观模式,提供基本API:增删改查,还有辅助API,也就是提交、关闭会话
通俗说法:SqlSession是一个会话,相当于jdbc的一个connection对象,生命周期是在请求数据库处理事务的过程中,线程不安全的对象。
注意事项:
每次创建SqlSession都必须即时关闭,否则数据库连接池的活动资源少。SqlSession提供了增删改查,使用mapper接口,其中有映射器,映射器作为一个动态代理,进入到mapperMethod的方法就能简单找到SqlSession的增删改查。其实就是通过动态代理记录,让接口跑起来,使用命令模式,最后采用sqlSession的方法执行sql语句。
SqlSession的实现类
- 【DefaultSqlSession】是mybatis默认使用的实现类。这个类的线程是不安全的。所以每一个线程都要创建一个他自己有的sqlSession,所以不能把他设置成单例。
- 【SqlSessionManager】线程安全
- 【SqlSessionTemplate】SqlSessionTemplate是一个线程安全的类,当你运行一个sqlSessionTemplate时,会重新获取一个sqlSession,所有每一个方法都有独立的一个sqlSession,说明是线程安全的。
Executor执行器
1、SimpleExecutor
每执行一次 update 或 select,就开启一个 Statement 对象,用完立刻关闭 Statement 对象。
所以这种会特别浪费性能,不合适使用。
2、ReuseExecutor
可重用处理器,执行 update 或 select,以 sql 作为 key 查找 Statement 对象,存在就使用,不存在就创建,用完后,不关闭 Statement 对象,而是放置于 Map<String, Statement>内,供下一次使用。简言之,就是重复使用 Statement 对象。
3、BatchExecutor
执行 update(没有 select,JDBC 批处理不支持 select),将所有 sql 都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个 Statement 对象,每个 Statement 对象都是 addBatch()完毕后,等待逐一执行 executeBatch()批处理。与 JDBC 批处理相同。
总结:Executor的这些特点,都严格限制在SqlSession生命周期范围内
Mapper
Mapper是一个接口,没有任何实现类,作用是发送SQL返回需要的结果,或者执行SQL从而修改数据库的数据,因此应该在一个SqlSession事务方法之内,是方法基本的