MyBatis【从入门到基本精通】
一、MyBatis的基本使用
1、MyBatis作用
- MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。
- MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
- MyBatis可以使用简单的XML用于配置和原始映射,将接口和Java的POJO类映射成数据库中的记录
- 使开发者只需要关注 SQL
本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的
过程代码。
2.MyBatis的历史
原是apache的一个开源项目iBatis,2010年6月这个项目由apache software foundation
迁移到了google code,并且改名为MyBatis 。
iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。
3.为什么要使用MyBatis?
JDBC的缺点
- SQL夹在Java代码块里,耦合度高导致硬编码内伤
- 维护不易且实际开发需求中sql是有变化,频繁修改的情况多见
- 要自已创建connection、创建statement、手动设置参数、结果集检索等
Hibernate的缺点
- 长难复杂SQL,对于Hibernate而言处理也不容易
- 内部自动生产的SQL,不容易做特殊优化。
MyBatis的好处:
- 对开发人员而言,核心sql还是需要自己优化
- MyBatis是一个半自动化的持久化层框架。
- MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。
二、MyBatis的开发步骤
1、下载Mybatis核心包
http://www.mybatis.org/mybatis-3/getting-started.html
https://github.com/mybatis/mybatis-3/releases
2、创建工程,引入MyBatis核心包及依赖包

