MyBatis 详解

摘要:MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以对配置和原生 Map 使用简单的 XML 或注解,将接口和 Java 的 POJO 映射成数据库中的记录。那么她究竟是什么?

学习大纲如下:

  • MyBatis 概念?Mybatis 的版本管理,Jar 包;
  • MyBatis 官方和入门实例基于 XML 配置;
  • MyBatis 入门实例注解配置;
  • MyBatis 入门实例 一对一;
  • MyBatis 入门实例 一对多,多对一;
  • MyBatis 入门实例 多对多;
  • Mybatis 和 Hibernate 的对比;
  • MyBatis 框架的优缺点及其适用场合。

一、MyBatis 概念

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。

二、Mybatis 的版本管理和 Jar 包

安装

要使用 MyBatis, 只需将 mybatis-x.x.x.jar 文件置于 classpath 中即可。

注:其中 x.x.x:代表您所使用的时候的 MyBatis 最新版本。

截止到笔者发稿前,目前的最新版本是:3.4.7-SNAPSHOT。

如果使用 Maven 来构建项目,则需将下面的 dependency 代码置于 pom.xml 文件中:

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>x.x.x</version>
</dependency>

注意:其中 x.x.x 代表您所使用的时候的 MyBatis 最新版本。

三、MyBatis 官方和入门实例基于 XML 配置

我们知道:每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为中心,SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先定制的 Configuration 的实例构建出 SqlSessionFactory 的实例。

所以我们可以通过下面这个常用的示例了解到 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>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>  <!-- 后面:Array老师详细解析此处 -->
      <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>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>

很明显可以看出:

包含了数据源(DataSource)的链接信息和事务管理器(TransactionManager),这都是我们日常研发中常用的。其中:

   <transactionManager type="JDBC"/>
3.1 事务管理器
  1. JDBC:这个配置直接简单使用了 JDBC 的提交和回滚设置。它依赖于从数据源得到的连接来管理事务范围。
  2. MANAGED:这个配置几乎没做什么。它从来不提交或回滚一个连接。而它会让容器来管理事务的整个生命周期。

默认情况下,它会关闭连接。然而一些容器并不希望这样,因此如果你需要从连接中停止它,就可以将 closeConnection 属性设置为 false,比如:

            <transactionManager type="MANAGED">
                <property name="closeConnection" value="false"/>
            </transactionManager>

总而言之,MyBatis 管理事务是分为两种方式:

  1. 使用 JDBC 的事务管理机制,就是利用 java.sql.Connection 对象完成对事务的提交
  2. 使用 MANAGED 的事务管理机制,这种机制 MyBatis 自身不会去实现事务管理,而是让程序的容器(JBOSS、WebLogic)来实现对事务的管理
3.2 代码演示

(大家先整体感知一下,不要在意具体的业务逻辑怎么使用。整体通过下面的代码感受一下 MyBatis 的魅力为先。)

我们接下来:可以看看真实项目的代码示例:(节选)

如果 SSM 整合的话(SpringMVC 4 + MyBatis 3 + Spring 4),可以参考另外一篇 chat:http://gitbook.cn/gitchat/activity/5a618f2b99d4bd32a9872b68

SSM 一起的话,配置交给 Spring,那么我们的实际配置如下:

3.2.1 mybatis-config.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>
     <settings>
         <setting name="logImpl" value="STDOUT_LOGGING"/>
     </settings>
<!-- 配置分页插件,如果不设计分页,下面的可以不用写 -->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageHelper">
            <!-- 配置数据库方言,选定项目所用的数据库 -->
            <property name="dialect" value="mysql"/>
        </plugin>
    </plugins>


</configuration>
3.2.2 spring-mybatis.xml

其中 Spring 管理的 xml 如下:

 <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
        <!-- 1.配置数据源: -->
        <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
             <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
             <property name="url" value="jdbc:mysql://localhost:3306/array"></property> 
             <property name="username" value="root"></property>
             <property name="password" value="1111"></property>
        </bean>

        <!-- 2.整合MyBatis配置文件 -->
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
             <!-- 2.1关联数据源 -->
             <property name="dataSource" ref="dataSource"></property>
             <!-- 2.2扫描MyBatis的在mapper包中的xml 和扫描MyBatis的配置文件-->
             <property name="mapperLocations" value="classpath:com/array/mapper/*.xml"></property>
             <property name="configLocation" value="classpath:config/mybatis-config.xml"></property>
        </bean>
        <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
             <property name="basePackage" value="com/array/dao"></property>
             <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
        </bean>

        <!-- 3.事务管理管理器 -->
        <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
        <!-- 4.声明式事务  引用上面定义的事务管理器-->
        <tx:annotation-driven transaction-manager="txManager"/>
        <!-- 5.加载日志文件等配置文件 -->
        <bean id="" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
             <property name="locations">
                <list>
                    <value>classpath:config/log4j.properties</value>
                </list>
             </property>
        </bean>

