1.Mybatis是一个半ORM(对象关系映射)框架,它内部封装了JDBC,开发时只需要关注SQL语句本身,不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程;
2.MyBatis 可以使用 XML 或注解来配置和映射原生信息,将 POJO映射成数据库中的记录,避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集;
3.通过xml 文件或注解的方式将要执行的各种 statement 配置起来,并通过java对象和 statement中MySQL的动态参数进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射为java对象并返回。
1.创建SqlSessionFactory
2.通过SqlSessionFactory创建SqlSession
3.通过SqlSession执行数据库操作
4.调用SqlSession的commit()方法提交事务
5.调用SqlSession的close()方法关闭会话
1.基于SQL语句编程,相对灵活,接触sql与程序代码的藕合,便于统一管理,支持写动态sql语句并可重复使用;
2.减少代码量,消除了冗余代码;
3.数据库兼容能够与Spring集成;
4.提供映射标签支持字段关系映射;
1.SQL语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写SQL的功底有一定要求;
2.SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。
1.传入的参数在SQL中显示不同
#传入的参数在SQL中相当占位符,#方式能够很大程度防止sql注入;而$传入的参数在SQL中相当字符串,$方式无法防止Sql注入.
--------------------------------------------
例:使用以下SQL
1)select id,name,age from student where name=#{name};
2)select id,name,age from student where name =${name}:
当我们传递的参数name为 "‘zs ' or 1=1" 时,上述 sql分别会解析为:
select id,name,age from student where id ="‘zs' or 1=1"
select id,name,age from student where id =‘zs' or 1=1
这样第二条sql语句的会查出所有学生的信息,这是非常不安全的,有sql注入的风险。所以#可以防止SQL注入的风险(语句的拼接);但$无法防止Sql注入。
------------------------------------------------------
2.$方式一般用于传入数据库对象,例如传入表名。
3.大多数情况下还是经常使用#,但有些情况下必须使用$,例:MyBatis排序时使用order by 动态参数时需要注意,用$而不是#。
1.一级缓存 Mybatis的一级缓存是指SQLSession,一级缓存的作用域是SQlSession, Mabits默认开启一级缓存。 在同一个SqlSession中,执行相同的SQL查询时;第一次会去查询数据库,并写在缓存中,第二次会直接从缓存中取。 当执行SQL时候两次查询中间发生了增删改的操作,则SQLSession的缓存会被清空。 每次查询会先去缓存中找,如果找不到,再去数据库查询,然后把结果写到缓存中。 Mybatis的内部缓存使用一个HashMap,key为hashcode+statementId+sql语句。Value为查询出来的结果集映射成的java对象。 SqlSession执行insert、update、delete等操作commit后会清空该SQLSession缓存。
2.二级缓存 二级缓存是mapper级别的,Mybatis默认是没有开启二级缓存的。 第一次调用mapper下的SQL去查询用户的信息,查询到的信息会存放代该mapper对应的二级缓存区域。 第二次调用namespace下的mapper映射文件中,相同的sql去查询用户信息,会去对应的二级缓存内取结果。 如果调用相同namespace下的mapepr映射文件中增删改sql,并执行了commit操作,此时会情况该
Mybatis 使用 RowBounds 对象进行分页,它是针对 ResultSet 结果集执行的内 存分页,而非物理分页。可以在 sql 内直接书写带有物理分页的参数来完成物理分 页功能,也可以使用分页插件来完成物理分页。 分页插件的基本原理是使用 Mybatis 提供的插件接口,实现自定义插件,在插件 的拦截方法内拦截待执行的 sql,然后重写 sql,根据 dialect 方言,添加对应的物 理分页语句和物理分页参数。举例:select * from student,拦截sql后重写为:select t.* from (select * from student)t limit 0,10
Mybatis使用JDK的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这4种接口对象的方法时,就会进入拦截方法,具体就是InvocationHandler的invoke()方法。
1)在MyBatis配置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false。MyBatis仅支持association关联对象和collection关联集合对象的延迟加载,association指的就是一对一,collection指的就是一对多查询。
2)它的原理是,使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用a.getB().getName(),拦截器invoke()方法发现a.getB()是null值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。
1.Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句。
2.Mybatis直接编写原生态sql,可以严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,因为这类软件需求变化频繁,一但需求变化要求迅速输出成果。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件,则需要自定义多套sql映射文件,工作量大。
3.Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件,如果用hibernate开发可以节省很多代码,提高效率。
1)在 sql 里面变量命名有原来的#变量# 变成了#{变量}
2)原来的$变量$变成了${变量}
3)原来在 sql 节点里面的 class 都换名字交 type
4)原来的 queryForObject queryForList 变成了 selectOne selectList
5)原来的别名设置在映射文件里面放在了核心配置文件里
1. IBatis 里面的核心处理类交 SqlMapClient,MyBatis 里面的核心处理类叫做 SqlSession
1.Mapper接口方法名和mapper.xml中定义的每个sql的id相同;
2.Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同;
3.Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同;
4.Mapper.xml文件中的namespace即是mapper接口的类路径;
第一种:通过定义select语句中字段名的别名,让字段明的别名和实体类的属性名一致
第二种:通过ResutlMap来映射字段名和实体类属性名的一一对应的关系。
<select id="selectlike">
select * from foo where bar like #{value}
</select>
第 2 种:在 sql 语句中拼接通配符,会引起 sql 注入
<select id="selectlike">
select * from foo where bar like "%"#{value}"%"
</select>
1)MyBatis动态sql可以让我们在Xml映射文件内,以标签的形式编写动态sql,完成逻辑判断和动态拼接sql的功能,MyBatis提供了9种动态sql标签 trim | where | set | foreach | if | choose | when | otherwise | bind。
2)其执行原理为,使用OGNL从sql参数对象中计算表达式的值,根据表达式的值动态拼接sql,以此来完成动态sql的功能。
Dao接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Dao接口生成代理proxy对象,代理对象proxy会拦 截接口方法,转而执行MappedStatement所代表的sql,然后将sql执行结果返回。
Dao接口里的方法,是不能重载的,因为是全限名+方法名的保存和寻找策略。
MyBatis实现一对一、一对多关联查询一般有两种方式:
方式一:sqlMapper配置文件
一对一:在resultMap标签中使用 association 标签
一对多:在resultMap 标签中使用collection 标签
方式二:注解
一对一:在@Results 注解中的@Result注解中使用@One注解
一对多:在@Results 注解中的@Result 注解中使用@Many注解
useGeneratedKeys为true,持自动生成主键,keyProperty和keyColumn分别代表数据库记录主键字段和java对象成员属性名
dao层 修饰符 为 void,不需要返回任何
<insert id="insertEntity" parameterType="**" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
//dao层 修饰符 为 void,不需要返回任何
void batchInsert(List<TAlarmChannelEntity> list);
<insert id="batchInsert" parameterType="java.util.List" useGeneratedKeys="true" keyProperty="id" >
INSERT INTO t_alarm_channel
(channel, silent_cycle, aggregation_mode,threshold,effective_start_time,effective_end_time,inform_obj,selected,create_time)
VALUES
<foreach collection="list" index="index" item="bo" separator=",">
(
#{bo.channel}, #{bo.silentCycle}, #{bo.aggregationMode},#{bo.threshold},#{bo.effectiveStartTime},#{bo.effectiveEndTime},#{bo.informObj},#{bo.selected},now()
)
</foreach>
</insert>
ResultMap是⾃⼰指定返回值与对象及与对象内部属性名和数据库列名的绑定
ResultType是直接返回值与别名库当中的java对象的映射
1,第一种:
public UserselectUser(String name,String area); 对应的 xml,#{0}代表接收的是 dao 层中的第一个参数,#{1}代表 dao 层中第二 参数,更多参数一致往后加即可。
<select id="selectUser"resultMap="BaseResultMap">
select * from user_user_t where user_name = #{0} and user_area=#{1}
</select>
2,第二种:使用@param注解:
public interface UserMapper {
User selectUser(@param("username") String username,
@param("hashedpassword") sString hashedpassword);
}
然后,就可以在 xml 像下面这样使用(推荐封装为一个 map,作为单个参数传递给mapper):
<select id="selectuser" resulttype="user">
select id, username, hashedpassword
from some_table
where username = #{username} and hashedpassword = #{hashedpassword}
</select>
3、第三种:多个参数封装成 map
try {
//映射文件的命名空间.SQL 片段的 ID,就可以调用对应的映射文件中的SQL
//由于我们的参数超过了两个,而方法中只有一个 Object 参数收集,因此我们使用 Map 集合来装载我们的参数
Map < String, Object > map = new HashMap();
map.put("start", start);
map.put("end", end);
return sqlSession.selectList("StudentID.pagination", map);
} catch (Exception e) {
e.printStackTrace();
sqlSession.rollback();
throw e;
} finally {
MybatisUtil.closeSqlSession();
}
1.读取 MyBatis 配置文件:mybatis-config.xml 为 MyBatis 的全局配置文件,配置了 MyBatis 的运行环境等信息,例如数据库连接信息。
2.加载映射文件。映射文件即 SQL 映射文件,该文件中配置了操作数据库的 SQL 语句,需要在 MyBatis 配置文件 mybatis-config.xml 中加载。mybatis-config.xml 文件可以加载多个映射文件,每个文件对应数据库中的一张表。
3.构造会话工厂:通过 MyBatis 的环境等配置信息构建会话工厂 SqlSessionFactory。
4.创建会话对象:由会话工厂创建 SqlSession 对象,该对象中包含了执行 SQL 语句的所有方法。
5.Executor 执行器:MyBatis 底层定义了一个 Executor 接口来操作数据库,它将根据 SqlSession 传递的参数动态地生成需要执行的 SQL 语句,同时负责查询缓存的维护。
6.MappedStatement 对象:在 Executor 接口的执行方法中有一个 MappedStatement 类型的参数,该参数是对映射信息的封装,用于存储要映射的 SQL 语句的 id、参数等信息。
7.输入参数映射:输入参数类型可以是 Map、List 等集合类型,也可以是基本数据类型和 POJO 类型。输入参数映射过程类似于 JDBC 对 preparedStatement 对象设置参数的过程。
8.输出结果映射:输出结果类型可以是 Map、 List 等集合类型,也可以是基本数据类型和 POJO 类型。输出结果映射过程类似于 JDBC 对结果集的解析过程。
1)Configuration:用于描述 MyBatis 主配置文件信息,MyBatis 框架在启动时会加载主配置文件,将配置信息转换为 Configuration 对象。
2)SqlSession:面向用户的 API,是 MyBatis 与数据库交互的接口。
3)Executor:SQL 执行器,用于和数据库交互。SqlSession 可以理解为 Executor 组件的外观(外观模式),真正执行 SQL 的是 Executor 组件。
4)MappedStatement:用于描述 SQL 配置信息,MyBatis 框架启动时,XML 文件或者注解配置的 SQL信息会被转换为 MappedStatement 对象注册到 Configuration 组件中。
5)StatementHandler:封装了对 JDBC 中 Statement 对象的操作,包括为 Statement 参数占位符设置值,通过 Statement 对象执行 SQL语句。
6)TypeHandler:类型处理器,用于 Java 类型与 JDBC 类型之间的转换。
7)ParameterHandler:用于处理 SQL 中的参数占位符,为参数占位符设置值。
8)ResultSetHandler:封装了对 ResultSet 对象的处理逻辑,将结果集转换为 Java 实体对象。
Mybatis有三种基本的Executor执行器,SimpleExecutor、ReuseExecutor、BatchExecutor。
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生命周期范围内。
⼀级缓存使⽤者可以随时使⽤或者销毁缓存,从SqlSession对象打开时缓存就已经存在。当关闭SqlSession对象缓存就失效。当与spring整合的时候,直接跳过SqlSession对象,⽆法直接操作到SqlSession对象,spring在操作SqlSession的时候,不知道⽤户什么时候关闭,所以每调⽤完⼀个dao⽅法就关闭了,所以导致⼀级缓存失效。
如果开启了事务,⼀级缓存就会⽣效,因为开启了事务,执⾏完dao就不会销毁,因为⼀旦销毁,事务就没有了,你开启了事务,Spring就知道你什么时候需要结束