一.MyBatis是什么?
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。MyBatis是一个 半自动化的ORM框架(Object Relational Mapping对象关系映射--解决面向对象和数据库发展不一致的问题)
①根据MyBatis官方的定义,MyBatis是支持定制化SQL语句,存储过程,高级映射的持久层框架.
②MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集的过程.
③MyBatis可以对配置和原生Map使用简单的XML或注解,将接口和Java的实体类映射成数据库的对应的记录.
二.MyBatis的使用流程总结
1.导入Jar包
asm-3.3.1.jar (java文件解析包,spring需要用到这个包)
cglib-2.2.2.jar(动态代理包,MyBatis通过动态代理,不需要编写Mapper接口的实现类)
commons-loggin-1.1.1.jar (日志包,spring需要用到这个包)
javassist-3.17.1-GA.jar (字节码解析助手包,处理.class文件)
log4j-1.2.17.jar、logj-api-2.0-rc1.jar、log4j-core-2.0-rc1.jar(这三个包都是log4j日志包)
mybatis-3.2.7.jar(mybatis核心包)
slf4j-api-1.7.5.jar(日志包)
slf4j-log4j12-1.7.5.jar(日志包)
2.构建实体类pojo包下的实体类构建
3.创建和配置mybatis.xml文件
①定义DTD文档约束(使用一系列合法的元素来定义文档结构)
<!--DTD是提高书写代码的速度,提供了快捷提示 -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
②配置configuration标签(根标签)
③配置其子标签,各子标签的作用如下
<!-- 配置 -->
<configuration>
<!-- 配置属性文件路径 -->
<properties resource="config.properties">
</properties>
<!-- 开启log4j的 -->
<settings >
<setting name="logImpl" value="LOG4J"/>
<setting name="cacheEnabled" value="true"/>
</settings>
<!-- 设置实体类别名 -->
<typeAliases>
<!-- 别名 -->
<!--<typeAlias type="com.bjsxt.pojo.Flower" alias="a"/> -->
<!-- 声明包 resultType值为类名就行 (不区分大小写)-->
<package name="com.bjsxt.pojo"></package>
</typeAliases>
<!-- 配置数据库 default属性表示要使用哪个数据库环境,值为environment 标签的id-->
<environments default="mysql">
<environment id="mysql">
<!-- 配置数据库的事务管理 -->
<transactionManager type="JDBC">
<!-- type(JDBC|MANAGED) -->
<!-- JDBC表示使用原生的事务管理器 -->
<!-- MANAGED表示将事务管理交给容器管理,比如spring -->
</transactionManager>
<!-- 配置具体数据库参数 -->
<dataSource type="POOLED">
<!-- type为POOLED表示开启数据库连接池 -->
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
<property name="driver" value="${driver}"/>
</dataSource>
</environment>
</environments>
<!-- 配置mapper文件 -->
<mappers>
<!-- resource mapper文件的路径,便于同一加载解析 -->
引用url地址
<mapper url="file:///e:/..../.../mybatis.xml" />
resource 切记:"/"的目录
<mapper resource="com/bjsxt/mapper/FlowerDMLMapper.xml" />
<package name="com.bjsxt.mapper"/>
</mappers>
</configuration>
4.创建和配置mapper.xml标签
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="包名.接口的名称">
<!-- id: 方法名称 resultType:返回值类型 如果返回的是一个对象,就写对象的实体即可 如果返回的是一个集合。书写集合的泛型的类型即可 parameterType:参数的类型 -->
<!--如果configuration中配置了typeAlias写别名即可,如果配置了package只写类名即可,不区分大小写-->
<select id="selectAll" resultType="com.bjsxt.pojo.Flower"> select * from flower </select>
</mapper>
5.使用SqlSession的对象完成数据库操作
①获取读取mybatis.xml文件,获得配置文件输入流对象
InputStream is = Resources.getResourceAsStream("mybatis.xml");
②获取SqlSessionFactory工厂对象(通过实例化SqlSessionFactoryBuilder调用Builder方法,传入配置文件输入流对象,获取)
SqlSessionFactroy factory = new SqlSessionFactroyBuilder().build(is);
③获取SqlSession对象
SqlSession sqlSession = factory.openSession();
④使用sqlSession对象完成对数据库的操作
insert/update/delete
-----select的方法有很多----------------
MyBatis最初提供的API的方法有
selectOne("namespace+statementId",parameter)
selectList("namespace+statementId",parameter)
selectMap("namespace+statementId",parameter,key) 需要指定key为数据库的哪一个字段
⑤commit或者rollback,最后close关闭SqlSession
6.配置setting开启log4j的支持
MyBatis使用日志的最大的作用:
①就是为了方法的输出后台执行的sql语句和参数传递的变化过程,方便开发人员的调试
②可以把指定的日志信息按照规定的格式保存到本地文件中
log4j的五种级别
①FATAL
②ERROR
③WARN
④INFO
⑤DEBUG
在log4j.properties配置文件中配置
log4j.logger.com.xxxx.mapper=debug/trace (log4j.logger+包名---即以该包名开头的所有的命名空间都用debug或者trace级别记录日志)
8.注意事项
①#{ }相当于展位操作
②${ }相当于拼接,无法应对sql注入攻击
③#{0} #{param1} 获得下标为0的参数
④如果传入的参数只有一个,且类型为引入数据类型,非包装类或者String,不能使用#{0.name} #{param1.name}获取值,可以直接#{name},或者给该 参数在接口中添加注解,声明别名如: List<Flower> select(@Param("f")Flower flower)
⑤select必须要声明返回值类型及resultMap或者resultType,DML语句不需要再标签中声明,因为返回的都是int
⑥标签中的parameterType可以省略,在底层会自动匹配参数类型,如果写了但写错了,会报错
⑦resultType如果为Map,sqlSession调用了selectMap()的方法,会自动生成一个类去存放所对应的数据库的字段值,和你声明的实体类无关,因此不能强转,否则会报错,但如果resultType为实体类如Flower,调用了selectMap()生成的value值得真实类型就是Flower了,可以强转,select底层都是调用了selectList方法
三.MyBatis的SQL动态拼接
1.if标签
<if test="param1!=null and param1!='' ">
</if>
2.where标签
自动在前面加上where,同时去除第一个and
<where>
</where>
3.choose when otherwise标签
相当于else if()只执行一个,后续都不执行
<choose>
<when test="">
</when>
<otherwise>
</otherwise>
</choose>
4.set标签
自动补充set关键字,并且把最后逗号去掉(只能用于update标签中)
<set>
<if>
</if>
</set>
5.trim标签
去除前缀后缀及添加前缀后缀----------功能十分强大
<trim prefix="set" suffixOverrides=",">
</trim>
prefix增加前缀 prefixOverrides去除前缀
suffix增加后缀 sufffixOverrides去除后缀
6.foreach标签
open开始 close结束 separator分割 item把每一个值赋予item
<foreach collection="list/array" open="(" close=")" separator="," item="it">
#{it}
</foreach>
7.bind标签
用于模糊查询
<bind name="pa" value="'%'+param1+'%'"></bind>
8.sql标签
sql使用*效率非常低 可以使用sql配置替代* ------------把相同的代码的内容提取出来
<sql id="..">
id,name,price
</sql>
9.include
INCLUDE引入SQL片段使用的标签
<include refid="sql的id"></include>
四.多表联合查询
1.resultMap的三个使用场景
①数据库的字段名和实体中的属性名
②N+1查询的时候 (注意:书写的两个表中的公共字段不可以省去)
③多表查询的sql语句的时候 (注意:即使字段名称一致也不可以省去)
2.什么时候使用 resultType 什么时候使用resultMap
①单表的查询的时候resultType
②数据库的字段和实体的属性不一致resultMap
③多表查询的sql语句的时候resultMap
3.业务代码方式和N+1方式的区别和联系
联系:
无论使用哪一种方式执行的sql语句都是N+1条
不同点:
业务代码:两个表的联系是使用java代码的方式进行关联的
N+1方式:mybatis标签的配置
4.示例
多对一的多表查询的sql语句
<resultMap id="rm1" type="student">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<result column="password" property="password"></result>
<result column="clazz" property="clazz"></result>
<association property="cla" javaType="Clazz" >
<id column="cid" property="id"></id>
<result column="cname" property="name"></result>
</association>
</resultMap>
一对多的多表查询sql语句
<resultMap type="clazz" id="rm2">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<collection property="stuList" ofType="student">
<id column="sid" property="id"></id>
<result column="sname" property="name"/>
<result column="sage" property="age"/>
<result column="sclazz" property="clazz"/>
</collection>
</resultMap>
注意:即使字段名称一致也不可以省去N+1方式的多表查询
如果是N+1方式跟上面两种方式差不多,但是在collection中和association中需要指定select(namespace+statementId或者自己写sql语句) ,还有要指定column,以指定的column为参数进行查询;column和你执行的sql语句要有关系;
注意:书写的两个表中的公共字段不可以省去
五.mybatis中的注解
mubatis中的注解:
注解的出现就是为了简化XML 的操作
@Select("select * from student")
public List<Student> findAll();
@Select("select * from student where sid =#{0}")
public Student findOne(int sid);
@Insert("insert into student values(default,#{sname},#{pwd},#{clazzno})")
public int insert(Student stu);
@Update("update student set sname = #{sname} where sid=#{sid}")
public int update(Student stu);
@Delete("delete from student where sid =#{0}")
public int delete(int sid);
注解的缺点:
[1]多表的查询支持操作不完善
[2]使用XML的目的是实现java和SQL语句的问题
[3]使用注解的使用必须保证 实体中的属性和数据库的字段必须一致
六.Mybatis的运行原理
1. 运行过程中涉及到的类
1.1 Resources MyBatis中IO流的工具类
1.1 加载配置文件
1.2 SqlSessionFactoryBuilder() 构建器
1.2.1 作用:创建SqlSessionFactory接口的实现类
1.3 XMLConfigBuilder MyBatis全局配置文件内容构建器类
1.3.1 作用负责读取流内容并转换为JAVA代码.
1.4 Configuration 封装了全局配置文件所有配置信息.
1.4.1 全局配置文件内容存放在Configuration中
1.5 DefaultSqlSessionFactory 是SqlSessionFactory接口的实现类
1.6 Transaction 事务类
1.6.1 每一个SqlSession会带有一个Transaction对象.
1.7 TransactionFactory 事务工厂
1.7.1 负责生产Transaction
1.8 Executor MyBatis执行器
1.8.1 作用:负责执行SQL命令
1.8.2 相当于JDBC中statement对象(或PreparedStatement或CallableStatement)
1.8.3 默认的执行器SimpleExcutor
1.8.4 批量操作BatchExcutor
1.8.5 通过openSession(参数控制)
1.9 DefaultSqlSession 是SqlSession接口的实现类
1.10 ExceptionFactory MyBatis中异常工厂
2.流程解释
在MyBatis运行开始时需要先通过Resources加载全局配置文件.下面需要实例化SqlSessionFactoryBuilder构建器.帮助SqlSessionFactory接口实现类DefaultSqlSessionFactory.
在实例化DefaultSqlSessionFactory之前需要先创建XmlConfigBuilder解析全局配置文件流,并把解析结果存放在Configuration中.之后把Configuratin传递给DefaultSqlSessionFactory.到此SqlSessionFactory工厂创建成功.
由SqlSessionFactory工厂创建SqlSession.
每次创建SqlSession时,都需要由TransactionFactory创建Transaction对象,同时还需要创建SqlSession的执行器Excutor,最后实例化DefaultSqlSession,传递给SqlSession接口.
根据项目需求使用SqlSession接口中的API完成具体的事务操作.
如果事务执行失败,需要进行rollback回滚事务.
如果事务执行成功提交给数据库.关闭SqlSession
-------------------------------------------------------------------------------------------
ps:下一节会对mybatis的缓存机制进行总结