MyBatis学习总结
MyBatis学习总结
Mybatis简介
Mybatis是apache组织下的一个子项目。原来叫ibatis。改名为mybatis。版本比较稳定。是一个支持定制化SQL、存储过程以及高级映射的优秀的持久层框架。
Mybatis可以将向MapperedStatement中的输入参数自动进行输入映射,将查询结果集灵活映射成java对象。(输出映射)
mybatis架构图
xxx.xml :文件名可以自定义。作为mybatis的核心配置文件。配置数据源、事务等框架运行环境和映射文件的配置。
SqlSessionFactory : 会话工厂,通过核心配置文件获得 。生产SqlSession的。
SqlSession接口:会话。会话中封装了一个数据库连接。实现CRUD 操作。
Executor : 执行器。在SqlSession中操作数据库。
Mappedstatement :底层对象,操作数据库。 封装sql、输入参数、输出映射等。
输入参数:数据类型可以是:简单类型 、pojo(实体类)、hashmap
输出映射:数据类型可以是:简单类型 、pojo(实体类)、hashmap
入门程序
根据id查询用户信息
基本步骤
1. 创建java工程
2. 加入mybatis的jar包、数据库驱动包
3. 在classpath下创建log4j.properties,配置日志。
4. 在classpath下创建mybatis.xml核心配置文件,名称任意。
引用mybatis配置文件的dtd验证。
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
5. 程序编写
创建pojo类和任意名称的xml映射文件,设置dtd文件。
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
- 编写映射文件
7. 在主配置文件中加载xml映射文件
8. 测试程序
用mybatis提供的Resources类读取配置文件
用SqlSessionFactoryBuilder获得会话工厂,传入配置文件
用工厂生产SqlSession
调用SqlSession的相关方法获得结果
关闭SqlSession对象
补充导入dtd:Window->preferences->xml catalog->add
根据名称模糊查询
步骤:1.编写映射文件2.测试程序.
#{}和${}区别
#{}是占位符,防止sql注入,若入参是简单类型,#{}中可用任意值
${}表示拼接sql串,若入参是简单类型,${}中只能是value
selectOne和selectList
selectOne()查询单条记录, 也可以用selectList() , 集合中只有1条记录
selectList()查询多条记录, 不能用selectOne()替代。 异常:TooManyResultsException
录入新用户
步骤:1.编写映射文件2.测试程序.
获得自增列的值
使用<selectKey>标签实现自增列的返回
keyProperty属性:返回的主键存储在pojo中的哪个属性
order属性:selectKey相对与insert语句的执行顺序,BEFORE|AFTER
resultType属性:返回的主键类型
LAST_INSERT_ID():是mysql的函数,返回auto_increment自增列新记录id值。
如果主键是uuid:
selectKey : select uuid()
order属性:BEFORE
如果主键是oracle的序列
selectKey :SELECT seq_name.nextval FROM dual;
order属性 :BEFORE
总结
核心配置文件的基本写法。 (了解)
#{}和${}区别。
selectOne()和selectList()方法。
获得自增列的值,应用<selectKey>标签获得。
Mybatis优点:
连接数据库配置放到了配置文件。
Sql语句放到了映射文件
应用了连接池。
使用parameterType封装输入参数,进行输入映射。
使用resultType指定结果类型,自动进行输出映射。
简单。
常用类
SqlSessionFactoryBuilder类 : 是一个工具类,构建工厂的。工厂构建成功,类没用,适合在方法内部作为局部变量使用。
SqlSessionFactory 接口 :是一个工厂, 生产SqlSession的。 最佳使用范围是整个应用运行期间,可以重复使用,以单例模式出现。
SqlSession 接口 : 是一个数据库会话,操作数据库。 非线程安全 , 适合在方法内部使用。
Mybatis中Dao的开发方式
原始dao开发(掌握)
要求用户写dao时既要写dao接口,同时要写dao实现类。
需求:实现以上功能。
原始dao开发的不足:
- dao实现类中的程序有冗余,重复。 获得session,关闭session。
- 调用sql语句的statement的id被硬编码在程序中,不便维护。
Mapper代理开发(掌握)
用户写dao时,只写dao接口,框架自动根据dao接口生成代理对象。Mabatis官方推荐使用mapper代理开发。
Mapper代理开发的要求、规则:
映射文件中的mapper标签的namespace属性的值必须是mapper接口的完全路径。
mapper接口中的方法名和映射文件中的statement的id相同。
mapper接口方法的参数类型和映射文件中的parameterType的类型要相同
mapper接口方法的返回类型和映射文件中的resultType的类型相同
映射文件要和mapper接口在同一目录下且同名。
需求:实现以上所有功能。
获得mapper接口的代理对象
UserMapper userMapper = session.getMapper(UserMapper.class);
总结
查询时到底调用的是selectOne还是selectList,底层会根据方法返回值自动选择。
Mybatis传入参数时,只能传1个,会不会影响开发。不会:parameterType类型可以是简单类型 、 pojo 、map、 包装pojo
主配置文件
Mybatis主配置文件中配置框架的环境、属性等信息。
主配置文件的基本结构:
configuration
properties(属性)
settings(全局配置参数)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境集合属性对象)
environment(环境子属性对象)
transactionManager(事务管理)
dataSource(数据源)
mappers(映射器)
properties(属性)
properties 可以将属性(properties)文件中的key/value对导入到主配置文件中使用, 也可以在内部声明属性值对。
<!--
Resource属性:导入指定位置的属性文件
-->
<properties resource="com/mybatis/class4/mysql.properties">
</properties>
在主配置文件中可以使用导入的key/value对,例如在数据源配置中使用:
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
</dataSource>
在properties内部声明属性值对:
<properties resource="com/mybatis/class4/mysql.properties">
<!-- 声明属性值对 -->
<property name="key1" value="value1"/>
</properties>
读取属性顺序
读取属性时,按如下顺序读取
最先读取properties内部的属性值对,
然后继续读取resource加载属性文件中的属性值对,
最后读取parameterType传递的属性值对。
如果key已经存在,后读取会覆盖先读取的值。
Settings(配置)
Settings是用来配置mybatis框架的全局运行参数的。如:开启二级缓存、延迟加载等。参考API。
typeHandlers(类型处理器)
用于java类型和jdbc类型之间的互相映射,mybatis框架提供了足够用的类型处理器,一般不需要管。
可能要自定义类型处理器。
typeAliases(类型别名)(重点)
编写映射文件时,输入映射和输出映射必须写pojo的完全路径。可以将java类型映射到一个简单的短的别名上去。
<typeAliases>
<!-- 单个定义一个类型的别名 -->
<typeAlias type="com.mybatis.class4.UserPo" alias="user"/>
<!-- 批量定义多个类型的别名 : 指定要定义别名的类的包
框架自动扫描包中的所有类,自动定义别名 , 别名是:类名,首字母小写、大写都行。
-->
<package name="com.mybatis.class4"/>
</typeAliases>
类型别名既能用在输入参数,也能用在输出映射。
Mybatis框架内置了很多类型别名,用户可以直接用。
别名 |
映射类型 |
别名 |
映射类型 |
_byte |
byte |
long |
Long |
_long |
long |
short |
Short |
_short |
short |
int |
Integer |
_int |
int |
integer |
Integer |
_integer |
int |
double |
Double |
_double |
double |
float |
Float |
_float |
float |
boolean |
Boolean |
_boolean |
boolean |
date |
Date |
string |
String |
decimal |
BigDecimal |
byte |
Byte |
bigdecimal |
BigDecimal |
Environments(环境)
Environments是配置mybatis的环境。可以配置多个环境。一个environment就是一个环境。
<environments default="mysql">
<environment id="mysql">
</environment>
<environment id="oracle">
</environment>
</environments>
在程序中读取特定的环境。
通过SqlSessionFactoryBuilder工具类获得工厂时,调用build(Reader reader, String environment)方法获得特定的环境。
在每个environment环境中,都可以指定事务管理transactionManager和数据源dataSource。如果数据源的type属性值为POOLED,说明底层使用连接池,可以设置更多的连接属性。如:poolMaximumActiveConnections=20
Mappers
Mappers用来导入映射文件的。可以用mapper标签导入单个映射文件。也可以用package标签批量导入映射文件。
Mapper标签的属性有:
Resource属性:指定要导入的映射文件的相对路径。例:Com/a/b.xml
url属性:指定要导入的映射文件的绝对路径。 例:file:///var/AuthorMapper.xml
class属性:指定映射文件对应的mapper接口完全路径。 要求:mapper代理模式。
Package标签指定mapper接口或映射文件的包
映射文件
映射文件用来映射sql语句
映射文件的顶层标签是mapper标签,namespace属性指定当前映射文件要映射给的接口的完全路径。
输入参数映射
输入映射是输入参数的类型可以是:
简单类型
Pojo类型
在sql语句中使用${}或#{}获得属性的值,如果属性名写错。报错:
包装pojo类型
查询数据时,如果是包含多张表查询条件,这时可以使用包装对象传递输入参数。
在映射文件中使用${}或#{}获得属性的属性的属性值。
Map类型
传递给查询语句的参数类型是map类型,在sql语句中使用${}或#{}根据map中的key获得值。如果key写错,获得的值就是空。
数组类型
如果输入参数是数组类型,parameterType指定为object或arraylist,注意的是循环标签的collection属性的值必须指定为array。
<foreach collection="array" index="i" item="name" open="username in (" close=")" separator=",">
${name}
</foreach>
集合类型
如果输入参数是集合类型,parameterType指定为object或list,注意的是循环标签的collection属性的值必须指定为list。
<foreach collection="list" index="i" item="name" separator="or">
username = ${name}
</foreach>
输出结果映射
将查询到的结果集自动映射为java的对象。
resultType
能将以下类型进行输出映射:
简单类型
要求sql语句返回的必须是一行一列。如果查询到一行多列,只映射第一列的值。
Pojo类型
resultType指定的是pojo类型
自动将列名对应的值映射到同名的属性中。
Pojo集合类型
resultType指定的是集合中元素的类型。
Map类型
查询到单条纪录时,是将查询到的列名作为map的key,将查询到的值作为map的value,构成map。
用resultType进行输出映射,只有当查询的列名和pojo的属性名一致,才可以映射成功。如果属性名和列名都不一致,则不创建pojo对象。
resultMap
结果映射:能解决查询的列名和属性名不一致时映射不成功的问题。能实现一对一或一对多的关联查询。高级输出映射。
Resultmap定义
<!-- 定义resultmap
id:resultmap的编号
type:将结果映射成什么java类型
-->
<resultMap type="UserPo" id="rm8">
<!-- 定义主键列的映射
column:指定查询到的列名
property:指定pojo中的属性名
-->
<id column="ids" property="id"/>
<!-- 定义非主键列的映射 -->
<result column="uname" property="username"/>
</resultMap>
使用定义好的resultmap:
<select id="sel8" parameterType="int" resultMap="rm8">
动态sql(重点)
通过mybatis框架提供的各种标签,在映射文件中实现sql语句的动态拼接。
常用的标签有:if (choose when otherwise) where forEach
If标签
根据参数值动态生成sql语句的条件,主要做非空字符串校验。
<if test="key1!=null and key1!=''"></if>
Where标签
自动添加where关键字,且自动处理第一个and或or关键字。
Choose、when、otherwise标签
相当于switch语句,进行多重选择条件判断
Foreach标签
如果向sql中传递数组或List,使用foreach进行解析
foreach标签的属性说明:
collection属性:要循环的数组或者ist
如果数组或List是pojo的属性,collection的值是属性名
如果直接传递数组为参数,collection的值是array
如果直接传递List为参数,collection的值是list
index属性:定义保存数组的下标的变量名。
item属性:定义数组当前元素的变量的名称,随意定义
open属性:定义循环开始时的字符
close属性:定义循环结束时的字符
separator属性:每次循环的中间分隔符
sql片段
sql片段可以将公共的一段sql,单独封装,在需要的地方引用。
Sql中可将重复的片段提取出来,需要时用include标签引用,达到sql重用的目的。
<sql id="user_col">id, username uname </sql>
<include refid="user_col"/>
关联查询
一对一查询
需求:查询一个订单信息,同时查询出下订单的用户信息。
resultType方式(了解)
确定主表订单表和关联表用户表,写sql语句,根据sql查询到的列,定义pojo继承字段较多的po类,实现映射文件的select和mapper接口中的方法,测试结果。
resultType:能实现简单输出映射, 不支持延迟加载。
resultMap方式
在订单的pojo对象中,添加下单人对象属性。
用resultMap实现结果映射。在resultmap中用association标签实现一对一关联映射。
<!-- 利用association标签实现 1对1关联映射
property:将关联查询的用户信息放到哪个属性中
javaType:指定属性的类型
-->
<association property="user" javaType="UserPo">
<id column="user_id" property="id"/>
<result column="username" property="username"/>
</association>
resutMap能实现高级输出映射,支持延迟加载。
一对多查询
需求:查询一个指定的订单,同时查询出订单对应的明细。
在订单pojo对象中添加订单明细集合属性。
用resultmap实现查询结果的映射,在resultmap中用collection标签实现一对多关联映射。
<!-- collection标签实现一对多关联查询
property:在订单中订单明细集合的属性名
ofType:指定集合的元素类型
-->
<collection property="details" ofType="OrderDetailPo">
<id column="odid" property="id"></id>
<result column="items_id" property="itemsId"/>
</collection>
resultMap是可以继承另一个resultMap
多对多查询
需求:查询一个用户信息,同时查出用户购买的商品信息。
在用户pojo中添加订单列表属性。在订单pojo中添加订单明细列表属性。在订单明细pojo中添加商品属性。
resultMap定义。
延迟加载
查询数据时,先从单表中查询。当需要其他表数据时再从其他表中查数据。
Mybatis框架默认不开启延迟加载,要打开必须在settings中配置。
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
查询数据时,如果使用resultType,没有延迟加载功能。使用resultMap的association和collecation标签实现延迟加载。
<!--
column:指定外键列列名
select:指定延迟加载时要调用的sql语句,或statment的 id , 如果在其他namespace中 , namespace+id -->
<association property="user" javaType="UserPo"
column="user_id"
select="com.mybatis.class6.UserMapper.selectById">
</association>
<!-- 延迟加载 -->
<collection property="details" ofType="OrderDetailPo" column="id"
select="com.mybatis.class6.OrderDetailMapper.selectByOrderId">
</collection>
缓存
mybatis提供查询缓存,用于减轻数据压力,提高数据库性能。
查询缓存分一级缓存和二级缓存。
一级缓存
一级缓存是SqlSession级别的缓存,默认是打开。
二级缓存
二级缓存是mapper级别的,多个SqlSession操作同一个Mapper中的sql语句时可以共用二级缓存,是跨多个SqlSession的。
二级缓存默认不打开,在settings中设置二级缓存打开<setting name="cacheEnabled" value="true"/>。
在要缓存的mapper映射文件中应用二级缓存<cache/>
把pojo对象加序列化接口Serializable。
在select标签中设置useCache=false可以禁用当前select语句的二级缓存,默认情况是true。
清空(刷新)缓存
如果不及时刷新缓存,可能从缓存中拿到的数据是错误数据,有可能其他用户已经修改了数据库数据。
① 执行了增、删、改②或事务进行commit或rollback③或 执行SqlSession对象的clearCache方法都可以清空缓存。
Insert、update、delete标签中有flushCache属性,指定是否刷新缓存。默认值是true
集成ehcache缓存框架
Ehcache是一个第三方的分布式的缓存框架。能在分布式系统中统一管理缓存缓存信息。
Mybatis没有分布缓存的功能,要集成其他第三方分布式缓存框架。
- 导入jar包
ehcache-core-x.x.x.jar mybatis-ehcache-1.x.x.jar
- 在映射文件中配置
Mybatis框架的二级缓存由Cache接口实现,默认有PerpetualCache实现类。指定二级缓存使用的类是ehcache的实现类EhcacheCache。
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
- 添加ehcache框架的配置文件。
- 测试
Mybatis执行存储过程
在数据库中准备存储过程
调用无OUT参数的过程
在映射文件中写statement时,要设置statementType属性值为CALLABLE,在statement中调用存储过程。
CALL userInsert(#{username},#{birthday,jdbcType=DATE})
{CALL userInsert(#{username},#{birthday,jdbcType=DATE})}
<![CDATA[{CALL userInsert(#{username},#{birthday,jdbcType=DATE})}]]>
如果参数值可能为null,参数中必须指定jdbcType,值是org.apache.ibatis.type.JdbcType枚举的值
调用有OUT参数的过程
call selectNameById(#{id,mode=IN,jdbcType=INTEGER},#{result,mode=OUT,jdbcType=VARCHAR})
mode的取值有三种:IN,OUT,INOUT
parameterType参数须为对象或Map,若为对象则相关属性需要提供setter方法。
返回结果集
创建存储过程
CREATE OR REPLACE PROCEDURE selectByName(uname IN VARCHAR2,rst OUT SYS_REFCURSOR)
IS
BEGIN
OPEN rst FOR SELECT * FROM "USER" WHERE username = uname;
END;
编写statement
<select id="selectByName" parameterType="map" statementType="CALLABLE">
call selectByName(#{name},#{rst,mode=OUT,jdbcType=CURSOR,javaType=java.sql.ResultSet,resultMap=rm1})
</select>
编程测试
Map<String, Object> map = new HashMap<>();
map.put("name", "hanmeimei");
userMapper.selectByName(map);
System.out.println(map.get("rst"));
以上自己学习的一些总结的要点,有不到之处请大家批评指正!!!