首发于我的博客 和尚的博客
本篇主要讲解查询操作的结果集处理、映射文件里命名空间设置,SQL语句中resultMap,resultType等属性意思、MyBatis的传统和接口代理模式。


源码获取github

1.整体结构目录

  • SkillDao.java接口含一些方法
  • SkillDaoImpl.java是SkillDao的实现类
  • Skill.java是持久化类(实体Bean)
  • SkillMapper.xml是Skill持久化类的映射文件(含SQL语句操作等)
  • MyBatisTest.java测试类
  • jdbc.properties数据库的属性文件
  • log4j.properties日志框架配置(在控制台显示sql语句等信息)
  • mybatis-config.xml核心配置文件

2.数据库属性文件

jdbc.properties

jdbc.mysql.driver=com.mysql.jdbc.Driver
jdbc.mysql.url=jdbc:mysql://localhost:3306/cy42_mss
jdbc.mysql.username=root
jdbc.mysql.password=root

3.核心配置文件

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>
    <!--加载属性文件 -->
    <properties resource="jdbc.properties"/>
    <!--自定义设置类型的别名,也就是resultMap里的type,避免包名已修改,在映射文件里修改多处地方-->
    <typeAliases>
        <!-- 方式一、com.hs.model.Skill这个类设置了别名hs,之后要用这个的话,直接写hs -->
        <!--<typeAlias type="com.hs.model.Skill" alias="hs"/> -->
        <!-- 方式二、com.hs.model这个包下的类,要用的时候直接写类名,比如用com.hs.model.Skill,直接写Skill -->
        <package name="com.hs.model"/>
    </typeAliases>
    <!--配置数据库的环境-->
    <environments default="development">
        <environment id="development">
            <!--事务管理器:保证数据的完整性和一致性 关键信息 -->
            <!--框架:默认情况下CUD操作需要 手动提交事务 (如同在Navicat中表中输入了数据,没有点那个小√,就是没有提交事务, 但是输入insert语句,就自动提交事务了) -->
            <transactionManager type="JDBC" />
            <!-- mybatis提供了3种数据源类型,分别是:POOLED,UNPOOLED,JNDI -->
            <!-- POOLED 表示支持JDBC数据源连接池 -->
            <!-- UNPOOLED 表示不支持数据源连接池 -->
            <!-- JNDI 表示支持外部数据源连接池 -->
            <!--使用的是连接池:百度java如何实行连接池的原理? -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.mysql.driver}" />  <!--获取值,${属性文件里的变量名},也可以直接写值-->
                <property name="url" value="${jdbc.mysql.url}" />  <!--获取值,${属性文件里的变量名},也可以直接写值-->
                <property name="username" value="${jdbc.mysql.username}" /> <!--获取值,${属性文件里的变量名},也可以直接写值-->
                <property name="password" value="${jdbc.mysql.password}" /> <!--获取值,${属性文件里的变量名},也可以直接写值-->
            </dataSource>
        </environment>
    </environments>

    <!--加载映射文件 ,也就是含sql语句的文件-->
    <mappers>
        <!--告知映射文件方式1,一个一个的配置-->
        <mapper resource="com/hs/model/SkillMapper.xml"/>
        <!-- 告知映射文件方式2,自动扫描包内的Mapper接口与配置文件 -->
        <!--<package name="com.hs.model"/>-->
    </mappers>
</configuration>

4.封装好的工具类

MyBatisUtils.java

package com.hs.util;
/** * 知识点: * final修饰类:不能被继承 * 修饰方法:不能被重写 * 修饰变量:常量不可用变,但如果是对象,对象里的值可以变 * */
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

public class MyBatisUtils {

    private MyBatisUtils() { }  //不允许实例化

    private static final String PATH = "mybatis-config.xml";
    private static InputStream inputStream;
    private static SqlSessionFactory sqlSessionFactory;

    static { //1.静态代码块,只是加载一次
        try {
            //输入流 读文件
            //1.读取核心配置文件
            inputStream = Resources.getResourceAsStream(PATH);
            //2.创建SqlSession工厂(SqlSessionFactory)相当于Connection
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("加载核心配置文件失败");
        }
    }

