Mybatis2-基础回顾及使用

一:配置文件解析

 

SqlMapConfig.xml:

1、environments标签

2、mapper标签

通常用来加载mapper.xml, 当然也可以加载Mappper接口等等。 用法如下

使⽤相对于类路径的资源引⽤,例如:
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
使⽤完全限定资源定位符( URL ),例如:
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
使⽤映射器接⼝实现类的完全限定类名,例如:
<mapper class="org.mybatis.builder.AuthorMapper"/>
将包内的映射器接⼝实现全部注册为映射器,例如:
<package name="org.mybatis.builder"/>
3、 Properties 标签

将db配置信息单独存放在properties文件,然后使用该标签加载使用

4、typeAliases标签 

 取别名的。比如:

 常用的java类也有对应的别名

 Mapper.xml:

 动态映射sql语句,入参和返回值。 常规增删改查标签和简单的单表的写法这里就不说了。

 说一下复杂映射:

一对一

Order中有User:

public class Order {
    private Integer id;
    private String orderTime;
    private Double total;

    // 表明该订单属于哪个用户
    private User user;
}
<mapper namespace="com.lagou.mapper.IOrderMapper">

    <resultMap id="orderMap" type="com.lagou.pojo.Order">
        <result property="id" column="id"></result>
        <result property="orderTime" column="orderTime"></result>
        <result property="total" column="total"></result>

        <association property="user" javaType="com.lagou.pojo.User">
            <result property="id" column="uid"></result>
            <result property="username" column="username"></result>
        </association>
    </resultMap>


    <!--resultMap:手动来配置实体属性与表字段的映射关系-->
    <select id="findOrderAndUser" resultMap="orderMap">
        select * from orders o,user u where o.uid = u.id
    </select>

</mapper>

 一对多

一个user有多个订单

public class User {

    private int id;
    private String username;
    private String password;
    private Date birthday;
    //代表当前⽤户具备哪些订单
    private List<Order> orderList;
}
<resultMap id="userMap" type="com.lagou.pojo.User">
    <result property="id" column="uid"></result>
    <result property="username" column="username"></result>
    <collection property="orderList" ofType="com.lagou.pojo.Order">
        <result property="id" column="id"></result>
        <result property="orderTime" column="orderTime"></result>
        <result property="total" column="total"></result>
    </collection>
</resultMap>

<select id="findAll" resultMap="userMap">
    select * from user u left join orders o on u.id = o.uid
</select>

多对多 

一个用户多个角色,一个角色属于多个用户

public class Role {

    private Integer id;
    private String roleName;
    private String roleDesc;

}

<resultMap id="userRoleMap" type="com.lagou.pojo.User">
    <result property="id" column="userid"></result>
    <result property="username" column="username"></result>
    <collection property="roleList" ofType="com.lagou.pojo.Role">
        <result property="id" column="roleid"></result>
        <result property="roleName" column="roleName"></result>
        <result property="roleDesc" column="roleDesc"></result>
    </collection>
</resultMap>


<select id="findAllUserAndRole" resultMap="userRoleMap">
    select * from user u left join sys_user_role ur on u.id = ur.userid
                   left join sys_role r on r.id = ur.roleid
</select>

其实resultMap 就是一对多的方写法。 因为站着user或者role的角度上,都是一对多。

上面都是mapper.xml的配置文件开发,mybatis还支持注解开发。

二:注解开发 

注解要在Mapper接口上写,所以在SqlMapConfig.xml中,需要引入的是Mapper接口而不是mapper.xml。

<mappers>
        <!--扫描使⽤注解的类所在的包 -->
        <package name = "com.lagou.mapper" ></package>
</mappers>

User相关查询:

public interface IUserMapper {

    //一对多:查询所有用户、同时查询每个用户关联的订单信息
    @Select("select * from user")
    @Results({
            @Result(property = "id",column = "id"),
            @Result(property = "username",column = "username"),
            @Result(property = "orderList",column = "id",javaType = List.class,
                many=@Many(select = "com.lagou.mapper.IOrderMapper.findOrderByUid"))
    })
    public List<User> findAll();

    //多对多:查询所有用户、同时查询每个用户关联的角色信息
    @Select("select * from user")
    @Results({
            @Result(property = "id",column = "id"),
            @Result(property = "username",column = "username"),
            @Result(property = "roleList",column = "id",javaType = List.class,
             many = @Many(select = "com.lagou.mapper.IRoleMapper.findRoleByUid"))
    })
    public List<User> findAllUserAndRole();


    //添加用户
    @Insert("insert into user values(#{id},#{username})")
    public void addUser(User user);

    //更新用户
    @Update("update user set username = #{username} where id = #{id}")
    public void updateUser(User user);

    //查询用户
    @Select("select * from user")
    public List<User> selectUser();

    //删除用户
    @Delete("delete from user where id = #{id}")
    public void deleteUser(Integer id);

    //根据id查询用户
    @Options(useCache = true)
    @Select({"select * from user where id = #{id}"})
    public User findUserById(Integer id);
    

}

Order相关查询:

public interface IOrderMapper {

    //一对一:查询订单的同时还查询该订单所属的用户

    @Results({
            @Result(property = "id",column = "id"),
            @Result(property = "orderTime",column = "orderTime"),
            @Result(property = "total",column = "total"),
            @Result(property = "user",column = "uid",javaType = User.class,
                    one=@One(select = "com.lagou.mapper.IUserMapper.findUserById"))
    })
    @Select("select * from orders")
    public List<Order> findOrderAndUser();


    @Select("select * from orders where uid = #{uid}")
    public List<Order> findOrderByUid(Integer uid);
    
}

三:缓存 

1、一级缓存(sqlSession级别的缓存)