</beans>        
3.2.3 mapper 层

增删改查的 MyBatis 的 xml 版本解析:

<?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" >
<mapper namespace="com.array.dao.GirlsMapper" >
  <resultMap id="BaseResultMap" type="com.array.model.Girls" >
    <id column="id" property="id" jdbcType="INTEGER" />
    <result column="sname" property="sname" jdbcType="VARCHAR" />
    <result column="cometime" property="cometime" jdbcType="VARCHAR" />
    <result column="age" property="age" jdbcType="INTEGER" />
    <result column="maxscore" property="maxscore" jdbcType="INTEGER" />
    <result column="minscore" property="minscore" jdbcType="VARCHAR" />
  </resultMap>
  <sql id="Base_Column_List" >
    id, sname, cometime, age, maxscore, minscore
  </sql>
  <!-- 通过id查询对象-- >
  <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
    select 
    <include refid="Base_Column_List" />
    from girls
    where id = #{id,jdbcType=INTEGER}
  </select>
 <!-- 通过id删除对象-- >
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
    delete from girls
    where id = #{id,jdbcType=INTEGER}
  </delete>
 <!-- 通过id插入对象-- >
  <insert id="insert" parameterType="com.array.model.Girls" >
    insert into girls (id, sname, cometime, 
      age, maxscore, minscore
      )
    values (#{id,jdbcType=INTEGER}, #{sname,jdbcType=VARCHAR}, #{cometime,jdbcType=VARCHAR}, 
      #{age,jdbcType=INTEGER}, #{maxscore,jdbcType=INTEGER}, #{minscore,jdbcType=VARCHAR}
      )
  </insert>
  <insert id="insertSelective" parameterType="com.array.model.Girls" >
    insert into girls
    <trim prefix="(" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        id,
      </if>
      <if test="sname != null" >
        sname,
      </if>
      <if test="cometime != null" >
        cometime,
      </if>
      <if test="age != null" >
        age,
      </if>
      <if test="maxscore != null" >
        maxscore,
      </if>
      <if test="minscore != null" >
        minscore,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        #{id,jdbcType=INTEGER},
      </if>
      <if test="sname != null" >
        #{sname,jdbcType=VARCHAR},
      </if>
      <if test="cometime != null" >
        #{cometime,jdbcType=VARCHAR},
      </if>
      <if test="age != null" >
        #{age,jdbcType=INTEGER},
      </if>
      <if test="maxscore != null" >
        #{maxscore,jdbcType=INTEGER},
      </if>
      <if test="minscore != null" >
        #{minscore,jdbcType=VARCHAR},
      </if>
    </trim>
  </insert>
 <!-- 更新对象-- >
  <update id="updateByPrimaryKeySelective" parameterType="com.array.model.Girls" >
    update girls
    <set >
      <if test="sname != null" >
        sname = #{sname,jdbcType=VARCHAR},
      </if>
      <if test="cometime != null" >
        cometime = #{cometime,jdbcType=VARCHAR},
      </if>
      <if test="age != null" >
        age = #{age,jdbcType=INTEGER},
      </if>
      <if test="maxscore != null" >
        maxscore = #{maxscore,jdbcType=INTEGER},
      </if>
      <if test="minscore != null" >
        minscore = #{minscore,jdbcType=VARCHAR},
      </if>
    </set>
    where id = #{id,jdbcType=INTEGER}
  </update>
  <update id="updateByPrimaryKey" parameterType="com.array.model.Girls" >
    update girls
    set sname = #{sname,jdbcType=VARCHAR},
      cometime = #{cometime,jdbcType=VARCHAR},
      age = #{age,jdbcType=INTEGER},
      maxscore = #{maxscore,jdbcType=INTEGER},
      minscore = #{minscore,jdbcType=VARCHAR}
    where id = #{id,jdbcType=INTEGER}
  </update>
  <!-- 查询秀女列表 -->
  <select id="getAll" resultMap="BaseResultMap">
      select * from girls
  </select>
   <select id="toUpdateByid" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
    select 
    <include refid="Base_Column_List" />
    from girls
    where id = #{id,jdbcType=INTEGER}
  </select>
  <update id="doUpdateByid" parameterType="com.array.model.Girls" >
    update girls
    set sname = #{sname,jdbcType=VARCHAR},
      cometime = #{cometime,jdbcType=VARCHAR},
      age = #{age,jdbcType=INTEGER},
      maxscore = #{maxscore,jdbcType=INTEGER},
      minscore = #{minscore,jdbcType=VARCHAR}
    where id = #{id,jdbcType=INTEGER}
  </update>