    /** * 获取sqlsession * @return */
    public static SqlSession getSqlsession() {
        //3.获取SqlSession 相当于执行SQL语句对象PreparedStament预处理对象
        //***** SqlSession完成所有的持久化操作CRUD
        return sqlSessionFactory.openSession();
    }

    /** * 关闭资源 * @param sqlSession */
    public static void closeSqlSession(SqlSession sqlSession) {
        if (sqlSession != null) {
            sqlSession.close();
        }
    }
}

5.持久化类

为了讲出来一些知识点,持久化类的属性名没有和数据库的字段名一样,正常应该是一样的

Skill.java

package com.hs.model;

public class Skill {
    private Integer skillid;
    private String skillname;
    private Integer num;

    public Integer getSkillid() {
        return skillid;
    }

    public void setSkillid(Integer skillid) {
        this.skillid = skillid;
    }

    public String getSkillname() {
        return skillname;
    }

    public void setSkillname(String skillname) {
        this.skillname = skillname;
    }

    public Integer getNum() {
        return num;
    }

    public void setNum(Integer num) {
        this.num = num;
    }

    @Override
    public String toString() {
        return "Skill{" +
                "skillid=" + skillid +
                ", skillname='" + skillname + '\'' +
                ", num=" + num +
                '}';
    }
}

6.XML映射文件

SQL映射文件经常含一些元素

  • parameterType—-接收的参数类型,简写方式见mybatis官方文档中,别名和映射的类型那块
  • parameterMap没有人用了!!!!!
  • resultType—-语句执行完毕返回的结果集类型
  • resultMap—-语句执行完毕返回的结果集,这是一个标签,找它对应的标签,对这个结果集进行处理,里面的type就是相应的返回类型
  • sql—-提取公共的SQL代码
  • insert—-映射插入语句
  • update—-映射更新语句
  • delete—-映射删除语句
  • select—-映射查询语句

SkillMapper.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">
<!--namespace=命名空间,唯一不重复-->
<mapper namespace="com.hs.model.Skill"> <!--命名空间规则 传统模式:(持久化类(实体化Bean)的类名全路径com.hs.Skill) 接口代理模式:接口的全路径-->

    <!--查询的字段,并没有优化,下个专题进行优化-->
    <!--当你传递的是“一个”简单的数据类型的形参的时候,那么你的${任意名字},sql语句后面不要加 ; -->
    <select id="getMap01ByPk" parameterType="_int" resultType="map">
        select skill_id,skill_name,num from skill where skill_id = #{sadsa}
    </select>
    <select id="getMap02ByPk" parameterType="_int" resultType="map">
        select skill_id skillid,skill_name skill_name ,num number from skill where skill_id = #{skill_id}
    </select>
    <!--只能对结果集的结果操作进行处理,autoMapping="true"默认映射,默认为true,重写字段名会覆盖默认的,若false就不会映射默认字段(只映射出自己写的别名)-->
    <resultMap id="MapResultMapper" type="map" autoMapping="true">
        <result column="skill_id" property="id"/>   <!--column为结果集里的字段名,property为自己要映射(变成)的字段名-->
        <result column="skill_name" property="name"/>
        <result column="num" property="number"/>
    </resultMap>
    <select id="getMap03ByPk" parameterType="_int" resultMap="MapResultMapper">
        select skill_id,skill_name ,num from skill where skill_id = #{skill_id}
    </select>
    <!--1.别名方法,属性和字段名一致,可以完成自动映射-->
    <select id="getSkill01ByPk" parameterType="int" resultType="com.hs.model.Skill">
        select skill_id skillid,skill_name skillname,num from skill where skill_id = #{adsa}
    </select>
    <!--2.resultMap标签找对应id的标签,利用结果集,进行转换,jdbcType和javaType可以不用写,名字见jdbc类型和Java 类型对应http://www.mybatis.org/mybatis-3/zh/configuration.html#typeAliases-->
    <resultMap id="SkillResultMapper" type="com.hs.model.Skill">
        <id column="skill_id" jdbcType="INTEGER" property="skillid" javaType="java.lang.Integer"/>
        <result column="skill_name" jdbcType="VARCHAR" property="skillname" javaType="java.lang.String"/>
        <result column="num" property="num"/>
    </resultMap>
    <select id="getSkill02ByPk" parameterType="int" resultMap="SkillResultMapper">
        select skill_id,skill_name,num from skill where skill_id = #{adsa}
    </select>

    <!--一条一条的为map-->
    <select id="getSkillList01ByAll" resultType="map">
        select skill_id,skill_name,num from skill
    </select>
    <select id="getSkillList02ByAll" resultMap="SkillResultMapper">
        select skill_id,skill_name,num from skill
    </select>
