Java之Mybatis框架

Mybatis简介

Mybatis是一个Apache下的开源项目,后来转到谷歌旗下 2013年迁移到GitHub上
是一个超轻量级的半自动ORM框架
其核心是
    输入映射 
        将参数映射到sql语句中(JDBC中的参数替换)
        输入映射支持的类型 八大基础数据类型 list map  POJO 包装类型
        包装类型可以直接通过对象导航的方式不断往下获取
            例如:#{user.name}

    输出映射 (JDBC ResultSet到对象的映射)
        输出映射支持的类型 八大基础数据类型 list map  POJO
        输出包装类型时 需要自动映射字段
Mybatis帮我们管理事务,开发人员只需要关注具体sql语句即可(sql语句需要自己写 半自动)

Mybatis与hibernate
    1.Mybatis需要手写sql 适用于需求变化频繁场景
    2.切换数据库成本较高 通常需要重写一遍sql语句
    3.不是一个完全的ORM映射 无法实现面向对象操作数据库
    4.体积更小 学习难度更低

    1.hibernate与数据库的关联性几乎没有 随时可以切换方言
    2.更加完整的ORM映射 可以不编写sql语句
    3.可以自动生成表结构 从实体类映射关联关系
    4.体积大 学习过程更长

Mybatis环境搭建

1.下载jar包
2.添加jar到工程中
    mybatis核心包 依赖lib中的依赖包 连接数据库包
3.编写核心配置文件
    没有命名规范
    配置数据源的db.properties
4.编写Mapper文件
    创建对应的数据库和表
    添加主配置文件到mapper中
5.获取session进行操作
6.关闭资源

核心配置文件SqlMapConfig.xml

<?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配置文件 必须放到src下 不需要指定classpath -->
    <properties resource="db.properties"></properties>

<!-- 当前为开发环境 -->
  <environments default="development">
    <environment id="development">
    <!-- 事务管理 -->
      <transactionManager type="JDBC"/>
      <!-- 数据源 -->
      <dataSource type="POOLED">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
  </environments>

  <!-- 映射文件 -->
  <mappers>
    <!-- 方式一 resource指定相对路径 -->
    <mapper resource="com/lanou/bean/User.xml"/>
    <mapper resource="com/lanou/dao/UserDao.xml"/>
    <mapper resource="com/lanou/dao/DogDao.xml"/>

    <!-- 方式二 指定与映射文件关联的那个接口类名 要求映射文件和接口名字必须相同 在同一级目录 -->
    <mapper class="com.lanou.dao.UserDao"/>
    <!-- <mapper url=""/> -->

    <!-- 方式三 指定扫描某个包下以及子孙包下所有映射文件
            该方式要求 映射文件名与接口名一致
    -->
    <!-- <package name="com/lanou/dao"/> -->
  </mappers>
</configuration>

映射文件

<?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">
<!-- 与sql进行映射 这里写的全都是实现业务的sql语句
    有可能多个mapper中有相同id 所以使用namespace区分
    必填参数