</mapper>
3.2.4 bean 层

而我们操作的实体类如下:

package com.array.model;

public class Girls {
    private Integer id;

    private String sname;

    private String cometime;

    private Integer age;

    private Integer maxscore;

    private String minscore;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getSname() {
        return sname;
    }

    public void setSname(String sname) {
        this.sname = sname == null ? null : sname.trim();
    }

    public String getCometime() {
        return cometime;
    }

    public void setCometime(String cometime) {
        this.cometime = cometime == null ? null : cometime.trim();
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Integer getMaxscore() {
        return maxscore;
    }

    public void setMaxscore(Integer maxscore) {
        this.maxscore = maxscore;
    }

    public String getMinscore() {
        return minscore;
    }

    public void setMinscore(String minscore) {
        this.minscore = minscore == null ? null : minscore.trim();
    }
}
3.2.5 dao 层

我们针对 xml 进行封装供给 Java 调用的 mapper 类如下:

package com.array.dao;

import java.util.List;

import com.array.model.Girls;

public interface GirlsMapper {
        int deleteByPrimaryKey(Integer id);

    int insert(Girls record);
    //对应xml中的插入
    int insertSelective(Girls record);

    Girls selectByPrimaryKey(Integer id);
    //更新
    int updateBy PrimaryKeySelective(Girls record);

    int updateByPrimaryKey(Girls record);
    // 查询所有
    List<Girls> getAll();
    // 通过id更新
    Girls toUpdateByid(Integer sid);

    int doUpdateByid(Girls g);   
}
3.2.6 controller 层

也就是我们常用的 rest 接口层:

package com.array.controller;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.array.model.Girls;
import com.array.model.Pie;
import com.array.service.GirlsService;
import com.array.utils.PagedResult;
import com.google.gson.Gson;

/**
 * 宫女入册的增删改查控制类
 */
@Controller
public class GirlsController {

    @Autowired
    private GirlsService girlsService;




    /**
     * 查询所有姓氏的宫女列表
     */
    @RequestMapping(value="getAllOne.do",produces="application/json;charset=utf-8")
    @ResponseBody
    public ModelAndView getAllOne(HttpServletRequest resquest) {
        ModelAndView mv = new ModelAndView();
        List<Girls> findAllList =  girlsService.getAll();
        //resquest.setAttribute("findAllList", findAllList);
        mv.addObject("findAllList", findAllList);
        mv.setViewName("list"); 

        return mv;

    }

    /**
     * 查询所有姓氏的宫女列表 json
     */
    @RequestMapping(value="getAllTwo.do",produces="application/json;charset=utf-8")
    @ResponseBody
    public String getAllTwo(HttpServletRequest resquest) {

        List<Girls> findAllList =  girlsService.getAll();
        Gson gson = new Gson();
        String json = gson.toJson(findAllList);
        return json;

    }
    /**
     * 1.线传统分页
     *  设置分页的默认值
     */
    @RequestMapping(value="getAllByPage.do",produces="application/json;charset=utf-8")
    public ModelAndView getAllByPage(@RequestParam(value="pageNumber",defaultValue="1")Integer pageNumber,
            @RequestParam(value="pageSize",defaultValue="2")Integer pageSize){

        ModelAndView mv = new ModelAndView();
        // 当前页和每页的条数  
        // 传入数据到分页工具类
        PagedResult<Girls> pageResult = girlsService.getAllByPage(pageNumber,pageSize);
        // 数据传递到前台页面展示层
        mv.addObject("pageResult", pageResult);
        // 跳转页面
        mv.setViewName("listpage");

        return mv;

    }


