MyBatis:底层封装了JDBC的持久层框架
1.为什么使用MyBatis
1.1. 传统的ORM框架介绍?
-
传统的访问数据库的方式?JDBC
- 加载驱动 Class.forName()
- 获得连接 Connection con…
- 创建执行SQL的Statement对象 PreparedStatement…
- 执行SQL返回结果 execute executeUpdate executeQuery()
- 处理结果 while rs.next()…
- 关闭资源 close
问题:面向对象开发和面向关系存储之间不匹配问题【不完全对应。】开发人员手动处理由对象到关系型数据库之间的对应。【手动处理】 -
ORM思想的出现:
-
ORM:Object Relational Mapping 对象关系映射,这种思想目标是把面向对象开发中的对象映射到基于SQL的关系型数据库中。 -
addStu(Student stu) orm: addStu(Student stu) jdbc:手动造车 手动执行 ORM框架.save(stu)–>XML 映射文件 手动处理结果 手动写SQL 映射文件: 类=表 类中属性-表中字段 ? } -
ORM是一种思想,其中最著名的实现: Hibernate. -
Hibernate是一款“全自动”的ORM映射框架:实现了Pojo到数据库表的全套映射机制,开发人员只需要定义好映射文件。Hibernate会自动的根据映射文件逻辑生成SQL语句、自动的执行SQL语句、自动的返回结果。 -
Hibernate save()–>insert语句 翻译过程 效率非常低、SQL语句不灵活
2.MyBatis简介?
-
MyBatis也是一款ORM思想的实现框架,底层也是封装的JDBC。 -
MyBatis是一款"半自动的"ORM框架. MyBatis也会执行SQL,返回结果。具体的SQL语句需要开发人员自己写。 灵活 效率高。 -
MyBatis在2010年之前叫IBatis,属于ASF(apache software foundation),后来退出ASF,改名为MyBatis。 -
文档地址: https://mybatis.org/mybatis-3/zh/configuration.html -
MyBatis中有两类配置文件:
- 属性文件mybatis-config.xml:连接数据库的信息+属性 配置
- 映射文件StudentMapper.xml: 我们写的SQL语句
3.MyBatis提供的用户接口?
- org.apache.ibatis.session.SqlSessionFactoryBuilder:
- build(IO流)
- build(Configuration 配置对象)
- org.apache.ibatis.session.SqlSessionFactory:
- openSession()
- org.apache.ibatis.session.SqlSession:[核心]
- insert
- update
- delete
- selectOne selectList…
4. MyBatis的helloworld[对学生表的CRUD]?
-
mybatis-config.xml <?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>
<properties resource="db.properties"></properties>
<settings>
<setting name="logImpl" value="LOG4J"></setting>
</settings>
<typeAliases>
<package name="com.etoak.student.entity"/>
</typeAliases>
<environments default="m">
<environment id="m">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${m.driver}"></property>
<property name="url" value="${m.url}"></property>
<property name="username" value="${m.user}"></property>
<property name="password" value="${m.pwd}"></property>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="StudentMapper.xml" />
</mappers>
</configuration>
-
XXMapper.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="com.et">
<insert id="addStu" parameterType="com.etoak.student.pojo.Student">
insert into student( name, age, birth, email, schid)
values(#{name},#{age},#{birth},#{email},#{schid})
</insert>
<select id="queryStuById" parameterType="int"
resultType="com.etoak.student.pojo.Student">
select * from student where id=#{id}
</select>
<update id="updateStu" >
update student set name=#{name},age=#{age},birth=#{birth},
email=#{email} where id=#{id}
</update>
<delete id="deleteStu" >
delete from student where id=#{id}
</delete>
<select id="queryAll" resultType="com.etoak.student.pojo.Student">
select * from student
</select>
</mapper>
-
基础操作
session.insert(SQL语句id,参数)
session.update(SQL语句id,参数)
session.delete(SQL语句id,参数)
session.selectOne(SQL语句id,参数)
session.selectList(SQL语句id,参数)
5. Mapper方式实现MyBatis?
- Mapper.xml中namespace的名字和Mapper接口的名字一致
- Mapper.xml中的SQL语句的id和Mapper接口中方法名字一致
6. 类中属性和表中字段不完全一致?
-
添加 #{类中的属性不是表中的字段} -
查询
-
起别名 <select id="queryById" parameterType="int"
resultType="stu">
select
s_id as id,
s_name name,
s_age age,
s_birth birth,
s_email as email,
s_schid as schid
from tb_stu where s_id=#{id}
</select>
-
使用resultMap <resultMap id="rMap_stu" type="stu">
<id property="id" column="s_id"></id>
<result property="name" column="s_name"></result>
<result property="age" column="s_age"></result>
<result property="birth" column="s_birth"></result>
<result property="email" column="s_email"></result>
<result property="schid" column="s_schid"></result>
</resultMap>
<select id="queryById" parameterType="int" resultMap="rMap_stu">
select * from tb_stu where s_id=#{id}
</select>
7. 传递多个参数?
-
Map -
@Param -
对象
List<Student> querySome1(@Param("start")int startadadfa,
@Param("pageSize") int pageSizeasdfadf);
List<Student> querySome(Map<String,Object> map);
8. resultType和resultMap的区别?
- resultType:表示执行SQL查询之后的结果集的每一条记录返回的类型,如:自定义的对象Student/User/Teacher、int、map
- resultMap:一定对应的一个元素的id
9. MyBatis如何获得添加到数据库中的主键?
-
JDBC如何获得?
-
自动增长的数字
- 开关 Statement.RETURN_GENERATED_KEYS
- 同一个连接前提下查询:select last_insert_id()
-
字符串
- select replace(uuid(),‘-’,‘’)
- UUID.randomUUID()
- KeyGenerator.getId()
-
MyBatis和JDBC原理一样。
-
使用useGeneratedKeys +keyProperty属性 <insert id="addStudent" parameterType="stu" useGeneratedKeys="true"
keyProperty="id" keyColumn="s_id" >
insert into tb_stu( s_name, s_age, s_birth, s_email, s_schid)
values(#{name},#{age},#{birth},#{email},#{schid})
</insert>
-
selectKey <insert id="addStudent" parameterType="stu" >
<selectKey keyProperty="id" keyColumn="s_id" resultType="int"
order="AFTER">
select last_insert_id()
</selectKey>
insert into tb_stu( s_name, s_age, s_birth, s_email, s_schid)
values(#{name},#{age},#{birth},#{email},#{schid})
</insert>
10. 批量添加?
-
使用就是动态标签 foreach <insert id="addStus1" parameterType="list">
insert into tb_stu(s_name, s_age, s_birth, s_email, s_schid)
values
<foreach collection="list" item="s" separator=",">
(#{s.name},#{s.age},#{s.birth},#{s.email},#{s.schid})
</foreach>
</insert>
<insert id="addStus" parameterType="list">
insert into tb_stu(s_name, s_age, s_birth, s_email, s_schid)
<foreach collection="list" item="s" separator=" union ">
(select #{s.name},#{s.age},#{s.birth},#{s.email},#{s.schid} )
</foreach>
</insert>
11. 模糊查询:#和$的区别?
1.#底层使用的是预编译的Statement,即:PreparedStatement,支持?占位符的。$:底层使用的是普通的Statement,不支持?占位符的,参数只能拼接。
2.有些情况不能使用?占位:
? 参考JDBC :PrearedStatement和Statement的区别。
12. MyBatis中的动态SQL标签?
-
where -
if <select id="queryByConditions1" resultMap="rMap_stu">
select * from tb_stu
<where>
<if test="name!=null and name!='' ">
and s_name like '%${name}%'
</if >
<if test="email!=null and email!='' ">
and s_email=#{email}
</if>
</where>
</select>
-
foreach <insert id="addStus1" parameterType="list">
insert into tb_stu(s_name, s_age, s_birth, s_email, s_schid)
values
<foreach collection="list" item="s" separator=",">
(#{s.name},#{s.age},#{s.birth},#{s.email},#{s.schid})
</foreach>
</insert>
<insert id="addStus" parameterType="list">
insert into tb_stu(s_name, s_age, s_birth, s_email, s_schid)
<foreach collection="list" item="s" separator=" union ">
(select #{s.name},#{s.age},#{s.birth},#{s.email},#{s.schid} )
</foreach>
</insert>
-
trim <select id="queryByConditions" resultMap="rMap_stu">
select * from tb_stu
<trim prefix="where" prefixOverrides="and">
<if test="name!=null and name!='' ">
and s_name like '%${name}%'
</if >
<if test="email!=null and email!='' ">
and s_email=#{email}
</if>
</trim>
</select>
-
chose…when.otherwise <select id="queryByConditions" resultMap="rMap_stu">
select * from tb_stu
<trim prefix="where" prefixOverrides="and">
<choose>
<when test="name!=null and name!='' ">
and s_name like '%${name}%'
</when>
<otherwise>
and s_email=#{email}
</otherwise>
</choose>
</trim>
</select>
13. 一对一和一对多的关联查询?
-
association <resultMap id="rMap_stu_sch" type="stu">
<id property="id" column="s_id"></id>
<result property="name" column="s_name"></result>
<result property="age" column="s_age"></result>
<result property="birth" column="s_birth"></result>
<result property="email" column="s_email"></result>
<result property="schid" column="s_schid"></result>
<association property="sch" javaType="com.etoak.student.entity.School">
<id property="id" column="id"></id>
<result property="name" column="name"></result>
<result property="phone" column="phone"></result>
<result property="info" column="info"></result>
</association>
</resultMap>
<select id="queryByIdWithSch" resultMap="rMap_stu_sch">
select
s_id, s_name, s_age, s_birth, s_email, s_schid,
sch.id, sch.name, sch.phone,sch.info
from tb_stu s left join school sch
on s.s_schid = sch.id where s.s_id=#{id}
</select>
-
collection:一对多 <resultMap id="rMap_sch" type="com.etoak.student.entity.School">
<id property="id" column="id"></id>
<result property="name" column="name"></result>
<result property="phone" column="phone"></result>
<result property="info" column="info"></result>
<collection property="stus" ofType="stu">
<id property="id" column="s_id"></id>
<result property="name" column="s_name"></result>
<result property="age" column="s_age"></result>
<result property="birth" column="s_birth"></result>
<result property="email" column="s_email"></result>
<result property="schid" column="s_schid"></result>
</collection>
</resultMap>
<select id="querySchWithStus" resultMap="rMap_sch">
select sch.id, sch.name, sch.phone,sch.info,
s_id, s_name, s_age, s_birth, s_email, s_schid
from school sch left join tb_stu s on s.s_schid = sch.id
where sch.id=#{id}
</select>
14. MyBatis的核心接口【面向内部的】?
-
org.apache.ibatis.session.Configuration:
- 代表MyBatis中的配置文件
- 其中的属性:Environment:代表环境标签
- 其中的属性:MappedStatement:代表SQL映射文件中的等标签
-
org.apache.ibatis.mapping.Environment:
- 代表环境元素.
- 其中的属性:id+transactionFactory+dataSource
-
org.apache.ibatis.mapping.MappedStatement:
-
代表SQL映射文件中的标签 -
其中的属性:
-
StatementType:执行器的类型 枚举 STATEMENT:普通的执行器
PREPARED:预编译的执行器
CALLABLE:执行触发器的执行器
-
ResultSetType:结果集的类型 枚举 DEFAULT(-1):默认的结果集
FORWARD_ONLY(1003):不可滚动的结果集
SCROLL_INSENSITIVE(1004):可滚动结果集
SCROLL_SENSITIVE(1005):可滚动的结果集
-
SqlCommandType:SQL语句的类型 枚举 INSERT/UPDATE/DELETE/SELECT/UNKNOWN
-
SqlSource:解析SQL语句的方法+获得SQL的方法 其中有一个方法getBoundSql:BoundSql真正代表SQL语句
-
org.apache.ibatis.type.TypeAliasRegistry:类型别名注册器 存放别名
-
TypeAliasRegistry构造时默认注册一些别名: int string list -
new Configuration():中 自动添加别名 如:JDBC POOLED LOG4J -
我们写的别名 1. <typeAlias type="" alias="">
2. <typeAliasPackage value="">
-
org.apache.ibatis.builder.BaseBuilder:基本的解析器
-
代表解析器。解析XML的。 -
其中主要属性和构造方法 public abstract class BaseBuilder{
protected final Configuration configuration;
protected final TypeAliasRegistry typeAliasRegistry;
protected final TypeHandlerRegistry typeHandlerRegistry;
public BaseBuilder(Configuration configuration) {
this.configuration = configuration;
this.typeAliasRegistry = this.configuration.getTypeAliasRegistry();
this.typeHandlerRegistry = this.configuration.getTypeHandlerRegistry();
}
-
BaseBuilder有很多子类:
- XMLConfigBuilder:解析 mybatis-config.xml
- XMLMapperBuilder:解析 *Mapper.xml
- XMLStatementBuilder:解析insert update delete标签的
- XMLScriptBuilder:SQL语句
-
org.apache.ibatis.io.Resources:资源
- 该类是MyBatis封装的工具类。专门加载配置文件
- 底层委托 classLoaderWrapper实现具体加载的。原理就是使用ClassLoader.getResourceAsStream实现的。
15. 解析配置以及SqlSessionFactory构造的过程?
-
SF工厂
-
build(reader)
-
分步骤解析:1.XMLConfigBuilder parser = new XMLConfigBuilder(reader)
XMLPathParser:接收mybatis-config.xml流+resolver,本身提供把流转换成Document对象【JDK中提供DOM解析器】的方法和一堆使用JDK中提供的XPath方式计算XML中每一个部分的的方法。
-
分析步骤2: parser.parse():挨个解析mybatis-config和mapper.xml中的每一个元素 最终都装configuration对象 -
步骤分析3:new DefaultSqlSessioFacotry(config)
16. parseConfiguration中的几个部分分析?
-
解析元素 -
解析元素
-
解析元素
-
XMLConfigBuilder:解析mybatis-config.xml 1.XMLConfigBuilder中 调用 XMLMapperBuilder解析 Mapper.xml, 2.然后再XMLMapperBuilder 调用XMLStatementBuilder专门解析元素中的每一个属性和内容 2.然后再XMLStatementBuilder中调用XMLScriptBuilder 构造SQL语句 BoundSql===》SqlSource
17. 常见错误?
- Mapped Statements collection does not contain value for xxx
? 原因: SQL语句映射文件中没有DAO层调用的语句。
-
A query was run and no Result Maps were found for the Mapped Statement ‘com.et2203.queryById’. It’s likely that neither a Result Type nor a Result Map was specified. 原因:执行的是查询语句,没有resultType或者resultMap。 -
Caused by: org.apache.ibatis.binding.BindingException: Parameter ‘start’ not found. Available parameters are [arg1, arg0, param1, param2] 原因:传递多个参数MyBatis默认不会按照形参去命名,而是自动命名为:arg0,arg1…或者param1 param2…
|