转载

MyBatis基本知识

简介

  • MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。
  • mybatis与hibernate不同
    不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句。mybatis可以通过XML或注解方式灵活配置要运行的sql语句,并将java对象和sql语句映射生成最终执行的sql,最后将sql执行的结果再映射生成java对象。
  • Mybatis学习门槛低,程序员直接编写原生态sql,可严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件则需要自定义多套sql映射文件,工作量大。

jdbc编程问题

  1. 频繁创建、关闭数据连接,太消耗资源
  2. Sql语句存在硬编码,不利于维护
  3. Sql参数设置硬编码,不利于维护
  4. 结果集获取与遍历复杂,存在硬编码,不利于维护,期望能够查询后返回一个java对象

MyBatis

  1. 使用数据库连接池。
  2. 将Sql语句配置在XXXXmapper.xml文件中与java代码分离。
  3. Mybatis自动将java对象映射至sql语句,通过statement中的parameterType定义输入参数的类型。
  4. Mybatis自动将sql执行结果映射至java对象,通过statement中的resultType定义输出结果的类型。

JDBC代码

public static void main(String[] args) {
     Connection connection = null;
     PreparedStatement preparedStatement = null;
     ResultSet resultSet = null;
 
     try {
       // 加载数据库驱动
       Class.forName("com.mysql.jdbc.Driver");
 
       // 通过驱动管理类获取数据库链接
       connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "root");
       // 定义sql语句 ?表示占位符
       String sql = "select * from user where username = ?";
       // 获取预处理statement
       preparedStatement = connection.prepareStatement(sql);
       // 设置参数,第一个参数为sql语句中参数的序号(从1开始),第二个参数为设置的参数值
       preparedStatement.setString(1, "王五");
       // 向数据库发出sql执行查询,查询出结果集
       resultSet = preparedStatement.executeQuery();
       // 遍历查询结果集
       while (resultSet.next()) {
          System.out.println(resultSet.getString("id") + "  " + resultSet.getString("username"));
       }
     } catch (Exception e) {
       e.printStackTrace();
     } finally {
       // 释放资源
       if (resultSet != null) {
          try {
            resultSet.close();
          } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
          }
       }
       if (preparedStatement != null) {
          try {
            preparedStatement.close();
          } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
          }
       }
       if (connection != null) {
          try {
            connection.close();
          } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
          }
       }
     }
  }

