作者:田超凡
版权所有,严禁复制转载
1.MyBatis简介
MyBatis是一个优秀的JavaEE数据持久层ORM框架,它内部封装了通过JDBC访问数据库的操作,支持普通的SQL查询、存储过程和高级映射,几乎消除了所有的JDBC代码和参数的手工设置带来的SQL注入风险。其主要思想是将SQL语句从程序代码中剥离出来,单独将SQL语句定义在xml配置文件中,实现SQL的灵活配置。这样做的好处是可以在不修改程序代码的情况下,直接在配置文件中修改SQL语句,降低了程序代码和SQL语句的耦合度。
2.ORM简介
ORM指的是对象/关系映射(Object Relational Mapping),是数据持久化的一种实现方式。数据持久化指的是将内存中的数据模型转换为存储模型,以及将存储模型转换为内存中的数据模型的统称。ORM在对象模型和关系型数据库之间建立了一座桥梁,通过建立Java实体类和数据库表之间的映射关系,实现使用Java代码操作实体类的属性即可操作关联的数据库表中的数据,是一种半自动化的ORM实现。基于ORM,MyBatis在对象模型和关系型数据库的表之间建立了一座桥梁,通过MyBatis建立SQL关系映射,以便捷的实现数据的存储和管理操作。
3. MyBatis环境搭建
(1) .搭建MyBatis框架环境需要用到的Jar包
log4j-1.2.16.jar
mybatis-3.2.2-sources.jar
mybatis-3.2.2.jar
mysql-connector-java-5.1.0-bin.jar
Jar包说明:
log4j-1.2.16.jar log4j开源日志记录工具
mybatis-3.2.2.jar MyBatis核心jar包
mybatis-3.2.2-sources.jar MyBatis核心jar包的源码包
mysql-connector-java-5.1.0-bin.jar MySQL数据库驱动包
创建Java Web项目并将以上Jar包导入到项目的WEB-INF/lib目录下并进行BuildPath,可以根据需要导入MyBatis-source.jar这个源码包方便查看MyBatis框架API中定义的类和接口的相关信息。
导入MyBatis源码包方式:
Project-->Referneces Librarys-->mybatis-3.2.2.jar-->右击properties-->add attachment source-->从工作空间中选择或者从文件中的选择mybatis-3.2.2-sources.jar包-->apply save保存
(2).创建基本目录结构
src目录下:
创建Source Folder类型----resources目录:
database.properties 数据源配置文件
log4j.properties log4j日志配置文件
mybatis-config.xml MyBatis核心配置文件
dao包:存放Mapper映射器接口和SQL映射文件mapper.xml
entity包:存放实体类(pojo实体模型),需要遵循Java Bean规范
util包:存放MyBatisUtil工具类,构建MyBatis核心API实例
test包:测试类
注意:没有特殊说明,本文档总结的MyBatis框架测试都是在控制台进行,使用log4j输出日志
(2) .配置MyBatis核心配置文件mybatis-config.xml,基本配置项如下:
<configuration>
<!-- 引入数据源配置文件 -->
<properties resource="database.properties"></properties>
<!-- 配置MyBatis运行时行为,Log日志实现 -->
<settings>
<setting name="logImpl" value="LOG4J"></setting>
</settings>
<!-- 实体类指定别名 -->
<typeAliases>
<typeAlias alias="Bill" type="entity.Bill"/>
<typeAlias alias="Provider" type="entity.Provider"/>
</typeAliases>
<!-- 配置MyBatis运行时环境 -->
<environments default="environment">
<environment id="environment">
<!-- 配置事务管理器 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置数据源 -->
<dataSource type="POOLED">
<property name="driver" value="${driver}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${username}"></property>
<property name="password" value="${password}"></property>
</dataSource>
</environment>
</environments>
<!-- 引入SQL映射文件 -->
<mappers>
<mapper resource="dao/BillMapper.xml"></mapper>
<mapper resource="dao/ProviderMapper.xml"></mapper>
</mappers>
</configuration>
基本层次结构如下:
注意:MyBatis核心配置文件配置项必须遵循以下顺序配置
Configuration 根节点,管理所有MyBatis配置项
properties 可以引入在Java属性配置文件中配置的数据源文件(database.properties),也可以直接使用子元素property配置数据源
settings 修改MyBatis运行时的行为方式
typeAliases 为Java类型命名一个别名(简称)
typeHandlers 类型处理器
objectFactory 对象工厂
plugins 插件
environments 环境
Environment 环境变量
transactionManager 事务管理器
dataSource 数据源
mappers 映射器
配置项元素说明:
properties元素:描述外部化、可替代的属性。
(1)通过resource属性引入外部database.properties数据源配置文件
(2)通过定义子元素<property>直接配置数据源
settings元素:设置一些非常重要的设置选项,用于设置和改变MyBatis运行中的行为。常用配置项如下:
name属性 value属性 默认值
cacheEnabled:对在此配置文件下的所有cache进行全局性开关设置 true | false true
lazyLoadingEnabled:全局性设置懒加载,如果设置为false,则所有相关联的都会被初始化加载,即立即加载模式 true | false true
autoMappingBehavior:MyBatis对于resultMap的自动映射匹配级别 NONE | PARTIAL | FULL PARTIAL
typeAliases元素:配置类型别名,通过与MyBatis的SQL映射文件相关联,减少输入多余的完整类名,简化操作。
子元素:typeAlias
属性:
alias 类型别名
type 完整类型限定名
子元素:package
属性:name 扫描制定包下的所有JavaBean并默认设置一个别名(默为类名)
environments元素:配置MyBatis多套运行环境,如开发环境、测试环境、生产环境等,可以灵活选择不同的配置,从而将SQL映射到不同的数据库环境。
注意:必须使用default属性指定默认运行环境。
子元素:
environment:MyBatis其中一套运行环境,需要指定id属性,并确保该id属性值全局唯一。
子元素:
transactionManager:事务管理器,设置其类型为JDBC,MyBatis有两种事务管理类型,JDBC和MANAGED.直接使用JDBC的提交和回滚功能,依赖于从数据源获得连接来管理事务的生命周期。
dataSource:使用标准的JDBC数据源接口配置JDBC连接对象的资源。MyBatis提供了三种数据源类型(POOLED/UNPOOLED/JNDI),一般采用POOLED类型,表示使用数据库连接池的概念来管理数据库连接,有利于快速响应请求。
mappers:映射器,用来定义SQL映射语句,通过指定mapper子节点的resource属性引入SQL映射文件的类资源路径,如dao/UserMapper.xml
有两种方式引入SQL映射文件
(1) .类资源路径获取
<mappers>
<mapper resource=”dao/UserMapper.xml”/>
</mappers>
(2) .使用URL获取资源
<mappers>
<mapper =”file:///D:/dao/UserMapper.xml”/>
</mappers>
(3) .创建pojo模型(实体类)和dao接口(mapper映射器接口)
注意:
1.实体类必须满足JavaBean规范
2.mapper映射器接口一般与SQL映射文件同名。并且在SQL映射文件的根节点mapper的namespace属性中必须指定该SQL映射文件对应的Mapper映射器接口,并确保namespace属性值全局唯一。
3.接口中定义的方法名一般要和SQL映射文件中的元素id对应。
(4) 创建SQL映射文件
例:
<mapper namespace="dao.ProviderMapper">
<!-- 查询供应商表总记录数 -->
<select id="count" resultType="int">
SELECT COUNT(*) FROM `smbms_provider`
</select>
<!-- 查询供应商表所有记录 -->
<select id="queryAllProviders" resultType="entity.Provider">
SELECT * FROM `smbms_provider`
</select>
</mapper>
SQL映射文件常用元素介绍:
mapper:SQL映射文件的根节点,只有一个属性namespace
namespace:用于区分不同的mapper和关联Dao映射器接口
select:表示查询语句,常用属性:
id:该命名空间下唯一标识符,一般与映射器接口中的方法同名
resultType:SQL语句的返回值类型
(4).创建MyBatisUtil工具类,获取MyBatis核心API实例
private static SqlSessionFactory factory=null;
//加载factory
static
{
try
{
InputStream inputStream=Resources.getResourceAsStream("mybatis-config.xml");
factory=new SqlSessionFactoryBuilder().build(inputStream);
}
catch(Exception e)
{
e.printStackTrace();
}
}
//获取SqlSession
public static SqlSession getSqlSession()
{
//false手动提交事务
return factory.openSession(false);
}
//关闭SqlSession释放资源
public static void closeSqlSession(SqlSession sqlSession)
{
if(sqlSession!=null)
{
sqlSession.close();
}
}
(5) .创建测试类进行测试
4. MyBatis核心对象
SqlSessionFactoryBuilder
负责构建SqlSessionFactory对象,构建方式:
(1)获取MyBatis配置文件输入流对象
InputStream inputSteam=Resources.getResourceAsStream(“mybatis-config.xml”);
(2)build()方法返回SqlSessionFactory实例
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(inputStream);
拓展:build()方法常用的重载形式:
build(Reader reader)
Build(InputStream inputStream)
build(Configuration configuration)
生命周期:用过即丢,一旦创建了SqlSessionFactory对象后,这个SqlSessionFactoryBuilder类就不再需要存在了
最佳作用域:方法体,作为局部变量
SqlSessionFactory(MyBatis核心)
创建SqlSession实例的工厂。所有的MyBatis应用程序都是以SqlSessionFactory实例为核心。SqlSessionFactory实例可以通过SqlSessionFactoryBuilder对象来获得(详见上文),有了它之后,就可以通过调用他的openSession()方法获取SqlSession实例
注意:openSession()方法的参数为boolean值,SqlSessionFactory类提供了openSession()方法的重载形式。
True:自动提交事务(默认值)
False:手动提交事务
不带参数默认为true自动提交事务
一般建议手动提交事务,所以一般参数设置为false
SqlSessionFactory的生命周期和作用域:
生命周期:SqlSessionFactory实例一旦创建,就会在整个应用程序中始终存在,所有SqlSession共享一个SqlSessionFactory。没有理由销毁或者再次创建,这种存在于整个应用程序期间,并且同时只存在一个对象实例的模式就是单例模式(在应用运行期间有且仅有一个实例)
作用域:Application
SqlSession
SqlSession是用于执行持久化操作的对象,类似jdbc中的Connection,它提供了面向数据库执行SQL命令的所有方法,可以通过SqlSession实例直接执行已映射的SQL语句
SqlSession的生命周期和作用域:
生命周期:SqlSession对应着一次数据库会话,由于数据库回话不是永久的,因此SqlSession的生命周期也不应该是永久的。在每次访问数据库时都要重新创建(在一个SqlSession中可以执行多次SQL语句),但是如果关闭里SqlSession,那么就需要重新创建它。
注意:
(1)创建SqlSession对象的地方只有一个,即通过SqlSessionFactory对象的openSession()方法创建SqlSession对象。
(2)在多线程运行环境下,每个线程都有自己的SqlSession实例,SqlSession实例并不能被共享,也不是线程安全的。
作用域:Request或者方法体
(3) 使用完SqlSession后需要在finally块中关闭SqlSession对象,释放占用的内存资源。
(4) SqlSession的常用使用方式有两种:
※通过SqlSession实例直接运行已映射的SQL语句,例如:
sqlSession.selectList(“Mapper映射器包路径.方法名”);
※基于mapper接口方式操作数据
mapper接口的方法必须与SQL映射文件中SQL语句的id一一对应。
例如:
sqlSession.getMapper(UserMapper.class).findUserList();
5. MyBatis体系概述
MyBatis核心接口和类、MyBatis核心配置文件(mybatis-config.xml)、SQL映射文件(mapper.xml)
高级特性:支持动态SQL
6. SQL映射文件常用配置项
顶级配置项:
mapper 映射文件的根元素节点,只有一个属性namespace,其作用如下:
(1) .区分不同的mapper映射文件,保证namespace属性值全局唯一
(2) 绑定DAO接口(映射器接口),即面向接口编程。当namespace绑定某一接口之后,可以不用写该接口的实现类,MyBatis会通过接口的完整限定名查找到对应的Mapper配置来执行SQL语句。
注意:保证namespace的命名必须要跟接口同名
cache 配置给定命名空间的缓存
cache-ref 从其他命名空间引用缓存配置
resultMap 描述数据库结果集和对象的对应关系
sql可以重用的SQL语句块,也可以被其他语句引用。
Insert 映射插入语句
Update 映射修改语句
Delete 映射删除语句
Select 映射查询语句
属性:
id 命名空间下唯一的标识符,可以被用来引用这条语句,必须与该SQL映射文件绑定的映射器dao接口中的方法名一一对应
parameterType 表示查询语句传入参数的类型的完全限定名或别名,它支持基础数据类型和复杂数据类型。
常用类型别名:
别名 映射的类型
string String
byte Byte
long Long
short Short
int Integer
integer Integer
arraylist ArrayList
double Double
float Float
boolean Boolean
date Date
map Map
hashmap HashMap
list List
除了内建的类型别名之外,还可以在mybatis-config.xml核心配置文件中为自定义的JavaBean类指定别名(typeAliases元素),配置之后在SQL映射文件中可以直接使用别名,从而减少配置文件代码。
resultType 查询语句返回结果类型的完全限定名或别名,别名的使用方式与parameterType是一样的。
注意:
关于MyBatis的SQL映射文件中的mapper元素的namespace属性有如下要求:
(1) namespace命名必须要跟某个接口同名,同属于DAO层,代码结构上一般将该映射文件和DAO映射器接口放置在同一个package下,并且习惯上命名都是以Mapper结尾。
(2) 在不同的mapper映射文件中,子元素的id可以相同,MyBatis通过namespace和子元素的id联合进行区分。接口中的方法和SQL映射文件中SQL语句的id要一一对应。
7. SQL映射文件参数传递
(1) 基本数据类型作为参数
必须通过使用@Param注解实现
(2) 多条件查询处理方式:
*封装成JavaBean对象入参
#{对象的属性名}----------------->对象的属性值
*封装成map集合入参
#{map集合元素的key}------------>map结合元素的value
8. 使用resultMap映射查询结果集和实体类对象
注意:使用resultType属性进行自动映射时,要确保对象的属性名和查询结果集的字段名必须保持一致,如不一致,需要给查询结果集中的字段起别名,保证列名和属性一一对应
resultMap元素用来描述如何将查询结果集映射到Java对象,一般适用于两种情况:
(1) 查询结果集中的字段名和pojo属性名不一致,没有指定别名
(2) 多表连接查询
resultMap元素常用属性值和子节点:
id属性:唯一标示,此id对应select元素的resultMap属性
type属性:该resultMap的映射结果类型
result子节点:用于标识一些简单的属性,其中column属性表示从数据库中查询的字段名,property属性表示映射到pojo实体对象的哪个属性
注意:
对比select元素的resultType属性和resultMap属性
resultType直接表示返回结果类型,包括基础数据类型和复杂数据类型
resultMap则是对外部resultMap定义的引用,对应外部定义的resultMap的id,表示返回结果映射到哪一个resultMap上。它的应用场景一般是:数据库字段信息和对象属性不一致或者需要做复杂的联合查询,以便自由控制映射结果。
resultType和resultMap的关联:
在使用MyBatis框架进行查询映射的时候,其实查询出来的每个字段值都放在一个对应的Map里面,其中键是字段名,值是字段值,当select元素提供的返回类型属性是resultType时,MyBatis会将Map里面的键值对取出赋给resultType所指定的对象的属性(即调用指定的对象属性的setter方法进行填充)。因为如此,在后台就可以直接取到其对应的对象的属性值。
其实MyBatis每个查询映射的返回类型都是resultMap,只是当我们提供的返回属性是resultType时,MyBatis会自动把对应的值赋给resultType所指定的对象的属性。但是当我们提供的返回类型是resultMap的时候,因为Map不能很好地表示领域模型,我们需要通过进一步的定义把他转化为对应的实体对象。
注意:在同一个select元素中,resultType和resultMap绝对不能同时存在,只能二者选用其中之一。
9. resultMap的自动映射级别
resultMap自动映射的三个匹配级别:
NONE:禁止自动匹配
PARTIAL(默认值):自动匹配所有,有内部嵌套(association/collection)除外
FULL:自动匹配所有
配置resultMap自动映射级别:
在mybatis-config.xml核心配置文件中配置:
<settings>
<setting name=”autoMappingBehavior” value=”NONE | PARTIAL | FULL”>
</setting>
</settings>
10. MyBatis缓存
MyBatis提供了对一级缓存和二级缓存的支持
一级缓存:
一级缓存基于PerpetualCache(MyBatis自带)的HashMap本地缓存,作用范围是SqlSession域,当session被flush或者close后,该session中所有的cache缓存就会被清空
二级缓存:
二级缓存就是global caching,它超出session范围之外,可以被所有SqlSession共享,开启它仅需要在MyBatis核心配置文件mybatis-config.xml中配置即可,配置项如下:
<settings>
<setting name=”cacheEnabled” value=”true”></setting>
</settings>
在mapper映射文件中设置缓存,默认情况下没有开启缓存。
注意:global cache的作用域是针对mapper的namespace属性而言的,即只有在此namespace内的查询才能共享这个cache
<mapper namespace=”dao.UserMapper”>
<cache eviction=”FIFO” flushInterval=”60000” size=”512” readOnly=”true”/>
</mapper>
在mapper文件中配置支持cache后,如果需要对个别查询进行调整,可以单独设置cache
<select id=”findUserInfo” parameterType=”entity.User” resultMap=”queryUser” useCache=”true”>
......
</select>
11. resultMap高级结果映射
(1) .POJO持久化类定义了一个POJO类型的属性
association元素:映射到JavaBean某个复杂类型的属性,如JavaBean类型的属性,即JavaBean内部嵌套了一个JavaBean属性。
属性:
property 映射数据库列的实体对象的属性名(JavaBean属性名)
javaType JavaBean属性的类型,完整Java类名或别名
子元素:
Id
result
属性:
property 映射数据库列的实体对象的属性
column 数据库列名或别名
注意:association仅处理一对一关联关系
<resultMap id="queryAssoBill" type="Bill">
<result property="billCode" column="billCode"></result>
<result property="productName" column="productName"></result>
<result property="totalPrice" column="totalPrice"></result>
<result property="isPayment" column="isPayment"></result>
<association property="provider" javaType="Provider">
<result property="proCode" column="proCode"></result>
<result property="proName" column="proName"></result>
<result property="proContact" column="proContact"></result>
<result property="proPhone" column="proPhone"></result>
</association>
</resultMap>
(2) POJO持久化类定义了一个List集合类型的属性
collection元素:映射到JavaBean某个复杂类型的属性(集合列表List),
即在JavaBean内部嵌套了一个List集合类型的属性
属性:
property 映射数据库列的实体对象的属性(List集合属性名)
ofType List集合属性类型的完整类名或别名
子元素:
Id
result
属性:
property 映射数据库列的实体对象的属性
column 数据库列名或别名
注意:collection适用于一对多关联映射
12. 动态SQL
动态SQL是MyBatis的一个强大特性,动态SQL基于OGNL表达式,可是我们方便地在SQL语句中实现某些逻辑,提高SQL映射文件中的SQL语句编写效率
(1) .动态SQL元素
①if 利用if实现简单的条件判断
属性:
test 条件表达式
②choose(when/otherwise) 相当于Java中的switch语句,通常与when和otherwise搭配使用
属性:
test 条件表达式
③where 简化SQL语句WHERE条件判断
自动剔除多余的AND前缀
④set 解决动态更新语句
自动剔除结尾多余的,逗号
⑤trim 可以灵活地添加或去除多余关键字
prefix 前缀
prefixOverrides 忽略前缀
suffix 后缀
suffixOverrides 忽略后缀
⑥foreach 迭代一个集合,通常用于IN()子查询条件
collection:
入参为数组=====>array
入参为List集合=====>list
入参为Map=====>Map元素的键
Item: 当前迭代项
Index:每次迭代到的位置
open该语句以什么开始
separator迭代项之间使用什么作为分隔符
close该语句以什么结束
例子:
①if多条件查询
<!-- 使用if查询订单表信息 -->
<select id="findBillInfoByIF" parameterType="Bill" resultMap="queryBill">
SELECT b.*,p.`proName` FROM `smbms_bill` AS b,`smbms_provider` AS p
WHERE b.`providerId`=p.`id`
<if test="productName!=null and productName!=''">
AND b.`productName` LIKE CONCAT('%',#{productName},'%')
</if>
<if test="providerId!=null and providerId!=0">
AND b.`providerId`=#{providerId}
</if>
<if test="isPayment!=null and isPayment!=0">
AND b.`isPayment`=#{isPayment}
</if>
</select>
②If+where实现多条件查询
<!-- if+where查询供应商信息 -->
<select id="findProviderInfoByIfAndWhere" resultMap="queryProvider">
SELECT * FROM `smbms_provider`
<where>
<if test="proCode!=null and proCode!=''">
AND `proCode` LIKE CONCAT('%',#{proCode},'%')
</if>
<if test="proName!=null and proName!=''">
AND `proName` LIKE CONCAT('%',#{proName},'%')
</if>
</where>
</select>
③if+trim多条件查询
<!-- if+trim分页查询角色信息 -->
<select id="findRoleInfo" resultMap="queryRole">
SELECT * FROM `smbms_role`
<trim prefix="WHERE" prefixOverrides="and | or">
<if test="roleName!=null and roleName!=''">
AND `roleName` LIKE CONCAT('%',#{roleName},'%')
</if>
</trim>
LIMIT #{curPageNo},#{pageSize}
</select>
④if+set动态更新
<!-- if+set修改供应商表信息 -->
<update id="updateProviderInfoByIfAndSet" parameterType="Provider">
UPDATE `smbms_provider`
<set>
<if test="proCode!=null and proCode!=''">`proCode`=#{proCode},</if>
<if test="proName!=null and proName!=''">`proName`=#{proName},</if>
<if test="proDesc!=null and proDesc!=''">`proDesc`=#{proDesc},</if>
<if test="proContact!=null and proContact!=''">`proContact`=#{proContact},</if>
<if test="proPhone!=null and proPhone!=''">`proPhone`=#{proPhone},</if>
<if test="proAddress!=null and proAddress!=''">`proAddress`=#{proAddress},</if>
<if test="proFax!=null and proFax!=''">`proFax`=#{proFax},</if>
<if test="modifyBy!=null and modifyBy!=0">`modifyBy`=#{modifyBy},</if>
<if test="modifyDate!=null and modifyDate!=''">`modifyDate`=#{modifyDate},</if>
</set>
WHERE `id`=#{id}
</update>
⑤if+trim动态更新
<!-- if+trim修改供应商表信息 -->
<update id="updateProviderInfoByIfAndTrim" parameterType="Provider">
UPDATE `smbms_provider`
<trim prefix="SET" suffixOverrides="," suffix="WHERE `id`=#{id}">
<if test="proCode!=null and proCode!=''">`proCode`=#{proCode},</if>
<if test="proName!=null and proName!=''">`proName`=#{proName},</if>
<if test="proDesc!=null and proDesc!=''">`proDesc`=#{proDesc},</if>
<if test="proContact!=null and proContact!=''">`proContact`=#{proContact},</if>
<if test="proPhone!=null and proPhone!=''">`proPhone`=#{proPhone},</if>
<if test="proAddress!=null and proAddress!=''">`proAddress`=#{proAddress},</if>
<if test="proFax!=null and proFax!=''">`proFax`=#{proFax},</if>
<if test="modifyBy!=null and modifyBy!=0">`modifyBy`=#{modifyBy},</if>
<if test="modifyDate!=null and modifyDate!=''">`modifyDate`=#{modifyDate},</if>
</trim>
</update>
⑥MyBatis入参为数组(Array)类型的foreach迭代
<!-- foreach入参数组类型,查询指定供应商下的订单信息 -->
<select id="findBillInfoByArray" resultMap="queryBill">
SELECT b.*,p.`proName` FROM `smbms_bill` AS b
INNER JOIN `smbms_provider` AS p
ON b.`providerId`=p.`id`
WHERE b.`providerId` IN
<foreach collection="array" item="providerId" open="(" separator="," close=")">
#{providerId}
</foreach>
</select>
⑦MyBatis入参为List类型的foreach迭代
<!-- foreach入参list类型,查询指定供应商下的订单信息 -->
<select id="findBillInfoByList" resultMap="queryBill">
SELECT b.*,p.`proName` FROM `smbms_bill` AS b
INNER JOIN `smbms_provider` AS p
ON b.`providerId`=p.`id`
WHERE b.`providerId` IN
<foreach collection="list" item="providerId" open="(" separator="," close=")">
#{providerId}
</foreach>
</select>
⑧MyBatis多参数入参,封装成Map类型的foreach迭代
<!-- foreach入参为map类型,查询指定订单编码和供应商id下的订单信息 -->
<select id="findBillInfoByMap" resultMap="queryBill">
SELECT b.*,p.`proName` FROM `smbms_bill` AS b
INNER JOIN `smbms_provider` AS p
ON b.`providerId`=p.`id`
WHERE b.`billCode` LIKE CONCAT('%',#{billCode},'%')
AND b.`providerId` IN
<foreach collection="providerIds" item="providerId" open="(" separator="," close=")">
#{providerId}
</foreach>
</select>
⑨choose(when/otherwise)动态查询
<!-- choose(when/otherwise)查询供应商表信息 -->
<select id="findProviderInfoByChoose" resultMap="queryProvider">
SELECT * FROM `smbms_provider`
WHERE 1=1
<choose>
<when test="proCode!=null and proCode!=''">AND `proCode` LIKE CONCAT('%',#{proCode},'%')</when>
<when test="proName!=null and proName!=''">AND `proName` LIKE CONCAT('%',#{proName},'%')</when>
<when test="proContact!=null and proContact!=''">AND `proContact` LIKE CONCAT('%',#{proContact},'%')</when>
<otherwise>AND YEAR(`creationDate`)=#{creationDate}</otherwise>
</choose>
</select>
13. MyBatis实现分页
MySQL的分页是基于内存的分页,即查出来所有的记录,再按起始位置和页面容量取出结果集。
MyBatis实现分页步骤:
1. 使用聚合函数count()获得总记录数
2. 实现分页,通过LIMIT 起始位置,页面容量实现(起始位置从0开始)
例如:
<!-- if+trim分页查询角色信息 -->
<select id="findRoleInfo" resultMap="queryRole">
SELECT * FROM `smbms_role`
<trim prefix="WHERE" prefixOverrides="and | or">
<if test="roleName!=null and roleName!=''">AND `roleName` LIKE CONCAT('%',#{roleName},'%')</if>
</trim>
LIMIT #{curPageNo},#{pageSize}
</select>
参数说明:
curPageNo,起始行索引,从0开始(不是页码):
起始行索引=(当前页码-1)*页面容量
pageSize页面容量
14. MyBatis参数入参补充说明
(1)MyBatis接受的参数类型:基本类型、对象、数组、List、Map
(2)无论MyBatis的入参是哪种类型,MyBatis都会将参数放在一个Map中。
(3)对于单参数入参的情况:
入参为基本类型===>变量名作为Key,变量值作为Value
入参为对象===>对象的属性名作为Key,对象的属性值作为Value
入参为数组===>array作为Key,该数组作为Value
入参为List集合===>list作为Key,该List集合作为Value
入参为Map===>键值不变
(4).对于多参数入参的情况:
入参均为基本数据类型,需要使用@Param注解
入参为复杂数据类型(如基本数据类型和复杂数据类型混合入参),需要将参数封装为一个Map,Map的key作为键,Map的value作为值。
(5) 关于#{参数名}和${参数名}的对比说明
#{参数名}
采用预编译的方式入参,作用类似于PreparedStatement
${参数名}
采用拼接字符串的方式入参,将${参数名}解析为一个变量,有SQL注入风险,使用较少,一般适用于自定义排序字段或排序方式。
例如:
<select id=”queryUsers” resultType=”entity.User”>
SELECT * FROM `smbms_user`
ORDER BY ${orderBy} ${orderWay}
</select>
模糊查询使用#{},配合MySQL的字符串拼接函数CONCAT()使用
15. MyBatis配置文件组成结构
mybatis-config.xml是MyBatis核心配置文件,MyBatis将在启动时加载该配置文件中的配置项,该配置文件用来定义通用的共享的MyBatis相关配置信息,这是使用传统xml配置的形式,该配置文件各配置元素是有顺序要求的,集成spring或springboot后可基于注解驱动配置则免于顺序要求,mybatis-config.xml常用配置项和顺序要求如下:
configuration 根节点,管理所有MyBatis配置项
properties 可以引入在Java属性配置文件中配置的数据源文件(database.properties),也可以直接使用子元素property配置数据源
settings 修改MyBatis运行时的行为方式
typeAliases 为Java类型命名一个别名(简称)
typeHandlers 类型处理器
objectFactory 对象工厂
plugins 插件
environments 环境
Environment 环境变量
transactionManager 事务管理器
dataSource 数据源
mappers 映射器
配置项元素说明:
properties元素:描述外部化、可替代的属性。
(1)通过resource属性引入外部database.properties数据源配置文件
(2)通过定义子元素<property>直接配置数据源
settings元素:设置一些非常重要的设置选项,用于设置和改变MyBatis运行中的行为。常用配置项如下:
name属性 value属性 默认值
cacheEnabled:对在此配置文件下的所有cache进行全局性开关设置 true | false true
lazyLoadingEnabled:全局性设置懒加载,如果设置为false,则所有相关联的都会被初始化加载,即立即加载模式 true | false true
autoMappingBehavior:MyBatis对于resultMap的自动映射匹配级别 NONE | PARTIAL | FULL PARTIAL
typeAliases元素:配置类型别名,通过与MyBatis的SQL映射文件相关联,减少输入多余的完整类名,简化操作。
子元素:typeAlias
属性:
alias 类型别名
type 完整类型限定名
子元素:package
属性:name 扫描制定包下的所有JavaBean并默认设置一个别名(默为类名)
environments元素:配置MyBatis多套运行环境,如开发环境、测试环境、生产环境等,可以灵活选择不同的配置,从而将SQL映射到不同的数据库环境。
注意:必须使用default属性指定默认运行环境。
子元素:
environment:MyBatis其中一套运行环境,需要指定id属性,并确保该id属性值全局唯一。
子元素:
transactionManager:事务管理器,设置其类型为JDBC,MyBatis有两种事务管理类型,JDBC和MANAGED.直接使用JDBC的提交和回滚功能,依赖于从数据源获得连接来管理事务的生命周期。
dataSource:使用标准的JDBC数据源接口配置JDBC连接对象的资源。MyBatis提供了三种数据源类型(POOLED/UNPOOLED/JNDI),一般采用POOLED类型,表示使用数据库连接池的概念来管理数据库连接,有利于快速响应请求。
mappers:映射器,用来定义SQL映射语句,通过指定mapper子节点的resource属性引入SQL映射文件的类资源路径,如dao/UserMapper.xml
有两种方式引入SQL映射文件
(1) .类资源路径获取
<mappers>
<mapper resource=”dao/UserMapper.xml”/>
</mappers>
(2) .使用URL获取资源
<mappers>
<mapper =”file:///D:/dao/UserMapper.xml”/>
</mappers>