    /**
     * 秀女入宫插入操作
     * 使用ajax,所以要用String
     */
    @RequestMapping(value="insert.do",produces="application/json;charset=utf-8")
    @ResponseBody
    public String  insert(Girls g) {

        int  i = girlsService.insert(g);
        if(i>0) {
            return "yes";
        } else {
            return "no";
        }

    }

    /**
     * 秀女的删除后台操作
     * 使用ajax
     */
    @RequestMapping(value="del.do",produces="application/json;charset=utf-8")
    @ResponseBody
    public String del(String id) {
        int i = girlsService.del(id);
        if(i>0) {
            return "yes";
        } else {
            return "no";
        }
    }

    /**
     * 更新操作
     * 回显示
     */
    @RequestMapping(value="toUpdateByid.do",produces="application/json;charset=utf-8")
    @ResponseBody
    public ModelAndView toUpdateByid(String id) {
        ModelAndView mv = new ModelAndView();
        Girls girls = girlsService.toUpdateByid(id);
        mv.addObject("girls", girls);
        mv.setViewName("toupdate");
        return mv; 

    }

    /**
     * 更新操作
     */
    @RequestMapping(value="doUpdateByid.do",produces="application/json;charset=utf-8")
    @ResponseBody
    public String doUpdateByid(Girls g) {

        int i = girlsService.doUpdateByid(g);
        if(i>0) {
            return "yes";
        } else {
            return "no";
        }
    }

    /*
     * 玫瑰图
     */
    @RequestMapping("getAllByPie.do")
    @ResponseBody
    public String getAllByPie() {
        List<Girls> glist = girlsService.getAll();
        List<Pie> plist = new ArrayList<Pie>();
        for (Girls girls : glist) {
            Pie pie = new Pie();
            pie.setValue(girls.getAge().toString());
            pie.setName(girls.getSname());
            plist.add(pie);
        }
        Gson gson = new Gson();
        String json = gson.toJson(plist);
        return json;
    }
}

总结:我们通过上面的例子很清楚的看到,最终我们还是去写自己的 SQL 从而达到了 CRUD 的目的。这也是 Hibernate 完全封装所不能办到的。缺点是:xml 相对繁琐。

四、MyBatis 入门实例注解配置

和上面的基本一样,但是我们无需创建繁琐的 mapper 的 xml。

<?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" >
<mapper namespace="com.array.dao.GirlsMapper" >
  <resultMap id="BaseResultMap" type="com.array.model.Girls" >
    <id column="id" property="id" jdbcType="INTEGER" />
    <result column="sname" property="sname" jdbcType="VARCHAR" />
    <result column="cometime" property="cometime" jdbcType="VARCHAR" />
    <result column="age" property="age" jdbcType="INTEGER" />
    <result column="maxscore" property="maxscore" jdbcType="INTEGER" />
    <result column="minscore" property="minscore" jdbcType="VARCHAR" />
  </resultMap>
  <sql id="Base_Column_List" >
    id, sname, cometime, age, maxscore, minscore
  </sql>
  <!-- 通过id查询对象-- >
  <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
    select 
    <include refid="Base_Column_List" />
    from girls
    where id = #{id,jdbcType=INTEGER}
  </select>
 <!-- 通过id删除对象-- >
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
    delete from girls
    where id = #{id,jdbcType=INTEGER}
  </delete>
 <!-- 通过id插入对象-- >
  <insert id="insert" parameterType="com.array.model.Girls" >
    insert into girls (id, sname, cometime, 
      age, maxscore, minscore
      )
    values (#{id,jdbcType=INTEGER}, #{sname,jdbcType=VARCHAR}, #{cometime,jdbcType=VARCHAR}, 
      #{age,jdbcType=INTEGER}, #{maxscore,jdbcType=INTEGER}, #{minscore,jdbcType=VARCHAR}
      )
  </insert>
  <insert id="insertSelective" parameterType="com.array.model.Girls" >
    insert into girls
    <trim prefix="(" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        id,
      </if>
      <if test="sname != null" >
        sname,
      </if>
      <if test="cometime != null" >
        cometime,
      </if>
      <if test="age != null" >
        age,
      </if>
      <if test="maxscore != null" >
        maxscore,
      </if>
      <if test="minscore != null" >
        minscore,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        #{id,jdbcType=INTEGER},
      </if>
      <if test="sname != null" >
        #{sname,jdbcType=VARCHAR},
      </if>
      <if test="cometime != null" >
        #{cometime,jdbcType=VARCHAR},
      </if>
      <if test="age != null" >
        #{age,jdbcType=INTEGER},
      </if>
      <if test="maxscore != null" >
        #{maxscore,jdbcType=INTEGER},
      </if>
      <if test="minscore != null" >
        #{minscore,jdbcType=VARCHAR},
      </if>
    </trim>
  </insert>
 <!-- 更新对象-- >
  <update id="updateByPrimaryKeySelective" parameterType="com.array.model.Girls" >
    update girls
    <set >
      <if test="sname != null" >
        sname = #{sname,jdbcType=VARCHAR},
      </if>
      <if test="cometime != null" >
        cometime = #{cometime,jdbcType=VARCHAR},
      </if>
      <if test="age != null" >
        age = #{age,jdbcType=INTEGER},
      </if>
      <if test="maxscore != null" >
        maxscore = #{maxscore,jdbcType=INTEGER},
      </if>
      <if test="minscore != null" >
        minscore = #{minscore,jdbcType=VARCHAR},
      </if>
    </set>
    where id = #{id,jdbcType=INTEGER}
  </update>
  <update id="updateByPrimaryKey" parameterType="com.array.model.Girls" >
    update girls
    set sname = #{sname,jdbcType=VARCHAR},
      cometime = #{cometime,jdbcType=VARCHAR},
      age = #{age,jdbcType=INTEGER},
      maxscore = #{maxscore,jdbcType=INTEGER},
      minscore = #{minscore,jdbcType=VARCHAR}
    where id = #{id,jdbcType=INTEGER}
  </update>
  <!-- 查询秀女列表 -->
  <select id="getAll" resultMap="BaseResultMap">
      select * from girls
  </select>
   <select id="toUpdateByid" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
    select 
    <include refid="Base_Column_List" />
    from girls
    where id = #{id,jdbcType=INTEGER}
  </select>
  <update id="doUpdateByid" parameterType="com.array.model.Girls" >
    update girls
    set sname = #{sname,jdbcType=VARCHAR},
      cometime = #{cometime,jdbcType=VARCHAR},
      age = #{age,jdbcType=INTEGER},
      maxscore = #{maxscore,jdbcType=INTEGER},
      minscore = #{minscore,jdbcType=VARCHAR}
    where id = #{id,jdbcType=INTEGER}
  </update>
</mapper>

以上的 xml 如果使用注解的话,是无需创建的。

4.1 注解的魅力在哪儿?

我们可以通过这个 dao 层入手:看下面每个 CRUD 上面的增加的部分,注解

package com.array.dao;

import java.util.List;

import com.array.model.Girls;

public interface GirlsMapper {