3、创建customer表
1 | 1 CREATE TABLE customer( |
4、建立与表对象的domain,创建Customer实体类我在IDEA中用了lombok jar包
1 | package com.lqg.domain; |
5、创建与表对象的关系映射Mapping文件编写sql语句
1 | <?xml version="1.0" encoding="UTF-8" ?> |
6、在核心配置文件当中引入Mapping
1 | <!--加载映射文件--> |
7、创建工厂,执行sql语句
1 | package com.lqg.test; |
8通过用户id查询结果如下:

三. MyBatis的入门程序:
4.1、MyBatis的CRUD操作
MyBatis查询一个,多个以及增删改
4.4.1通过用户id进行查询
对应映射配置
1 | <select id="queryCustomerById" parameterType="Int" resultType="com.domain.Customer"> |
在测试类里面查询
1 | Customer c = session.selectOne("queryCustomerById", 1); |
查询所有用户
在对应的映射文件里面配置
1 | <select id="queryAllCustomer" resultType="com.domain.Customer"> |
模糊查询(同查询所有差不多)
1 | <select id="queryAllByName" parameterType="String" resultType="com.lqg.domain.Customer"> |
4.4.2、总结
- parameterType:指定输入参数类型,mybatis通过ognl从输入对象中获取参数值拼接在sql中
- resultType:指定输出结果类型,mybatis将sql查询结果的一行记录数据映射为resultType指定类型的对象。如果有多条数据,则分别进行映射,并把对象放到容器List中
- selectOne查询一条记录,如果使用selectOne查询多条记录则抛出异常
- selectList可以查询一条或多条记录
- #{}
表示一个?占位符号,通过#{}可以实现preparedStatement向占位符中设置值
自动进行java类型和jdbc类型转换,可以有效防止sql注入
#{}可以接收简单类型值或pojo属性值
如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称
里面的参数传递过来都是加上’’引号的, - 表示拼接sql串,可以接收简单类型值或pojo属性值通过{} 表示拼接sql串,可以接收简单类型值或pojo属性值 通过表示拼接s*ql串,可以接收简单类型值或pojo*属性值通过{}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换
如果parameterType传输单个简单类型值,${}括号中只能是value
5、保存更新删除
5.1添加用户
对应关系映射配置
1 | <insert id="insertCustomer" parameterType="com.domain.Customer"> |
注意:如果添加操作后面直接跟的表名,赋值里面的所有字段都要写上包括自动增长的id,如果是跟字段那值就跟上自己写的字段一一对应
5.5.1、添加用户的方法测试代码
1 | SqlSession session = MyBatisUtils.openSession(); |
注意:当要修改数据库中的记录的时候,执行sql时候需要自己提交事务
5.5.2、返回添加过后自增的主键两种方式
方式一:获取插入最后一个id(写在insert标签里面)
1 | <selectKey keyColumn="cust_id" keyProperty="cust_id" resultType="Integer" order="AFTER"> |
方式二:获取插入的最后一个id(这种方式比第一种简单)*
1 | <insert id="insertCustomer" parameterType="Customer" useGeneratedKeys="true" keyProperty="cust_id" keyColumn="cust_id"> |
5.2更新用户
对应关系映射配置
1 | <update id="updateCustomerById" parameterType="com.lqg.domain.Customer"> |
5.2.1、修改用户的方法测试代码
1 | Customer customer1 = new Customer(); |
5.3删除用户
对应关系映射配置
1 | <delete id="deleteCustomerById" parameterType="com.lqg.domain.Customer"> |
5.3.1、修改用户的方法测试代码
1 | Customer customer1 = new Customer(); |
四、MyBatis开发Dao
1、原始的Dao开发方法
1.1、创建CustomerDao接口类
1 | package com.lqg.dao; |
1.2、创建CustomerDao接口类的实现类CustomerDaoImpl
1 | package com.lqg.daoImpl; |
1.3、创建CustomerDao的测试类TestCustomerDao的测试类
1 | package com.lqg.test; |
2.Mapper动态代理
2.1、Mapper动态代理开发的要求
- namespace必须和Mapper接口类路径一致
- id必须和Mapper接口方法名一致
- parameterType必须和接口方法参数类型一致
- resultType必须和接口方法返回值类型一致
2.2、先重新创建一张表
1 | CREATE TABLE tbl_employee{ |
2.3、这是演示的结构图
2.4、创建一个Employee的pojo类
1 | package com.lqg.mybatis.domain; |
2.5、创建MyBatis的核心配置文件
1 | <?xml version="1.0" encoding="UTF-8" ?> |
2.6、创建pojo的接口类
1 | package com.lqg.mybatis.dao; |
2.7、创建pojo的映射EmployeeMapper.xml
1 | <?xml version="1.0" encoding="UTF-8" ?> |
2.8、最后编写MyBatisTest的测试类
1 | package com.lqg.mybatis.test; |
2.9、查询效果如下
五、MyBatis的参数传递
1.单个参数
- 可以接受基本类型,对象类型,集合类型的值。
- MyBatis可直接使用这个参数,不需要经过任何处理。
2.多个参数
- 任意多个参数,都会被MyBatis重新包装成一个Map传入。
- Map的key是param1,param2…,值就是参数的值
示例

3.@param命名参数 - 为参数使用@Param起一个名字
- MyBatis就会将这些参数封装进map中,key就是我们自己指定的名字
示例


4.pojo - 当这些参数属于我们业务POJO时,我们直接传递POJO
示例


5.Map
我们也可以封装多个参数为map,直接传递
示例


6.参数传递源码分析 - 会把参数给放到一个数组当中
- 如果一个参数, 内部处理时,会自动把该参数范围

- 如果是多个参数,内部会做判断
- 判断是否有@param注解
如果没有:
- 没有注解的话, 就直接使用arg0 arg1…为key 放到map中
并且还会以param1和param2…为key放一份到map中

如果有
- 如果有注解的话, 会使用注解当中的值,替换掉默认的arg0和arg1 使用@param中的值,做为key 放到一个map当中
并且还会以param1和param2…为key放一份到map中

六、MyBatis的核心配置文件
1、 properties:定义属性及读取属性文件
示例
1 | <properties resource="jdbc.properties"> |
resource为资源文件,配置文件访问方法”${key名称}”,如访问数据库连接,如果配置了相同的property会先加载,resource里面的会把其覆盖掉
2、settings——这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为
示例
1 | <!--全局信息配置,--> |
3、typeAliases——(定义别名,可以在使用时候省略掉前面一串路径)
1 | <typeAliases> |
如果当前包类与子包类重名,会有异常,可以在类上使用注解@Alias(“别名”)
4、typeHandlers——(类型处理器)
无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,
还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。
JDK1.8之后实现全部的JSR310规范
日期时间处理上,我们可以使用MyBatis基于JSR310(Date and Time API)
编写的各种日期时间类型处理器。
MyBatis3.4以前的版本需要我们手动注册这些处理器,以后的版本都是自动注册的
5、Plugins ——(插件)
插件是MyBatis提供的一个非常强大的机制,
MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。
通过插件来修改MyBatis的一些核心行为。
6、Environments ——(数据库运行的环境)
MyBatis可以配置多种环境,比如开发、测试和生产环境需要有不同的配置。
每种环境使用一个environment标签进行配置并指定唯一标识符
可以通过environments标签中的default属性指定一个环境的标识符来快速的切换环境
Environment子标签
transactionManager事务管理
Type有以下取值
JDBC
使用JDBC 的提交和回滚设置,依赖于从数据源得到的连接来管理事务范围
MANAGED
不提交或回滚一个连接、让容器来管理事务的整个生命周期
ManagedTransactionFactory
自定义
实现TransactionFactory接口
type=全类名/别名
dataSource数据源
type有以下取值
UNPOOLED
不使用连接池UnpooledDataSourceFactory
POOLED
使用连接池PooledDataSourceFactory
JNDI
在EJB 或应用服务器这类容器中查找指定的数据源
自定义
实现DataSourceFactory接口,定义数据源的获取方式
实际开发
实际开发中我们使用Spring管理数据源
并进行事务控制的配置来覆盖上述配置
7、databaseIDProvider——(定义数据的厂商)
MyBatis 可以根据不同的数据库厂商执行不同的语句。
可以能过databaseIDProvider标签来进行设置
1 | <databaseIdProvider type="DB_VENDOR"> |
8、mappers——(加载映射文件)
8.1、使用文件路径引入映射器
1 | <mapper resource="domain/Customer.xml"></mapper> |
8.2、使用mapper接口类路径,此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中
1 | <mapper class=" " /> |
8.3、使用包名引入映射器
指定包下的所有mapper接口、批量加载、此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中
1 | <package name=""/ |
//加载对应包下面所有的文件
七、MyBatis的输出类型
八、MyBatis【关联映射】
1、MyBatis的多表连接
1.1一对一

1.1.1设计表格:
1 | --mysql |
1.1.2、实体类
1 | /** |
1.1.3、映射文件
由于我们有两个实体,因此我们会有两个映射文件
Student映射文件
1 | <?xml version="1.0" encoding="UTF-8" ?> |
Card映射文件
1 | <?xml version="1.0" encoding="UTF-8" ?> |
我来看一下查询结果:
我们的实体与映射表中,Student实体是没有关联其他的字段的,仅仅是写出了该实体的自带的属性。
1 | <resultMap type="zhongfucheng2.Student" id="studentMap"> |
明显地,我们Student是不能封装返回的结果,因此我们需要将关联属性进行关联起来!
1 | <resultMap type="zhongfucheng2.Student" id="studentMap"> |
我们关联了以后,Student实体就能够封装返回的结果了
1 | <!-- 因为使用多表联合查询, |
1.1.4查询编号为1的学生信息【包括身份证编号】
1 | public Student findById(int id) throws Exception { |
这里写图片描述
2.1一对多

2.1.1设计数据库表
1 | create table grades( |
2.1.2创建实体类
1 | package zhongfucheng2; |
2.1.3映射文件SQL语句
1 | <mapper namespace="studentNamespace"> |
2.1.4DAO
1 | public List<Student> findByGrade(String grade) throws Exception { |

1.3多对多

1.3.1数据库表
1 | create table students( |
1.3.2 创建实体类
1 | package cn.itcast.javaee.mybatis.many2many; |
1.3.3映射文件
1 | <?xml version="1.0" encoding="UTF-8" ?> |
1.3.4创建DAO
1 | package cn.itcast.javaee.mybatis.many2many; |
九、MyBatis的动态sql语句
1.什么是动态sql:
通过mybatis提供的各种标签方法实现动态拼接sql。
1、if标签
需求:根据客户名和级别查询客户
1 | <!--根据客户名和级别查询客户--> |
存在问题
- 有可能传入的名称或级别为空
- 可以使用if标签来进行判断
注意:test:放的是Boolean表达式
1 | <select id="queryCustomerWhere" parameterType="customer" resultType="customer"> |
如果前一个条件这后,后面就会多一个and执行就会报错
2、Where标签
where标签可以自动添加where,同时可以处理sql语句中第一个and关键字
1 | <select id="queryCustomerWhere" parameterType="customer" resultType="customer"> |
去掉第一个前And
3、trim标签
- prefix:设置前缀,在第一个条件之前加上一个前缀
- prefixOerrides:条件前缀覆盖,把第一个条件之前的and变成空
- suffix:设置后缀,在最后一个条件之后加上一个后缀
- suffixOverrides:条件后缀覆盖,把最后一个条件之后的and变成空
1 | <select id="getCustomer" resultType="domain.Customer"> |
DAO层
现在我想根据学生的编号查询学生的信息和身份证信息!
由于该查询着重是查询学生的信息,于是我们在学生的映射文件中写SQL语句
按照需求,我们写出来的SQL语句是这样子的
4、choose标签
choose用法基本和if一致
sql
sql
sql
注意:整个choose最终只会匹配一种情况
when
choose标签:(只查满足条件的第一个,后面的条件都不执行) select * fromcustomer
1 | <where> |
5、set标签
6、foreach
向sql传递数据或List,mybatis使用foreach解析,如下
根据多个id查询用户信息
查询sql:select * from user where id in(1,10,24)
在pojo中定义list属性ids存储多个用户id,并添加getter/settter方法
1 |
|
Mapper.xml文件
1 | <!--根据ids查询用户--> |
7、bind
用于绑定一个字符,并且取名
8、Sql片段
使用include标签加载sql片段,refid是sql片段的id
如果要使用别的Mapper.xml配置的sql片段,可以在refid前面加上对应的Mapper.xml的nameSpace
如:
1 | <include refid="com.lqg.mybatis.mapper.OrderMapper.userFirlds"/> |