使用同一个sqlSession执行多次相同sql查询, 只有第一次会请求数据库。 当然,如果sqlSession对同一数据有写操作并提交了事务,会清空缓存。

既然是sqlSession级别的缓存,查找sqlSession的方法,只有一个在操作缓存:

clearCache();

依次跟踪发现调用链:

底层是Perpetualcache, 点进去发现缓存就是一个hashmap,也就是调用map.clear()方法。 

每个sqlSession都会为其创建一个本地的map作为缓存,是在执行器Executor中,调用BaseExecutor的createCacheKey方法创建的:

 

 经过几个update方法把每一项信息放到了updateList中,确定了唯一。 缓存什么时候使用呢?

 

在 List<E>查询方法中,先从缓存取,没有就查数据库,再放到缓存中 。

2、二级缓存:

二级缓存就是针对同一个namespace下,也就是同一个mapper.xml中,多个sqlSession共享同一个sql的缓存(sqlSession动态代理创建mapper,也就是多个mapper共享)。

 当然,如果过程中某一个mapper执行了commit,会清空缓存。

二级缓存需要手动开启:

在全局sqlMapConfig.xml中

<!--开启⼆级缓存-->

<settings>
        <setting name = "cacheEnabled" value = "true" />
</settings>

在某个mapper.xml中 

<!-- 开启⼆级缓存 -->
<cache></cache>

看起来是个空标签,默认使用了PerpetualCache

a、实现了Cache接口,我们也可以实现该接口自定义缓存,在typemapper.xml中就不再是空标签了,需要type指定。

b、二级缓存也是个hashmap。

c、对缓存的实体需要实现Serializable,因为二级缓存不一定只存储在内存中,还可以存在redis或者其他磁盘介质,就需要序列化与反序列化了。 比如,我们使用type指定二级缓存使用Redis来存储。

<cache type = "org.mybatis.caches.redis.RedisCache" />

另外,还可以对某个statement禁用使用缓存或者刷新缓存:

useCache为false代表该语句每次都查数据库,不会使用二级缓存(默认true);

 flushCache为false代表commit后,不会刷新缓存,会产生脏读(默认true);

四:插件

mybatis对持久层的操作,主要是借助四个核心对象:

执⾏器 Executor:
        update、 query commit rollback 等⽅法
SQL 语法构建器 StatementHandler :
        prepare、 parameterize batch updates query 等⽅ 法
参数处理器 ParameterHandler :
        getParameterObject、 setParameters ⽅法
结果集处理器 ResultSetHandler :
        handleResultSets、 handleOutputParameters 等⽅法

当然,并不是直接使用这几个对象操作,而是通过很多插件对这几个对象,通过jdk动态代理生成代理对象,对方法进行扩展。

这些插件就是一系列的拦截器注意:是mybatis自己的拦截器,不是springmvc的拦截器)。

比如,对ParameterHandler的使用,拦截器是如何工作的:

首先,容器启动时,mybatis会将所有的拦截器读取,并设置到全局配置类Configuration的拦截器链中。 

其次,Configuration中提供了创建ParameterHandler的方法

如上,拦截器连中每个拦截器,都调用了plugin方法对target做处理。

Plugin是一个实现了InvocationHandler的类,也就是JDK动态代理的实现

 wrap方法中,会判断当前interceptor中,是否对当前target做拦截,如果是,创建target的代理对象;如果否,直接返回原生的target。 

假如这时候有一个拦截器,配置了拦截ParameterHandler的方法,这里就会对ParameterHandler生成代理对象。 后续调用方法时,就会进入invoke方法。 invoke方法中,又调用了当前interceptor的intercept方法,实现增强:

这时候,如果拦截器链中多个拦截器都生效,最后一个拦截器处理后,生成了一个经过层层代理的终极代理对象:

总结来说:

        1、全局配置类提供了创建四大对象的方法。

        2、在具体创建某个对象时,会调用所有interceptor的wrap方法,如果某个interceptor发现自己需要拦截当前目标对象,就为目标创建代理。

        3、代理调用方法时,通过invoke回调到interceptor的intercept方法中,实现逻辑的增强。

下面自定义一个拦截器:

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.*;
import java.sql.Connection;
import java.util.Properties;

@Intercepts({   //注意看这个⼤花括号,也就这说这⾥可以定义多个@Signature对多个地⽅拦截,都⽤这个拦截器
        @Signature (type = StatementHandler .class , //这是指拦截哪个接⼝
                method = "prepare",     //这个接⼝内的哪个⽅法名,不要拼错了
                args = { Connection.class, Integer .class}),       // 这是拦截的⽅法的⼊参,按顺序写。如果⽅法重载,要通过⽅法名和⼊参来确定
        })
public class MyPlugin implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
         //增强逻辑
        System.out.println("对⽅法进⾏了增强....");
        //执⾏原⽅法
        return invocation.proceed(); 
    }

    @Override
    public Object plugin(Object target) {
        System.out.println("⽬标对象:" + target);
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        System.out.println("插件配置的初始化参数:" + properties);
    }
}

其实就是实现了mybatis中的Interceptor接口,重写逻辑。  并在类上使用@Intercepts注解配置要拦截的类和方法。

将Myplugin配置到配置文件中:

<plugins>
        
<plugin interceptor = "com.example.demo.interceptor.MyPlugin " >
        <!--配置参数 -->
        <property name = "name" value = "Bob" />
</plugin>
</plugins>

其实mybatis中有两个插件会经常使用。 分页插件PageHelper和通用插件Mapper

一个是分页用的,一个是提供mapper基本的增删改查方法。 具体使用这里不说了。

好了,mybatis基本功能就这些,下一篇说一下mybatis-plus

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值