    @Delete("delete from vwhere id=#{id}")
    int deleteByPrimaryKey(Integer id);

    @Insert("insert into girls (id,sname,cometime,age,maxscore,minscore) values(#{id},#{sname},#{cometime},#{age},#{maxscore},#{minscore})")
    int insert(Girls record);

    int insertSelective(Girls record);

    @Select("select * from girls where id= #{id}")
    Girls selectByPrimaryKey(Integer id);

    int updateByPrimaryKeySelective(Girls record);

    int updateByPrimaryKey(Girls record);

    List<Girls> getAll();
    @Update("update girls set sname=#{pname},age=#{age} where id = #{id}")
    Girls toUpdateByid(Integer sid);

    int doUpdateByid(Girls g);   
}

其他的同 xml 相通即可。

五、MyBatis 入门实例:一对一

经典案例:老师和班级,一个班主任只属于一个班级,一个班级也只能有一个班主任。

xml 的使用如下:

<?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"> 
<!--  为这个mapper指定一个唯一的namespace,namespace的值习惯上设置成包名+sql映射文件名,这样保证了namespace的值是唯一的-->
<mapper namespace="com.array.mybatis.onetoone.ClassMapper">

<!--   嵌套结果:使用封装联表查询的数据(去除重复的数据)
         select * from class a, teacher t where a.teacher_id=t.t_id and a.c_id=1
     -->

    <select id="getClass" parameterType="int" resultMap="getClassMap">
        select * from class a, teacher t  where a.teacher_id = t.t_id and      a.teacher_id=#{id}
    </select>