</mapper>

7.接口

SkillDao.java

package com.hs.dao;

import com.hs.model.Skill;

import java.util.List;
import java.util.Map;

public interface SkillDao {
    /** * 处理结果集为Map类型 * @param skillid * @return */
    Map<String, Object> getMap01ByPk(int skillid);
    /** * 处理结果集为Map类型—通过给字段取别名方式 * @param skillid * @return */
    Map<String, Object> getMap02ByPk(int skillid);

    /** * 处理结果集为Map类型—通过resultMap标签处理 * @param skillid * @return */
    Map<String, Object> getMap03ByPk(int skillid);

    /** * 处理结果集为自定义的类Skill—通过给字段取别名方式 * @param skillid * @return */
    Skill getSkill01ByPk(int skillid);

    /** * 处理结果集为自定义的类Skill—resultMap标签处理 * @param skillid * @return */
    Skill getSkill02ByPk(int skillid);

    /** * 处理结果集为集合(list) * @param skillid * @return */
    List<Map<String, Object>> getSkillList01ByAll();

    /** * 处理结果集为集合(list)—通过resultMap * @param skillid * @return */
    List<Map<String, Object>> getSkillList02ByAll();

}

8.接口实现类

SkillDaoImpl.java

package com.hs.dao;

import com.hs.model.Skill;
import com.hs.util.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;

import java.util.List;
import java.util.Map;

public class SkillDaoImpl implements SkillDao {

    /* * 关键步骤:定位执行SQL语句***如何定位 (namespace+"."+id) * 因为命名空间是Bean的路径,所以下面的 命名空间.sql语句的id === 类.class.getName()+" ." +id * 后面就是要传过去的值 * */
    @Override
    public Map<String, Object> getMap01ByPk(int skillid) {
        SqlSession sqlSession = null;
        try {
            sqlSession = MyBatisUtils.getSqlsession();
            System.out.println(Skill.class.getName()+"----com.he.model.Skill");
            //关键步骤
            return sqlSession.selectOne(Skill.class.getName() + ".getMap01ByPk",skillid);
        } finally {
            MyBatisUtils.closeSqlSession(sqlSession);
        }
    }

    @Override
    public Map<String, Object> getMap02ByPk(int skillid) {
        SqlSession sqlSession = null;
        try {
            sqlSession = MyBatisUtils.getSqlsession();
            return sqlSession.selectOne(Skill.class.getName() + ".getMap02ByPk",skillid);
        } finally {
            MyBatisUtils.closeSqlSession(sqlSession);
        }
    }

    @Override
    public Map<String, Object> getMap03ByPk(int skillid) {
        SqlSession sqlSession = null;
        try {
            sqlSession = MyBatisUtils.getSqlsession();
            return sqlSession.selectOne(Skill.class.getName() + ".getMap03ByPk",skillid);
        } finally {
            MyBatisUtils.closeSqlSession(sqlSession);
        }
    }

    @Override
    public Skill getSkill01ByPk(int skillid) {
        SqlSession sqlSession = null;
        try {
            sqlSession = MyBatisUtils.getSqlsession();
            return sqlSession.selectOne(Skill.class.getName() + ".getSkill01ByPk",skillid);
        } finally {
            MyBatisUtils.closeSqlSession(sqlSession);
        }
    }

