一、简介
1、概念
- mybatis 是一个半自动轻量级的一个 orm 框架
2、作用
- 将 java 与 sql 分离,解决了 jdbc 的硬编码问题,方便 sql 的修改;
- sql 由开发人员控制,更加方便 sql 的调优;
3、快速开始
(1)原始方法
- 建一个全局配置文件,里面是数据源等运行环境的信息;
- 建立一个sql 的映射文件,并将这个文件注册到全局的配置中;
- 根据全局的配置文件获得一个 sqlsessionfactory;
- 通过 factory 获得 sqlsession(非线程安全),一个sqlsession 就是和数据库的一次会话,用完需要关闭;
- sqlsession通过 sql 的唯一标识符调用方法执行;
- 注意数据库的字段名和bean的字段名要相同才能顺利映射;
(2)接口式编程
- 定义一个接口,接口中定义操作数据库的方法;
- 将接口和sql的映射文件绑定:xml的namespace是接口全限定名,sql的id是接口中的方法名;
- 在 java 程序中通过session获得借口的实现类(代理对象)对象;
- 通过对象调用方法执行相应的sql;
二、配置文件
1、全局配置文件
(1)xml 中引入 dtd 约束
(2)properties标签:url引入网络或者磁盘的资源;resource引入 classpath 下的资源;
(3)settings标签:设置一些mybatis运行时的重要参数
(4)typeAliases标签:就是给 java 类起别名用的
- 别名不分大小写;
- 可以单独起也可以批量起;
- 默认别名就是类名;
- 也可以使用注解来起别名(@alias);
- java 中的基本数据类型和一些常用的类已经取好了别名(基本类型就是前面加 _ ;引用类型就是原类名)
(5)typeHandlers标签:
- 就是处理 java 类型和数据库类型的转换的;
- 常用的类型 mybatis 都给默认处理了,不用我们自己去做;
- 当然是支持自定义的了;
(6)plugins标签:作用就是拦截四大对象,改变他们的默认行为
(7)environments标签:
- 用来配置环境的,可以配置多个环境,在default属性里可以指定默认的环境;
- 每个环境都应包含:transactionManager 和 dataSource
(8)databaseIdProvider标签:
- 为mybatis提供多数据库厂商的支持;
- 厂商标识在数据库的驱动里;
- 标签内通过property标签指定数据库的别名;
- 在相应的sql语句的标签上用databaseId引入数据库的别名;
- 注意:主配置文件里的标签的书写的顺序是有要求的,databaseIdProvider应该写在envir 和 mapper 之间;
(9)mappers标签:
- 作用就是注册 sql 映射;
- 里面具体的 mapper 的属性有三种写法:
- resource:classpath 路径下;
- url:网络资源或者磁盘资源;
- class:指定对应的映射的接口(条件是必须同包同名);
- 批量的注册直接用package 标签(条件是必须同包同名);
<?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="conf/dbconfig.properties"></properties>
<!-- <settings>
<setting name="" value="" />
</settings>
<typeAliases>
单独起别名
<typeAlias type="" alias="" />
批量起别名
<package name="" />
</typeAliases>
<typeHandlers>
<typeHandler handler="" />
</typeHandlers>
<plugins>
<plugin interceptor=""></plugin>
</plugins> -->
<environments default="development">
<!-- <environment id="test">
<transactionManager type=""></transactionManager>
<dataSource type=""></dataSource>
</environment> -->
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</dataSource>
</environment>
</environments>
<databaseIdProvider type="DB_VENDOR">
<property name="Oracle" value="oracle" />
<property name="MySQL" value="mysql" />
</databaseIdProvider>
<mappers>
<mapper resource="conf/TuserMapper.xml" />
</mappers>
</configuration>
2、sql映射文件概述
(1)增删改测试
- int、long 和 boolean 类型的返回值我们可以直接用;
- 增删改后一定要 commit;
(2)数据插入获得自增主键
- mysql:支持自增主键
- useGeneratedKeys 和 keyProperty 属性配合使用即可获取到自增主键的值
- oracle:不支持自增主键,靠序列来完成
- 在要执行的sql前用 selectKey 标签来实现
- 相关的三个属性分别是 keyProperty、resultType 和 order;
- 有两种写法分别是 order 的属性值为 before 和 after;通常使用 before
3、映射文件的参数处理
(1)单个参数
- 单个参数可以在 #{}中随意写;
(2)多个参数
- 多个参数默认在其中写 param1 和 param2 等;也可以用注解@param 指定名称;多个参数本质是封装在一个map中;
- 业务相关的数据直接封装在 pojo 中;
- 关联性不高且使用的频率不高的话的可以放在一个map里;在map 里可以随意指定键名;
- 同时多个参数如果使用的频率很高的话还可以封装为一个 TO 对象;
- 集合和数组的特殊处理:参数可以写 collection、list 和 array;
(3)参数处理源码分析
- 参数封装成map 的过程:总结起来就是参数多的时候就封装成 map 集合,有@param注解的参数的键值就是指定的值,否则就是默认的;
(4)关于 #{} 和 ${}两种取值的方法:
- #{}是以预编译的形式来取参数的值的,可以防注入;而${}是直接拼接的;
- 大多数的情况采用 #{},但在原生的 jdbc 不支持占位符的地方可以使用 ${},比如order by ${age};
- #{}进行参数设置的时候可以指定一些规则,比如:#{email,jdbcType.null},mybatis自动将 null值映射为jdbc的other类型,这个类型oracle不支持会报错;
4、映射文件的select 元素
(1)resultType
- resultType的作用就是指定结果集的封装的规则;
- 结果集封装为 list类型直接写 list里数据类型即可;
- 封装为 map 单条记录直接写 map 的别名;多条记录写pojo 的类型(map的值是pojo),map的键值在相应的方法上面用注解@mapKey来指定pojo中的属性;
(2)resultMap(关联查询 | 分步查询 | 延迟加载 | 集合属性封装)
- 配置列名属性名映射
- resultMap也是用来定义结果集的封装规则的(表的列名和pojo 的属性名的对应关系);
- resultMap标签两个属性 type是pojo类型,id是唯一标识;表中的主键列用id 封装,普通列用 result 封装;
- 用resultMap实现关联查询(前提pojo包装pojo):
- 第一种方法是直接写 property 的时候用属性点属性的方式就可以了;
- 第二种方法是在 resultMap 里用 association 标签实现关联查询,两个属性 property 和 javatype;
- association 标签用法
- 可以用来实现关联查询;
- 用 association 实现分步查询:select属性指定 mapper方法,column 属性指定传入方法的参数;
- 关联查询时,如果想按需加载,就可以在全局 settings 里设置lazyloading 为true,实现get相应的pojo 的时候再发出sql向数据库查询;
- collection 标签用法
- 用 collection 标签实现集合类型属性的封装,属性 property为相应的集合类型的属性名,而ofType 是集合的泛型的类型;
- collection 实现分步查询和延迟加载:
- 实际上还是 select 将两个接口方法、两个sql关联,再用 column 属性传入参数;
- 多个参数的传递可以用map,就是这样的形式:{key1=col1,key2=col2};
- fetchType属性可以设置延迟加载;
- discriminator鉴别器根据列的值做出不同的处理:还是写在 resultMap里,内含case标签指定各种值的处理方法(封装方法),其中指定封装数据的类型时,type 和 map 必须二选一;这个东西用的少;
<?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.wc.mapper.TuserMapper">
<!-- <resultMap type="tuser" id="map1">
<id property="uid" column="tid"/>
<result property="uname" column="uname"/>
<result property="age" column="age"/>
关联查询
<association property="dept" javaType="department">
<id property="did" column="did"/>
<result property="dname" column="dname"/>
</association>
</resultMap> -->
<resultMap type="tuser" id="map2">
<id property="uid" column="tid"/>
<result property="uname" column="uname"/>
<result property="age" column="age"/>
<result property="did" column="did"/>
<!-- select step by step -->
<association property="dept"
select="com.wc.mapper.DepartmentMapper.getDeptById" column="did">
<id property="did" column="did"/>
<result property="dname" column="dname"/>
</association>
</resultMap>
<select id="getById" resultMap="map2">
select * from tuser where tid = #{id}
</select>
</mapper>
三、动态sql
1、if 判断
(1)OGNL(对象图导航语言)
- 有点类似于 jsp 中的 el 表达式,可以用来取参数的值并作一些基本的运算;
(2)if 判断
- if 判断拼接 where 条件存在的问题:就是可能会出现where后面直接是一个 and的情况
- 第一种方法:就是where 后面紧跟一个 1=1;
- 第二种方法:使用where 标签,使用时注意条件的后就不要写 and 了;
- 第三种方法:使用trim 标签,可以通过属性设置前缀后缀和前后缀的覆盖问题,where 前后多出的 and(or)都能解决;
- set 标签用来封装修改条件,作用就是去除 set 的时候多余的逗号,当然用 trim 标签也可以实现,与if结合使用可以实现动态更新;
2、choose 分支选择
(1)语法:choose----when----when----otherwise-----choose
(2)理解:类似于 java 中带break 的 switch语句,只匹配一个条件;
3、foreach 遍历
(1)遍历集合拼接 where 条件(如:in 集合)
- 几个常用的属性 collection、item、separator、open、close、index(map的时候就是map的key);
(2)实现数据的批量插入
- mysql 第一种:在 values 后面用 foreach 遍历拼接 sql;
- mysql 第二种:直接整个插入语句来循环,需要在数据库的 url 后面传参开启多条语句执行的支持;
- oracle 第一种:用 plsql ,在begin 和 end 中来遍历;
- oracle 第二种:循环用 select 语句将集合中的值从伪表中查出,再用查出的结果进行插入;
4、其他
(1)内置参数:
- 除了我们传入的参数,还有内置的参数,这里的内置参数可以取到也可以判断
- _parameter:封装所有的参数,传入的参数一个就是这个参数本身,传入多个参数就是一个 map;
- databaseId:全局配置文件里面配置了 databaseproviderid这里可以取到;
- _parameter 和 if结合可以用来进行 where条件的拼接;
- databaseId 和 if 结合使用可以用来在一个 select 元素里写两个数据库的 sql;
(2)bind 标签:作用就是将传入的参数赋值给一个变量方便以后的调用,连个属性name 和 value;
(3)sql 片段:
- 用 sql 标签抽取可以重用的sql 片段方便以后在其他的sql 里用include标签用id引用,如查询字段的重用;
- include 支持自定义 property ,在sql标签的内部就能用${}取来使用;