    <!-- resultMap:映射实体类和字段之间的一一对应的关系 -->
    <resultMap type="Classes" id="getClassMap">
        <id property="id" column="c_id"/>   
        <result property="name" column="c_name"/>
        <association property="teacher" javaType="Teacher">   
            <id property="id" column="t_id"/>
            <result property="name" column="t_name"/>
        </association>
    </resultMap> 
</mapper>

六、MyBatis 入门实例:一对多

经典案例:一个班级里面对应多个学生,这是一对多;反过来,多个学生对应一个班级,这是多对一。

我们可以创建 ArrayClass 和 Stu 两个类来说明:

public class Stu {
    private int sid;
    private String sname;
    private ArrayClass classes;
    public int getSid() {
        return sid;
    }
    public void setSid(int sid) {
        this.sid = sid;
    }
    public String getSname() {
        return sname;
    }
    public void setSname(String sname) {
        this.sname = sname;
    }
    public Classes getClasses() {
        return classes;
    }
    public void setClasses(Classes classes) {
        this.classes = classes;
    }


}

对应的 ArrayClass .java 如下:

public class ArrayClass {
    private int cid;
    private String cname;
    private List<Stu> stu;  // 以集合的形式呈现

    public int getCid() {
        return cid;
    }
    public void setCid(int cid) {
        this.cid = cid;
    }
    public String getCname() {
        return cname;
    }
    public void setCname(String cname) {
        this.cname = cname;
    }
    public List<Stu> getStu() {
        return stu;
    }
    public void setStu(List<Stu> stu) {
        this.stu = stu;
    }

}

那么我们一对多的 xml 对应关系就如下:

<?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">
<mapper namespace="com.array.onetomany.ArrayClassMapper">
    <select id="getClass" resultMap="getMap">
        select * from class c,stu s where s.cid=c.cid and c.cid=#{cid}
    </select>
    <resultMap type="com.array.onetomany.ArrayClass" id="getMap">
        <id column="cid" property="cid"></id>
        <result column="cname" property="cname"/>
        <collection property="stu" ofType="com.array.onetomany.Stu">
            <id column="sid" property="sid"/>
            <result column="sname" property="sname"/>
        </collection>
    </resultMap>

</mapper>

总结:上面的 xml 重点在于 <collection> 这个是集合,相当于 list 的象征。

七、MyBatis 入门实例:多对一

通过上面的例子,我们很容易得出,多个学生属于一个班级(跨班此处不考虑)。那么对应的 xml 如下:

<?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">
<mapper namespace="com.array.onetomany.StuMapper">
    <select id="getStudents" resultMap="getStuMap">
        select * from classes c,student s where s.cid=c.cid and s.sid=#{sid}
    </select>
    <resultMap type="com.array.onetomany.Stu" id="getStuMap">
        <id column="sid" property="sid"></id>
        <result column="sname" property="sname"/>
        <association property="classes" javaType="com.array.onetomany.ArrayClass">
            <id column="cid" property="cid"/>
            <result column="cname" property="cname"/>
        </association>
    </resultMap>

</mapper>

总结:上面的 xml 重点在于 <association> 这个是集合,相当于一个对象的象征。

八、MyBatis 入门实例:多对多

MyBatis3.0 添加了 association 和 collection 标签专门用于对多个相关实体类数据进行级联查询,但仍不支持多个相关实体类数据的级联保存和级联删除操作。因此在进行实体类多对多映射表设计时,需要专门建立一个关联对象类对相关实体类的关联关系进行描述。下文将以“User”和“Group”两个实体类之间的多对多关联映射为例进行 CRUD 操作。

经典案例:一个用户可以属于多个集体(领导、朋友、同事、亲戚),当然一个集体也包含了多个用户。

这个看似很复杂,但是有了前面的基础,我们就很容易看懂下面的 xml 关系:

8.1 建立 group 表

对应实体类“Group”,建表语句如下:

CREATE TABLE `group` (  
      `id` int(11) NOT NULL auto_increment,  
      `name` varchar(40) collate utf8_unicode_ci default NULL,  
      PRIMARY KEY  (`id`)  
    )  
8.2 建立 user 表

对应实体类“User”,建表语句如下::

 CREATE TABLE `user` (  
      `id` int(11) NOT NULL auto_increment,  
      `name` varchar(40) collate utf8_unicode_ci default NULL,  
      `password` varchar(20) collate utf8_unicode_ci default NULL,  
      PRIMARY KEY  (`id`)  
    ) 
8.3 建立 user_group 表

该类为 User 和 Group 两个实体类之间的关系描述对应实体类”UsertoGroup”,建表语句如下:

 CREATE TABLE `user_group` (  
      `user_id` int(11) default NULL,  
      `group_id` int(11) default NULL,  
      KEY `FK_user_group_user_id` (`user_id`),  
      KEY `FK_user_group_group_id` (`group_id`),  
      CONSTRAINT `FK_user_group_group_id` FOREIGN KEY (`group_id`) REFERENCES `group_info` (`id`),  
      CONSTRAINT `FK_user_group_user_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)  
    )   
8.4 建立 User 类

Java 代码:

import java.util.Date;  
    import java.util.List;  

    /** 
     * @describe: User实体类 ,讲解多对多
     * @author:    Array
     */  

    public class User {  

        private long id;  

        private String name;  

        private String password;   

        private List<Group> group;  


        public long getId() {  
            return id;  
        }  

        public void setId(long id) {  
            this.id = id;  
        }  

        public String getName() {  
            return name;  
        }  

        public void setName(String name) {  
            this.name = name;  
        }  

        public String getPassword() {  
            return password;  
        }  

        public void setPassword(String password) {  
            this.password = password;  
        }  

        public List<Group> getGroup() {  
            return group;  
        }  

        public void setGroup(List<Group> group) {  
            this.group = group;  
        }  
    }  
8.5 建立实体 Group

代码如下:

 import java.util.Date;  
    import java.util.List;  

    /** 
     * @describe: Group实体类 
     */  
    public class Group {  

        private long id;  
        private String name;  
        private List<User> user;   
        public long getId() {  
            return id;  
        }  

        public void setId(long id) {  
            this.id = id;  
        }  

        public String getName() {  
            return name;  
        }  

        public void setName(String name) {  
            this.name = name;  
        }   

        public List<User> getUser() {  
            return user;  
        }  

        public void setUser(List<User> user) {  
            this.user = user;  
        }  

    }  
8.6 建立实体类 UsertoGroup

用于描述 User 和 Group 之间的对应关系,代码如下:

import java.util.Date;  

    /** 
     * @describe: 定义User和Group之间的映射关系 
     */  
    public class UsertoGroup{  

        private User user;  

        private Group group;  

        private Date createTime;  

        public Date getCreateTime() {  
            return createTime;  
        }  

        public void setCreateTime(Date createTime) {  
            this.createTime = createTime;  
        }  

        public Group getGroup() {  
            return group;  
        }  

        public void setGroup(Group group) {  
            this.group = group;  
        }  

        public User getUser() {  
            return user;  
        }  

        public void setUser(User user) {  
            this.user = user;  
        }  
    }  

其中剩下的我们去xml中去配置:

8.7 user 的 xml 代码:user.map.xml
<?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">  
    <mapper namespace="com.array.bean.User">  
        <resultMap type="User" id="userMap">  
            <id property="id" column="id" />  
            <result property="name" column="name" />  
            <result property="password" column="password" />   
        </resultMap>  

        <resultMap type="User" id="userGroupMap" extends="userMap">  
            <collection property="groups" ofType="Group">  
                <id property="id" column="goupId" />  
                <result property="name" column="groupName" />  
                <result property="state" column="state" />   
            </collection>  
        </resultMap>  


        <!--  id查询用户信息 -->  
        <select id="selectUser" parameterType="long" resultMap="userMap">  
            select * from user where id = #{id}  
        </select>  

        <!-- 根据user表中的id查询用户和组信息 -->  
        <select id="selectUserGroup" parameterType="long"  
            resultMap="userGroupMap">  
            select u.id,u.name,u.password, gi.id as  
            goupId,gi.name as groupName 
             from user u left join user_group ug on u.id=ug.user_id  
            left join group gi on ug.group_id=gi.id where u.id = #{id}  
        </select>  

        <!-- 插入-->  
        <insert id="saveUser" parameterType="User" keyProperty="id"  
            useGeneratedKeys="true">  
            insert into user(name,password) values(#{name},#{password})  
        </insert>  

        <!-- 保存用户和组之间的关系信息 -->  
        <insert id="saveRelativity" parameterType="UsertoGroup">  
            insert into user_group(user_id,group_id)  
            values(#{user.id},#{group.id})  
        </insert>  

        <select id="selM" resultMap="userMap">  
            select * from user  
        </select>  

    </mapper>  
8.8 group 的 xml 配置代码:
     group.map.xml
   language-<?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">  
    <mapper namespace="com.array.bean.Group">  
        <resultMap type="Group" id="groupMap">  
            <id property="id" column="id" />  
            <result property="name" column="name" />    
        </resultMap>  

        <resultMap type="Group" id="groupUserMap" extends="groupMap">  
            <collection property="users" ofType="User">  
                <id property="id" column="userId" />  
                <result property="name" column="userName" />  
                <result property="password" column="password" />     
            </collection>  
        </resultMap>  


        <!-- 根据Group表中的id -->  
        <select id="selectGroupUser" parameterType="Group"  
            resultMap="groupUserMap">  
            select u.id as userId,u.name as userName,  
            u.password,
            gi.id,gi.name  from group gi left  
            join user_group ug on gi.id=ug.group_id left join user u on  
            uug.user_id=u.id  
            <where>  
                <!--当id为初始值0,不再使用id作为查询条件 -->  
                <if test="id != 0  ">gi.id=#{id}</if>  
                <!-- 当name为空或为空串时,不再使用name作为查询条件 -->  
                <if test="name != null and name != ''">  
                    or gi.name = #{name}  
                </if>  
            </where>  
        </select>   
    </mapper>  

总结:很明显,通过 select 这个查询对应的 map,我们能看清其中多对多的 MyBatis 具体用法。

如果我们要取别名的话可以参考下面或者直接在 xml 中写出对应的真实位置即可,自由选择:

         <typeAliases>  
            <typeAlias type="com.array.bean.User" alias="User" />  
            <typeAlias type="com.array.bean.Group"  
                alias="Group" />  
            <typeAlias type="com.array.bean.UsertoGroup"  
                alias="UsertoGroup" />  
        </typeAliases> 

九、MyBatis 和 Hibernate 的优缺点对比 & MyBatis 框架的优缺点及其适用场合

Hibernate 的优点:

  1. Hibernate 是全自动,Hibernate 完全可以通过对象关系模型实现对数据库的操作,拥有完整的 JavaBean 对象与数据库的映射结构来自动生成 SQL。
  2. 功能强大,数据库无关性好,O/R 映射能力强,需要写的代码很少,开发速度很快。
  3. 有更好的二级缓存机制,可以使用第三方缓存。
  4. 数据库移植性良好。
  5. Hibernate 拥有完整的日志系统,Hibernate 日志系统非常健全,涉及广泛,包括 SQL 记录、关系异常、优化警告、缓存提示、脏数据警告等

Hibernate 的缺点:

  1. 学习门槛高,精通门槛更高,程序员如何设计 O/R 映射,在性能和对象模型之间如何取得平衡,以及怎样用好 Hibernate 方面需要的经验和能力都很强才行;
  2. Hibernate 的 SQL 很多都是自动生成的,无法直接维护 SQL;虽然有 HQL 查询,但功能还是不及 SQL 强大,见到报表等变态需求时,HQL 查询要虚,也就是说 HQL 查询是有局限的;Hibernate 虽然也支持原生 SQL 查询,但开发模式上却与 ORM 不同,需要转换思维,因此使用上有些不方便。总之写SQL的灵活度上 Hibernate 不及 MyBatis。

MyBatis的优点:

  1. 易于上手和掌握,提供了数据库查询的自动对象绑定功能,而且延续了很好的 SQL 使用经验,对于没有那么高的对象模型要求的项目来说,相当完美。
  2. SQL 写在 xml 里,便于统一管理和优化, 解除 SQL 与程序代码的耦合。
  3. 提供映射标签,支持对象与数据库的 ORM 字段关系映射。
  4. 提供对象关系映射标签,支持对象关系组建维护。
  5. 提供 xml 标签,支持编写动态 SQL,经常使用 MyBatis 的场合。
  6. 速度相对于 Hibernate 的速度较快。

MyBatis 的缺点:

  1. 关联表多时,字段多的时候,SQL 工作量很大。
  2. SQL 依赖于数据库,导致数据库移植性差。
  3. 由于 xml 里标签id必须唯一,导致 DAO 中方法不支持方法重载。
  4. 对象关系映射标签和字段映射标签仅仅是对映射关系的描述,具体实现仍然依赖于 SQL。
  5. DAO 层过于简单,对象组装的工作量较大。
  6. 不支持级联更新、级联删除。
  7. MyBatis 的日志除了基本记录功能外,其它功能薄弱很多。
  8. 编写动态 SQL 时,不方便调试,尤其逻辑复杂时。
  9. 提供的写动态 SQL 的 xml 标签功能简单~
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值