    @Override
    public Skill getSkill02ByPk(int skillid) {
        SqlSession sqlSession = null;
        try {
            sqlSession = MyBatisUtils.getSqlsession();
            return sqlSession.selectOne(Skill.class.getName() + ".getSkill02ByPk",skillid);
        } finally {
            MyBatisUtils.closeSqlSession(sqlSession);
        }
    }
    @Override
    public List<Map<String, Object>> getSkillList01ByAll() {
        SqlSession sqlSession = null;
        try {
            sqlSession = MyBatisUtils.getSqlsession();
            return sqlSession.selectList(Skill.class.getName() + ".getSkillList01ByAll");
        } finally {
            MyBatisUtils.closeSqlSession(sqlSession);
        }
    }

    @Override
    public List<Map<String, Object>> getSkillList02ByAll() {
        SqlSession sqlSession = null;
        try {
            sqlSession = MyBatisUtils.getSqlsession();
            return sqlSession.selectList(Skill.class.getName() + ".getSkillList02ByAll");
        } finally {
            MyBatisUtils.closeSqlSession(sqlSession);
        }
    }

}

9.日志配置文件

log4j.properties

# 日志配置文件Global logging configuration
log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
# 如果要显示SQL语句,那么这个位置需要配置为命名空间log4j.logger.命名空间
log4j.logger.com.hs.model.Skill=TRACE
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

10.测试类

MyBatisTest.java

package com.hs.test;
/** * 本测试全是采用传统模式:dao层里dao接口写方法,daoImpl实现方法,然后写测试类 */

import com.hs.dao.SkillDao;
import com.hs.dao.SkillDaoImpl;
import org.junit.Test;

public class MyBatisTest {

    /** * 处理结果集为Map类型 */
    @Test
    public void getMap01ByPk() {
        SkillDao skillDao = new SkillDaoImpl();     //接口回调(个人理解,父类定义变量SkillDao skillDao,子类实例化)
        System.out.println(skillDao.getMap01ByPk(2));
    }

    /** * 处理结果集为Map类型—通过给字段取别名方式 */
    @Test
    public void getMap02ByPk() {
        SkillDao skillDao = new SkillDaoImpl();     //接口回调(个人理解,父类定义变量SkillDao skillDao,子类实例化)
        System.out.println(skillDao.getMap02ByPk(2));
    }

    /** * 处理结果集为Map类型—通过resultMap标签处理 */
    @Test
    public void getMap03ByPk() {
        SkillDao skillDao = new SkillDaoImpl();     //接口回调(个人理解,父类定义变量SkillDao skillDao,子类实例化)
        System.out.println(skillDao.getMap03ByPk(2));
    }

    /** * 处理结果集为自定义的类Skill—通过给字段取别名方式 */
    @Test
    public void getSkill01ByPk() {
        SkillDao skillDao = new SkillDaoImpl();     //接口回调(个人理解,父类定义变量SkillDao skillDao,子类实例化)
        System.out.println(skillDao.getSkill01ByPk(2));
    }

    /** * 处理结果集为自定义的类Skill—resultMap标签处理 */
    @Test
    public void getSkill02ByPk() {
        SkillDao skillDao = new SkillDaoImpl();     //接口回调(个人理解,父类定义变量SkillDao skillDao,子类实例化)
        System.out.println(skillDao.getSkill02ByPk(2));
    }

    /** * 处理结果集为集合(list) */
    @Test
    public void getSkillList01ByAll() {
        SkillDao skillDao = new SkillDaoImpl();     //接口回调(个人理解,父类定义变量SkillDao skillDao,子类实例化)
        System.out.println(skillDao.getSkillList01ByAll());
    }

    /** * 处理结果集为集合(list)—通过resultMap */
    @Test
    public void getSkillList02ByAll() {
        SkillDao skillDao = new SkillDaoImpl();     //接口回调(个人理解,父类定义变量SkillDao skillDao,子类实例化)
        System.out.println(skillDao.getSkillList02ByAll());
    }
}

11.在测试类中运行相应的测试