-->
<mapper namespace="test">
    <!-- 根据id获取User 
        id用来标识这个sql语句
        parameterType 指定输入参数的类型
        resultType 输出结果的类型
    -->
    <select id="findUserById" parameterType="Integer" resultType="com.lanou.bean.User">
        <!-- 原生sql语句 
            #{}代表占位符 等同于?
            括号中的内容可以随便写 不能不写
        -->
        select * from user where id=#{id}
    </select>

    <!-- 
        "%${value}%"
        如果当前参数需要拼接到字符串中就使用${value} 
        如果只有只一个参数 value是固定的
        因为#{xx} 会在字符串左右加上引号
        "%#{xx}%" == "%"xx"%"
        resultType 是结果的泛型 如果有多个结果 自动封装list
    -->
    <select id="searchByName" parameterType="String" resultType="com.lanou.bean.User">
        select * from user where name like "%"#{value}"%"
    </select>

    <!-- 添加新数据
     insert中不需要声明返回类型 因为只有Integer
        仅支持一个参数 参数比较复杂就直接传对象 或者map
        获取属性 或者map 通过#{属性名} 或 #{key名} 
    -->
    <insert id="add" parameterType="com.lanou.bean.User">
        insert into user values(null,#{name},#{address},#{sex},#{phone},#{age})
    </insert>

    <!-- 添加新数据并获得id  放到对象中 -->
    <insert id="insertNewUser" parameterType="com.lanou.bean.User" useGeneratedKeys="true" keyProperty="id">
        insert into user values(null,#{name},#{address},#{sex},#{phone},#{age})
    </insert>
</mapper>

获取session进行操作

// 构建器
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
// 读取配置文件
InputStream input = Resources.getResourceAsStream("SqlMapConfig.xml");
// 获取会话工厂
SqlSessionFactory factory = builder.build(input);
// 获取会话
SqlSession session = factory.openSession();
// CRUD 注意 除了查询操作 都需要提交事务 因为默认是不自动提交

Mybatis动态代理接口开发

在传统分层结构中 有大量的dao层实现类 随着项目的扩展 这些类文件会越来越多 不方便维护
Mybatis提供了一种dao层的解决方案
    纯接口开发
    只有接口 没有实现类 Mybatis自动为接口生成代理对象 完成实现类的封装
    实现原理:
        生成代理对象 实现目标接口 并在代理对象中 
        通过mapper读取配置信息 生成相应的实现代码

之前手动创建实现类,手动调用mapper中定义好的sql语句
之后Mybatis根据接口创建实现类 在实现类中自动调用mapper中定义好的sql语句

具体操作
1.创建接口 定义需要的方法

public interface UserDao {
    public User selectUserById(int id);
}

2.创建 编写映射文件mapper

<?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">
  <!-- 1.动态代理开发时 命名空间必须指定对应的接口 -->
<mapper namespace="com.lanou.dao.UserDao">
    <!-- 
        2.id必须和方法名保持一致 大小写必须一模一样
        3.返回值类型也必须一样
        4.参数与接口方法中一致
    -->
    <select id="selectUserById" parameterType="int" resultType="com.lanou.bean.User">
        select * from User where id = #{id}
    </select>
</mapper>

3.把映射文件注册到主配置文件

<mapper resource="com/lanou/dao/UserDao.xml"/>

4.通过session获取接口实现对象

// 获取代理对象
UserDao dao = session.getMapper(UserDao.class);
User user = dao.selectUserById(1);
System.out.println(user);

理解纯接口开发原理

加载配置文件发现有个UserDao.xml需要映射 创建UserDao等实现类
    UserDao dao = new UserDao() {
        @Override
        public User selectUserById(int id) {
            // 内部其实调用mapper定义的sql方法
            return session.selectOne("com.lanou.dao.UserDao.selectUserById", id);
        }
    };
    System.out.println(dao.selectUserById(5));

动态SQL

当我们传的参数是一个数组时
java中没有对应包装类型
可以写Object 也可以不写
parameterType作用其实是用来规范书写 怕你传错类型
遍历数组时参数名字是固定的 array
遍历list时参数名字固定是list

Mybatis参数映射的原理
    其实是把你传过来的参数 转成map 以键值对的方式传递

常用标签
    if 条件判断
    where 拼接多个参数 会自动去除第一个and
    foreach 遍历集合
    sql  定义sql片段
    include 配合sql一起使用

如果有很多sql重复 没有必要每次写 可以进行抽取

<sql id="selectUser">
    select * from user
</sql>

根据姓名和性别

<!-- 根据姓名和性别 -->
<select id="getUser" parameterType="User" resultType="User">
    <include refid="selectUser"/>
    <!-- where标签的作用 执行内部的逻辑并拼接到外部的sql中 会自动删除第一个and -->
    <where>
        <!-- if标签 注意多条件 用and而不是&& -->
        <if test="name != null and name != ''">
            and name=#{name} 
        </if>
        <if test="sex != null and sex != ''">
            and sex=#{sex}
        </if>
    </where>
</select>

根据一堆id查询

<!--
    foreach标签用来遍历参数
    collection 指定被遍历的集合
    item 每一次遍历得到的变量
    separator 分隔符
    open 开始标记
    close 结束标记
-->
<select id="selectUserByIds" parameterType="java.util.List" resultType="User">
    <include refid="selectUser"/> where
        id in
        <foreach collection="list" item="item" separator="," open="(" close=")">
            #{item}
        </foreach> 
</select>

Mybatis的关联查询

一对一

orders表和user表 一个订单只有一个用户 从订单角度出发 是一对一关系

实现获取订单时 自动获取user
1.Orders类中声明User类型属性

private User user;

2.在接口中声明对应的查询方法

public interface OrdersDao {
    public List<Orders> getOrders();
}

3.在mapper中实现sql语句

<select id="getOrders" resultType="Orders" resultMap="OrdersMap">
    select *,o.name o_name,o.id o_id,u.id u_id,u.name u_name from user u right join orders o on u.id=o.userid
</select>

4.手动映射列名到属性名

<!-- 当数据库类名与实体属性名不对应 就使用resultMap手动映射 -->
<resultMap type="Orders" id="OrdersMap" autoMapping="true">
    <!-- 把o_name的值映射到name属性上 -->
    <result property="name" column="o_name"/>
    <result property="id" column="o_id"/>
    <!-- 该标签用来映射关联对象  -->
    <association property="user" autoMapping="true" javaType="User">
        <result property="name" column="u_name"/>
        <result property="id" column="u_id"/>
    </association>
</resultMap>

一对多

一个用户有多个订单 从用户角度出发 是一对多关系

实现在查询user数据时 自动查询出对应的Orders数据
1.User类中声list类型属性

private List<Orders> orders;

2.在接口中声明对应的查询方法

public List<User> getUsers();

3.在mapper中实现sql语句

<select id="getUsers" resultType="User" resultMap="UserMap">
    select *,o.name o_name,o.id o_id,u.id u_id,u.name u_name from user u left join orders o on u.id=o.userid
</select>

4.手动映射列名到属性名

<resultMap type="User" id="UserMap" autoMapping="true">
    <result property="name" column="u_name"/>
    <result property="id" column="u_id"/>
    <collection property="orders" ofType="Orders" autoMapping="true">
        <result property="name" column="o_name"/>
        <result property="id" column="o_id"/>
    </collection>
</resultMap>

总结

手动映射的时候 AutoMapping 设为true 可以自动将列名与属性名对应数据映射
一对一 javaType用来指定关联对象的类型 必须写 否则空指针异常
一对多 ofType用来指定集合内元素的类型 必须写 否则空指针异常

多对多

现有 groups 和 user
需求 查询user 同时查询相关的groups
需求 查询groups 同时查询相关的user
多对多是一对多的特例(两个多对一) Mybatis中实现方式与一对多一样
唯一的区别是 sql语句不同 需要查三个表(中间表)
  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值