### #{ }和${ }

  • #{}:占位符,可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换。#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值,#{}括号中可以是value或其它名称。
  • /${}:拼接sql串,将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, /${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,/${}括号中只能是value。

SqlMapConfig.xml配置文件

  1. SqlMapConfig.xml中配置的内容和顺序如下:

    properties(属性)

    settings(全局配置参数)

    typeAliases(类型别名)

    typeHandlers(类型处理器)

    objectFactory(对象工厂)

    plugins(插件)

    environments(环境集合属性对象)

    environment(环境子属性对象)

    transactionManager(事务管理)
     dataSource(数据源)

    mappers(映射器)

  2. 自定义别名:

    <typeAliases>
         <!-- 单个别名定义 -->
         <typeAlias alias="user" type="cn.mybatis.pojo.User" />
         <!-- 批量别名定义,扫描整个包下的类,别名为类名(大小写不敏感) -->
         <package name="cn.mybatis.pojo" />
         <package name="其它包" />
      </typeAliases>
  3. mappers(映射器)

    Mapper配置的几种方法:

    • 使用相对于类路径的资源

      <mapper resource="sqlmap/User.xml" />
    • 使用mapper接口类路径。注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。

      <mapper class="cn.mybatis.mapper.UserMapper"/>
    • 注册指定包下的所有mapper接口。注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。

      <package name="cn.mybatis.mapper"/>

输出映射

<!-- resultMap最终还是要将结果映射到pojo上,type就是指定映射到哪一个pojo -->
  <!-- id:设置ResultMap的id -->
  <resultMap type="order" id="orderResultMap">
    <!-- 定义主键 ,非常重要。如果是多个字段,则定义多个id -->
    <!-- property:主键在pojo中的属性名 -->
    <!-- column:主键在数据库中的列名 -->
    <id property="id" column="id" />
 
    <!-- 定义普通属性 -->
    <result property="userId" column="user_id" />
    <result property="number" column="number" />
    <result property="createtime" column="createtime" />
    <result property="note" column="note" />
  </resultMap>
 
  <!-- 查询所有的订单数据 -->
  <select id="queryOrderAll" resultMap="orderResultMap">
    SELECT id, user_id,
    number,
    createtime, note FROM `order`
  </select>

动态sql

  1. if标签

    <!-- 根据条件查询用户 -->
    <select id="queryUserByWhere" parameterType="user" resultType="user">
      SELECT id, username, birthday, sex, address FROM `user`
      WHERE 1=1
      <if test="sex != null and sex != ''">
        AND sex = #{sex}
      </if>
      <if test="username != null and username != ''">
        AND username LIKE
        '%${username}%'
      </if>
    </select>
  2. where标签

    <!-- 根据条件查询用户 -->
    <select id="queryUserByWhere" parameterType="user" resultType="user">
      SELECT id, username, birthday, sex, address FROM `user`
    <!-- where标签可以自动添加where,同时处理sql语句中第一个and关键字 -->
      <where>
        <if test="sex != null">
           AND sex = #{sex}
        </if>
        <if test="username != null and username != ''">
           AND username LIKE
           '%${username}%'
        </if>
      </where>
    </select>
  3. sql片段

    <!-- 根据条件查询用户 -->
    <select id="queryUserByWhere" parameterType="user" resultType="user">
      <!-- SELECT id, username, birthday, sex, address FROM `user` -->
      <!-- 使用include标签加载sql片段;refid是sql片段id -->
      SELECT <include refid="userFields" /> FROM `user`
      <!-- where标签可以自动添加where关键字,同时处理sql语句中第一个and关键字 -->
      <where>
        <if test="sex != null">
           AND sex = #{sex}
        </if>
        <if test="username != null and username != ''">
           AND username LIKE
           '%${username}%'
        </if>
      </where>
    </select>
     
    <!-- 声明sql片段 -->
    <sql id="userFields">
      id, username, birthday, sex, address
    </sql>
  4. foreach标签

    <!-- 根据ids查询用户 -->
    <select id="queryUserByIds" parameterType="queryVo" resultType="user">
      SELECT * FROM `user`
      <where>
        <!-- foreach标签,进行遍历 -->
        <!-- collection:遍历的集合,这里是QueryVo的ids属性 -->
        <!-- item:遍历的项目,可以随便写,,但是和后面的#{}里面要一致 -->
        <!-- open:在前面添加的sql片段 -->
        <!-- close:在结尾处添加的sql片段 -->
        <!-- separator:指定遍历的元素之间使用的分隔符 -->
        <foreach collection="ids" item="item" open="id IN (" close=")"
           separator=",">
           #{item}
        </foreach>
      </where>
    </select>

一对多查询

  1. java对象

    public class User {
        private int id;
        private String userName;
        private String sex;
        private String address;
        private Date birthDay;
    
        private List<Order> orders;
  2. xml配置

    <resultMap type="user" id="userOrderResultMap">
      <id property="id" column="id" />
      <result property="username" column="username" />
      <result property="birthday" column="birthday" />
      <result property="sex" column="sex" />
      <result property="address" column="address" />
     
      <!-- 配置一对多的关系 -->
      <collection property="orders" javaType="list" ofType="order">
        <!-- 配置主键,是关联Order的唯一标识 -->
        <id property="id" column="oid" />
        <result property="number" column="number" />
        <result property="createtime" column="createtime" />
        <result property="note" column="note" />
      </collection>
    </resultMap>
     
    <!-- 一对多关联,查询订单同时查询该用户下的订单 -->
    <select id="queryUserOrder" resultMap="userOrderResultMap">
      SELECT
      u.id,  u.username,  u.birthday,  u.sex,  u.address,  o.id oid,  o.number,  o.createtime,  o.note
      FROM  `user` u  LEFT JOIN `order` o ON u.id = o.user_id
    </select>
原文  https://segmentfault.com/a/1190000022441674
正文到此结束
Loading...