一、什么是Mybatis
Mybatis 是一个持久层的框架(dao),他是一个半自动ORM(对象关系映射)框架,它是对jdbc操作的一次封装
ORM: Object Relational Mapping,简称ORM
O:对象
R:关系(对象和表关系)
M:映射(就是把表中的字段的值 映射到 对象的属性中)
半自动:就是需要自己书写sql语句
如何使用:
1、导入Mybatis的架包
2、配置Mybatis中的核心配置文件(有两种):1:核心配置文件(mybatis-config.xml):配置数据源(数据库),配置缓存、日志、别名 2:映射文件(xxxxMapper.xml):配置对象与表之间的关系。然后通过sql语句来映射字段和对象属性的值
二.mybatis config文件
typeAliases 类型别名是为 Java 类型设置一个短的名字。它只和 XML 配置有关,存在的意义仅在于用来减少类完全限定名的冗余。例如:
<typeAliases>
<typeAlias alias="Author" type="domain.blog.Author"/>
<typeAlias alias="Blog" type="domain.blog.Blog"/>
<typeAlias alias="Comment" type="domain.blog.Comment"/>
<typeAlias alias="Post" type="domain.blog.Post"/>
<typeAlias alias="Section" type="domain.blog.Section"/>
<typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>
三.插件(plugins)
MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:
- Executor (update, query, flushStatements, commit, rollback,getTransaction, close, isClosed)
- ParameterHandler (getParameterObject, setParameters)
- ResultSetHandler (handleResultSets, handleOutputParameters)
- StatementHandler (prepare, parameterize, batch, update, query)
下面通过自定义插件来打印出查询的sql语句:
@Intercepts({@Signature(type = Executor.class,
method = "query",
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})})
public class JunliPlugin implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
BoundSql boundSql = mappedStatement.getBoundSql(invocation.getArgs()[1]);
System.out.println(String.format("plugin output sql = %s , param=%s", boundSql.getSql(),boundSql.getParameterObject()));
return invocation.proceed();
}
@Override
public Object plugin(Object o) {
return Plugin.wrap(o,this);
}
@Override
public void setProperties(Properties properties) {
}
配置插件:
<plugins>
<plugin interceptor="com.junli.mybatis.demo.mybatis.JunliPlugin"/>
</plugins>
四.映射器(mappers)
既然 MyBatis 的行为已经由上述元素配置完了,我们现在就要定义 SQL 映射语句了。但是首先我们需要告诉 MyBatis 到哪里去找到这些语句。 Java 在自动查找这方面没有提供一个很好的方法,所以最佳的方式是告诉 MyBatis 到哪里去找映射文件。你可以使用相对于类路径的资源引用, 或完全限定资源定位符(包括 file:/// 的 URL),或类名和包名等。例如:
<mappers>
<mapper resource="xml/TestMapper.xml"/>
<mapper resource="xml/PostsMapper.xml"/>
</mappers>
五.Mapper XML 文件 解读
MyBatis 的真正强大在于它的映射语句,也是它的魔力所在。由于它的异常强大,映射器的 XML 文件就显得相对简单。如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。MyBatis 就是针对 SQL 构建的,并且比普通的方法做的更好。
SQL映射文件有很少的几个顶级元素(按照它们应该被定义的顺序):
cache – 给定命名空间的缓存配置。
cache-ref – 其他命名空间缓存配置的引用。
resultType:是用来处理简单对象的一种方式
resultMap:是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象。
sql – 可被其他语句引用的可重用语句块。
insert – 映射插入语句
update – 映射更新语句
delete – 映射删除语句
select – 映射查询语句
resultMap
constructor - 用于在实例化类时,注入结果到构造方法中
idArg - ID 参数;标记出作为 ID 的结果可以帮助提高整体性能
arg - 将被注入到构造方法的一个普通结果
id – 一个 ID 结果;标记出作为 ID 的结果可以帮助提高整体性能
result – 注入到字段或 JavaBean 属性的普通结果
association – 一个复杂类型的关联;许多结果将包装成这种类型
嵌套结果映射 – 关联可以指定为一个 resultMap 元素,或者引用一个
collection – 一个复杂类型的集合嵌套结果映射 – 集合可以指定为一个 resultMap 元素,或者引用一个
discriminator – 使用结果值来决定使用哪个 resultMap.
resultMap 关联查询.
关联的嵌套结果实现:
<resultMap id="commodityBeanMap" type="com.lovo.supplier.bean.sales.CommodityBean">
<id property="goodsId" column="goodsId"></id>
<result property="goodsSales" column="goodsSales"></result>
<result property="goodsMoney" column="goodsMoney"></result>
<result property="goodsState" column="goodsState"></result>
<association property="supplyBean" javaType="com.lovo.supplier.bean.offerAndSupply.SupplyBean">
<id property="supplyId" column="supplyId"></id>
<result property="supplyType" column="supplyType"></result>
<result property="srttlemeentTime" column="srttlemeentTime"></result>
<result property="indentId" column="indentId"></result>
<association property="targetGoodsBean" javaType="com.lovo.supplier.bean.supplierManager.TargetGoodsBean">
<id property="id" column="id"></id>
<result property="goodsName" column="goodsName"></result>
<result property="goodsNum" column="goodsNum"></result>
<result property="goodsProce" column="goodsProce"></result>
<result property="goodsTotalPrice" column="goodsTotalPrice"></result>
<result property="supplier_name" column="supplierName"></result>
</association>
</association>
</resultMap>
<select id="findByGoodsId" resultMap="commodityBeanMap">
select comm.goods_id as goodsId,
sup.indent_id as indentId,
comm.goods_sales as goodsSales,
comm.goods_state as goodsState,
comm.goods_money as goodsMoney,
sup.supply_id as supplyId,
ta.id as id,
ta.goodsName as goodsName,
ta.goodsNum as goodsNum,
ta.goodsProce as goodsProce,
ta.goodsTotalPrice as goodsTotalPrice
from t_commodity as comm
left join t_supply as sup on comm.indent_id=sup.indent_id
left join target as ta on ta.id=sup.id
where goods_id=#{goodsId}
</select>
缓存:
Mybatis中有一级缓存和二级缓存,默认情况下一级缓存是开启的,而且是不能关闭的。一级缓存是指SqlSession级别的缓存,当在同一个SqlSession中进行相同的SQL语句查询时,第二次以后的查询不会从数据库查询,而是直接从缓存中获取,一级缓存最多缓存1024条SQL。二级缓存是指可以跨SqlSession的缓存。
Mybatis中进行SQL查询是通过org.apache.ibatis.executor.Executor接口进行的,总体来讲,它一共有两类实现,一类是BaseExecutor,一类是CachingExecutor。前者是非启用二级缓存时使用的,而后者是采用的装饰器模式,在启用了二级缓存时使用,当二级缓存没有命中时,底层还是通过BaseExecutor来实现的。
一级缓存
一级缓存是默认启用的,在BaseExecutor的query()方法中实现,底层默认使用的是PerpetualCache实现,PerpetualCache采用HashMap存储数据。一级缓存会在进行增、删、改操作时进行清除。
二级缓存
二级缓存是默认是关闭的,如想取消,则可以通过Mybatis配置文件中的元素下的子元素来指定cacheEnabled为false。
<settings>
<setting name="cacheEnabled" value="false" />
</settings>
我们要想使用二级缓存,是需要在对应的Mapper.xml文件中定义其中的查询语句需要使用哪个cache来缓存数据的。这有两种方式可以定义,一种是通过cache元素定义,一种是通过cache-ref元素来定义。但是需要注意的是对于同一个Mapper来讲,它只能使用一个Cache,当同时使用了和时使用定义的优先级更高。Mapper使用的Cache是与我们的Mapper对应的namespace绑定的,一个namespace最多只会有一个Cache与其绑定。
六.动态 SQL
MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦。例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。动态 SQL 元素和 JSTL 或基于类似 XML 的文本处理器相似.MyBatis 采用功能强大的基于 OGNL 的表达式来淘汰其它大部分元素。
if
<if test="title != null">
AND title like #{title}
</if>
choose (when, otherwise)
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
trim (where, set)
<where>
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</where>
<trim prefix="WHERE" prefixOverrides="AND |OR ">
...
</trim>
<set>
<if test="username != null">username=#{username},</if>
<if test="password != null">password=#{password},</if>
<if test="email != null">email=#{email},</if>
<if test="bio != null">bio=#{bio}</if>
</set>
foreach
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>