MyBatis框架自学之路——简易入门

2023-05-16

目录

  • 目录
  • 介绍
  • 入门案例
    • 准备工作
    • MyBatis的CURD
      • MyBatis框架的基本原理
      • 使用MyBatis的工具类
      • 测试类
      • 查询操作
        • 根据用户ID查询对应的用户记录
        • 根据用户名查询一条或多条用户记录
      • 添加操作
        • 自增主键的返回
        • 非自增主键的返回
      • 删除操作
      • 更新操作
        • 修改用户信息
        • 根据性别修改用户信息
      • 小结
  • MyBatis中的类或接口
  • MyBatis开发dao的方法
    • 原始dao开发方法
    • mapper代理
  • 全局配置文件SqlMapConfig.xml
  • 知识点扩展或参考

介绍

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

  MyBatis是一个基于Java的持久层框架,是Apache下的一个顶级项目。当然,下面主要讲解的也是MyBatis的入门使用。在这里也只是我学习过程中的一个记录。毕竟网上对MyBatis介绍以及使用的文章太多太多了。
  另外,学习MyBatis除了网上的文章或教程视频外,其过程我们不能脱离MyBatis的官方文档(传送门:MyBatis官方文档)。下面开始我们的MyBatis学习吧!!!

入门案例

准备工作

  创建一个新的工程,导入MyBatis的jar包及相关依赖的jar包。(这里使用的是mybatis-3.4.6)下载地址:mybatis 3
  为在使用MyBatis过程中看到MyBatis的执行日志(MyBatis默认使用log4j输出日志信息),我们先在项目的classpath下(这里我在项目的根目录创建了一个config目录,在config目录下)创建log4j.properties,内容如下:

# Global logging configuration
# 在开发环境下日志级别建议设置为DEBUG,生产环境设置成INFO或ERROR
log4j.rootLogger=DEBUG, stdout
# 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

MyBatis的CURD

(1)创建MyBatis核心配置文件
  在config目录(该目录在项目根目录下被创建)下,(实际上也是classpath)创建MyBatis的核心配置文件,该文件的名称和位置并不是固定的。在这里我们将该文件命名为SqlMapConfig.xml
  MyBatis的核心配置文件包含了对 MyBatis 系统的核心设置,包含获取数据库连接实例的数据源(DataSource)和决定事务作用域和控制方式的事务管理器(TransactionManager)。
  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>
    <!-- 和Spring整合后environments配置将不再使用 -->
    <environments default="development">
        <environment id="development">
            <!-- 使用JDBC事务管理,事务控制由MyBatis -->
            <transactionManager type="JDBC"/>
            <!-- 数据库连接池,由MyBatis管理 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///mydb_329?useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value=""/>
            </dataSource>
        </environment>
    </environments>
</configuration>

  这里采用的是名为mydb_329的数据库。
(2)创建po类,po类作为MyBatis进行SQL映射使用,po类通常与数据表对应,User.java如下:(这里已经在数据库中事先准备好了mb_user表,对应于该po类)

package com.wm103.po;

import java.util.Date;

/**
 * Created by DreamBoy on 2018/4/9.
 */
public class User {
    private int id;
    private String username;
    private String sex;
    private Date birthday;
    private String address;

    public int getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", sex='" + sex + '\'' +
                ", birthday=" + birthday +
                ", address='" + address + '\'' +
                '}';
    }
}

(3)在config/sqlmap目录中创建User.xml映射文件,该文件是主要用于配置输入参数同SQL的映射以及SQL操作结果同输出结果的映射关系,在映射文件中我们可以配置SQL语句。
  在原始的iBatis中,习惯以xxx.xml命名,如 User.xml;在MyBatis中mapper代理开发(后续会讲解“什么是mapper代理开发”以及“如何实现mapper代理”等)映射文件名称则习惯以xxxMapper.xml名称,如 UserMapper.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="user">
    <!-- 根据用户ID查询对应的用户记录 -->

    <!-- 根据用户名查询一条或多条用户记录 -->

    <!-- 添加用户(自增主键) -->

    <!-- 添加用户(非自增主键) -->

    <!-- 删除用户 -->

    <!-- 修改用户信息 -->

    <!-- 根据性别更新用户信息 -->

</mapper>

  在这里需要重点说明的是mapper标签上的namespace属性,即该属性用于对SQL进行分类化管理,不同的映射文件中设置的mappernamespace不同。使用mapper代理方式开发,namespace有着特殊的重要作用,后续将进行讲解。
(4)在MyBatis核心配置文件中(这里指的是SqlMapConfig.xml)引入映射文件,如下:

<mappers>
    <mapper resource="sqlmap/User.xml"/>
</mappers>

  引入后,在java代码中使用的即是该核心配置文件的内容,通过核心配置文件,可以知道各映射文件的配置,从而进行对应的SQL操作。那么在实际编写CURD操作之前,我们有必要了解,MyBatis在java程序中,是“如何加载配置文件的”,以及“加载配置文件后我们又该如何获取到实现CURD的对象进行CURD操作的”等一系列问题。

MyBatis框架的基本原理

  1. 配置MyBatis核心配置文件(如:SqlMapConfig.xml),该文件配置了数据源、事务等MyBatis运行环境;
  2. 配置映射文件(在该文件中配置SQL语句),并将这些文件引入核心配置文件中;
  3. 在java程序中加载核心配置文件,根据配置文件创建SqlSessionFactory,即会话工厂。在创建会话工厂的过程中,将配置文件的内容封装为Configuration对象,并在创建会话工厂时通过构造方法传给会话工厂;
  4. 通过SqlSessionFactory会话工厂,获取SqlSession对象(将会话工厂的Configuration和Executor执行器等对象传入),用于操作数据库;
  5. 而在SqlSession接口(SqlSession是一个面向程序员的接口)默认实现类的内部,使用Configuration对操作数据库存储封装,返回一个MappedStatement底层封装对象(可以简单的理解为是映射文件中SQL语句的封装对象,当然该对象远不止这么简单);
  6. 接着将MappedStatement对象传给Executor对象,使用Executor(Executor同样也是接口,有基本执行器、缓存执行器)执行器操作数据库。

使用MyBatis的工具类

  那么根据以上说明,实际上我们所需做的步骤是:
1. 加载配置文件,创建会话工厂(会话工厂可采用单例模式进行实现);
2. 通过会话工厂,获取SqlSession对象;
3. 通过SqlSession对象操作数据库。
  MyBatis的简单工具类 MyBatisUtil.java,如下:

package com.wm103.utils;

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;

/**
 * Created by DreamBoy on 2018/4/9.
 */
public class MyBatisUtil {
    private final static SqlSessionFactory sqlSessionFactory;

    static {
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
        } catch (IOException e) {
            e.printStackTrace();
        }
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }

    public static SqlSessionFactory getSqlSessionFactory() {
        return sqlSessionFactory;
    }

    public static SqlSession getSqlSession() {
        return sqlSessionFactory.openSession();
    }

    public static void closeSession(SqlSession sqlSession) {
        if (sqlSession != null) {
            sqlSession.close();
        }
    }
}

测试类

  下面使用该工具类,实现CURD操作,为了方便案例的演示,创建一个测试类TestMyBatis,如下:

package com.wm103.test;

import com.wm103.po.User;
import com.wm103.utils.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

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

/**
 * Created by DreamBoy on 2018/4/9.
 */
public class TestMyBatis {

}

  在该测试类内实现CURD操作。

查询操作

根据用户ID查询对应的用户记录

(1)在User.xml映射文件中,配置SQL语句,如下:

<!-- 根据用户ID查询对应的用户记录 -->
<select id="findUserById" parameterType="int" resultType="com.wm103.po.User">
    SELECT * FROM mb_user WHERE id=#{id}
</select>

说明:
1. select标签用于标识该SQL语句实现的是查询操作;
2. id属性标识该映射文件中的SQL(在讲原理的时候,我们提到操作数据库前,会将SQL语句封装到一个叫MappedStatement对象中,因此这里的id我们也可以称之为statement的id)
3. parameterType属性指定输入参数的类型,这里指定为int类型;
4. SQL语句中的#{}表示一个占位符,接收的是输入参数的内容,如:#{id},其中id表示接收输入的参数,参数名称为id。对于简单类型而言,#{}中的参数名可以任意,而对于对象而言,#{}中的参数名需要对象的属性名,对于HashMap来说,#{}中的参数名则为map的key。
5. resultType属性指定输出结果的映射类型,确切地说是指单条记录所映射的java对象类型,这里将查询结果映射到User对象中。
(2)测试方法,如下:

@Test
public void findUserByIdTest() {
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    User user = sqlSession.selectOne("user.findUserById", 1);
    System.out.println(user);
    MyBatisUtil.closeSession(sqlSession);
}

说明:
通过SqlSession的方法操作数据库,这里使用的方法的参数:
1. 第一个参数:映射文件中的statement的id,即 映射文件的namesapce.statement的id,如user.findUserById;
2. 第二个参数:指定输入参数,与映射文件对应的配置所设置的parameterType属性值相匹配;
3. 方法的返回结果:与映射文件对应的配置所设置的resultType属性值相匹配。

根据用户名查询一条或多条用户记录

(1)在User.xml映射文件中,配置SQL语句,如下:

<!-- 根据用户名查询一条或多条用户记录 -->
<select id="findUserByName" parameterType="java.lang.String" resultType="com.wm103.po.User">
    SELECT * FROM mb_user WHERE username LIKE '%${value}%'
</select>

说明:
1. resultType属性在查询多条返回记录时,该属性值指的是单条记录所映射的java对象类型;
2. ${}表示将接收到的参数内容不加任何修饰的拼接在原有的SQL语句中,注意使用${}拼接SQL可能将引起SQL注入的问题。${}中,如果接收的输入参数为简单类型,那么拼接SQL语句时必须为${value}
(2)测试方法,如下:

@Test
public void findUserByNameTest() {
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    List<User> list = sqlSession.selectList("user.findUserByName", "mb");
    System.out.println(list);
    MyBatisUtil.closeSession(sqlSession);
}

添加操作

(1)在User.xml映射文件中,配置SQL语句,如下:

<!-- 添加用户(自增主键) -->
<insert id="insertUser" parameterType="com.wm103.po.User">
    INSERT INTO mb_user(username, birthday, sex, address) value(#{username}, #{birthday}, #{sex}, #{address})
</insert>

(2)测试方法,如下:

@Test
public void insertUserTest() {
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    User user = new User();
    user.setUsername("mb_user03");
    user.setBirthday(new Date());
    user.setSex("女");
    user.setAddress("广东广州");
    sqlSession.insert("user.insertUser", user);
    sqlSession.commit();
    MyBatisUtil.closeSession(sqlSession);
}

  有时在执行添加操作后,我们需要获取到刚被添加记录的主键的值。那么应如何实现呢?下面将分两个部分进行讲解,包括自增主键的获取、非自增主键的获取。以MySQL为例。

自增主键的返回

  为获取自增主键的值,在映射文件中应做如下配置,如:

<!-- 添加用户(自增主键) -->
<insert id="insertUser" parameterType="com.wm103.po.User">
    <!-- 将插入数据的主键返回,并设置到结果对象user中 -->
    <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
      SELECT LAST_INSERT_ID()
    </selectKey>
    INSERT INTO mb_user(username, birthday, sex, address) value(#{username}, #{birthday}, #{sex}, #{address})
</insert>

说明:
1. selectKey标签用来执行额外操作,并将结果设置到输入参数值中。属性如下(摘录自官方文档):

属性描述
keyPropertyselectKey 语句结果应该被设置的目标属性。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
keyColumn匹配属性的返回结果集中的列名称。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
resultType结果的类型。MyBatis 通常可以推算出来,但是为了更加确定写上也不会有什么问题。MyBatis 允许任何简单类型用作主键的类型,包括字符串。如果希望作用于多个生成的列,则可以使用一个包含期望属性的 Object 或一个 Map。
order这可以被设置为 BEFORE 或 AFTER。如果设置为 BEFORE,那么它会首先选择主键,设置 keyProperty 然后执行插入语句。如果设置为 AFTER,那么先执行插入语句,然后是 selectKey 元素 - 这和像 Oracle 的数据库相似,在插入语句内部可能有嵌入索引调用。
statementType与前面相同,MyBatis 支持 STATEMENT,PREPARED 和 CALLABLE 语句的映射类型,分别代表 PreparedStatement 和 CallableStatement 类型。

2. SELECT LAST_INSERT_ID():查询刚执行插入的记录的主键ID,配合insert语句使用,在insert之后调用。

非自增主键的返回

  使用MySQL的uuid()函数生成主键,需要修改表中id字段类型为string,且长度为35位。这种非自增主键的实现方式如下:
1. 首先通过uuid()查询到主键;
2. 将查询到的主键作为SQL语句中的insert的值;
3. 执行insert语句。
  因此从这里我们也可以看出执行uuid()语句(即获取主键的操作)的顺序相对于insert语句之前执行。映射文件的配置如下:

<!-- 添加用户(非自增主键) -->
<insert id="insertUser2" parameterType="com.wm103.po.User">
    <!-- 将插入数据的主键返回,并设置到结果对象user中 -->
    <selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
        SELECT uuid()
    </selectKey>
    INSERT INTO mb_user(id, username, birthday, sex, address) value(#{id}, #{username}, #{birthday}, #{sex}, #{address})
</insert>

删除操作

(1)在User.xml映射文件中,配置SQL语句,如下:

<!-- 删除用户 -->
<delete id="deleteUser" parameterType="java.lang.Integer">
    DELETE FROM mb_user WHERE id = #{id}
</delete>

(2)测试方法,如下:

@Test
public void deleteUserTest() {
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    sqlSession.delete("user.deleteUser", 1);
    sqlSession.commit();
    MyBatisUtil.closeSession(sqlSession);
}

更新操作

修改用户信息

(1)在User.xml映射文件中,配置SQL语句,如下:

<!-- 修改用户信息 -->
<update id="updateUser" parameterType="com.wm103.po.User">
    UPDATE mb_user SET username = #{username}, birthday = #{birthday}, sex = #{sex}, address = #{address} WHERE id = #{id}
</update>

(2)测试方法,如下:

@Test
public void updateUserTest() {
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    User user = new User();
    user.setId(2);
    user.setUsername("mb_user01");
    user.setSex("男");
    user.setBirthday(new Date());
    user.setAddress("新地址");
    sqlSession.update("user.updateUser", user);
    sqlSession.commit();
    MyBatisUtil.closeSession(sqlSession);
}

根据性别修改用户信息

(1)在User.xml映射文件中,配置SQL语句,如下:

<!-- 根据性别更新用户信息 -->
<update id="updateUserBySex" parameterType="com.wm103.po.User">
    UPDATE mb_user SET username = #{username}, birthday = #{birthday}, address = #{address} WHERE sex = #{sex}
</update>

(2)测试方法,如下:

@Test
public void updateUserBySexTest() {
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    User user = new User();
    user.setUsername("mb_user");
    user.setSex("男");
    user.setBirthday(new Date());
    user.setAddress("新地址23333");
    sqlSession.update("user.updateUserBySex", user);
    sqlSession.commit();
    MyBatisUtil.closeSession(sqlSession);
}

小结

  1. parameterType属性:在映射文件中通过parameterType指定输入参数的类型;
  2. resultType属性:在映射文件中通过resultType指定(在查询返回多条记录的情况下,指单条记录)输出结果的类型;
  3. #{}${}
      #{}表示一个占位符,接收输入参数,参数的类型可以是简单类型、pojo、HashMap。如果#{}接收简单类型,则#{}中可以写成value或其他名称,如#{value}等;如果#{}接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性....的方法获取对象属性值;如果#{}接收HashMap类型,则#{}中为HashMap的key值。
      ${}则是一个拼接符号,会引起SQL注入,所以不建议使用。${}接收输入参数,参数类型可以是简单类型、pojo、HashMap。如果接收${}接收简单类型,则${}必须写成${value};如果接收pojo或者HashMap则同#{}的规则一致。
  4. selectOneselectList
      selectOne查询一条记录进行映射。查询一条记录时,也可以使用selectList实现,只是使用selectList后返回结果中List只有一个值,即最后需要的那一条查询记录。
      selectList查询出一个列表(多条记录)进行映射。查询结果不止一条记录时,不能使用selectOne查询,否则将报如下错误:
org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 2

  我们可以使用如下方法测试一下:

@Test
public void findUserByNameTestError() {
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    User user = sqlSession.selectOne("user.findUserByName", "mb");
    System.out.println(user);
    MyBatisUtil.closeSession(sqlSession);
}

MyBatis中的类或接口

  对于SqlSessionFactory而言,我们可以采用单例模式对SqlSessionFactory进行管理,无需创建多个SqlSessionFactory对象,MyBatis同Spring整合后,我们将采用单例的方式创建SqlSessionFactory对象。
  SqlSession是一个面向程序员的接口,它提供了许多操作数据库的方法。此处之外,需要特别注意的是,SqlSession是线程不安全的,在SqlSession的实现类中除了有接口中的方法(操作数据库的方法)还有数据域属性。因此SqlSession最佳应用场合是在方法体内,定义成局部变量使用。

MyBatis开发dao的方法

  MyBatis中开发dao的方法有两种,一种是原始的dao开发方法,需要我们程序员编写dao接口和dao实现类;两一种则为mapper代理方法,我们程序员只需编写mapper接口(相当于dao接口),除此之外,还需遵守一些规范。

原始dao开发方法

(使用同上述案例相同的映射文件,即User.xml)
(1)首先编写dao接口,这里以User为例,即创建UserDao接口,如下:

package com.wm103.dao;

import com.wm103.po.User;

/**
 * Created by DreamBoy on 2018/4/10.
 */
public interface UserDao {
    User findUserById(int id) throws Exception;

    void insertUser(User user) throws Exception;

    void deleteUser(int id) throws Exception;
}

(2)创建UserDao的实现类UserDaoImpl,在实现类中需要注入SqlSessionFactory,用于获取SqlSession以实现数据库的操作,如下:(这里剩余了一些方法的具体实现)

package com.wm103.dao;

import com.wm103.po.User;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

/**
 * Created by DreamBoy on 2018/4/10.
 */
public class UserDaoImpl implements UserDao {
    private SqlSessionFactory sqlSessionFactory;

    public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
        this.sqlSessionFactory = sqlSessionFactory;
    }

    @Override
    public User findUserById(int id) throws Exception {
        SqlSession sqlSession = this.sqlSessionFactory.openSession();
        User user = sqlSession.selectOne("user.findUserById", id);
        sqlSession.close();
        return user;
    }

    @Override
    public void insertUser(User user) throws Exception {

    }

    @Override
    public void deleteUser(int id) throws Exception {

    }
}

(3)编写测试类TestUserDaoImpl,如下:

package com.wm103.test;

import com.wm103.dao.UserDao;
import com.wm103.dao.UserDaoImpl;
import com.wm103.po.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;

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

/**
 * Created by DreamBoy on 2018/4/10.
 */
public class TestUserDaoImpl {
    private SqlSessionFactory sqlSessionFactory;

    @Before
    public void setUp() throws IOException {
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        this.sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }

    @Test
    public void findUserByIdTest() throws Exception {
        UserDao userDao = new UserDaoImpl(this.sqlSessionFactory);
        User user = userDao.findUserById(2);
        System.out.println(user);
    }
}

mapper代理

(1)创建新的映射文件,这里我们遵循mapper代理方式的命名规范,即UserMapper.xml。我们在config/mapper目录下进行创建;
(2)在MyBatis核心配置文件中,引入映射文件:

<mappers>
    <mapper resource="sqlmap/User.xml"/>
    <mapper resource="mapper/UserMapper.xml"/>
</mappers>

(3)编写新的映射文件中的内容和mapper接口,要求如下:
1. 在映射文件中mapper的namespace属性的值应为mapper接口地址;
2. mapper.java接口中的方法名与mapper.xml中的statement的id一致;
3. mapper.java接口中的方法输入参数类型和mapper.xml中的statement的parameterType指定的类型一致;
4. mapper.java接口中的方法返回值类型和mapper.xml中的statement的resultType指定的类型一致(针对单条记录)。
映射文件 UserMapper.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命名空间,作用就是对sql进行分类化管理,将sql隔离
    注意:使用mapper代理方法开发,namespace有特殊重要的作用,namespace为对应的mapper接口地址
-->
<mapper namespace="com.wm103.mapper.UserMapper">
    <!-- 根据用户ID查询对应的用户记录 -->
    <select id="findUserById" parameterType="int" resultType="com.wm103.po.User">
        SELECT * FROM mb_user WHERE id=#{id}
    </select>

    <!-- 根据用户名查询一条或多条用户记录 -->
    <select id="findUserByName" parameterType="java.lang.String" resultType="com.wm103.po.User">
        SELECT * FROM mb_user WHERE username LIKE '%${value}%'
    </select>

    <!-- 添加用户(自增主键) -->
    <insert id="insertUser" parameterType="com.wm103.po.User">
        <!-- 将插入数据的主键返回,并设置到结果对象user中 -->
        <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
          SELECT LAST_INSERT_ID()
        </selectKey>
        INSERT INTO mb_user(username, birthday, sex, address) value(#{username}, #{birthday}, #{sex}, #{address})
    </insert>

    <!-- 添加用户(非自增主键) -->
    <insert id="insertUser2" parameterType="com.wm103.po.User">
        <!-- 将插入数据的主键返回,并设置到结果对象user中 -->
        <selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
            SELECT uuid()
        </selectKey>
        INSERT INTO mb_user(id, username, birthday, sex, address) value(#{id}, #{username}, #{birthday}, #{sex}, #{address})
    </insert>

    <!-- 删除用户 -->
    <delete id="deleteUser" parameterType="java.lang.Integer">
        DELETE FROM mb_user WHERE id = #{id}
    </delete>

    <!-- 修改用户信息 -->
    <update id="updateUser" parameterType="com.wm103.po.User">
        UPDATE mb_user SET username = #{username}, birthday = #{birthday}, sex = #{sex}, address = #{address} WHERE id = #{id}
    </update>

    <!-- 根据性别更新用户信息 -->
    <update id="updateUserBySex" parameterType="com.wm103.po.User">
        UPDATE mb_user SET username = #{username}, birthday = #{birthday}, address = #{address} WHERE sex = #{sex}
    </update>
</mapper>

mapper接口 UserMapper.java

package com.wm103.mapper;

import com.wm103.po.User;

import java.util.List;

/**
 * Created by DreamBoy on 2018/4/10.
 */
public interface UserMapper {
    User findUserById(int id) throws Exception;

    List<User> findUserByName(String name) throws Exception;

    void insertUser(User user) throws Exception;

    void deleteUser(int id) throws Exception;
}

(4)创建测试类,通过SqlSession根据mapper接口获取对应的代理对象,显示查询操作,无需我们mapper接口下的方法的具体逻辑。如下:

package com.wm103.test;

import com.wm103.mapper.UserMapper;
import com.wm103.po.User;
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 org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * Created by DreamBoy on 2018/4/10.
 */
public class TestUserMapper {
    private SqlSessionFactory sqlSessionFactory;

    @Before
    public void setUp() throws IOException {
        String resource = "SqlMapConfig.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        this.sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }

    @Test
    public void findUserByIdTest() throws Exception {
        SqlSession sqlSession = this.sqlSessionFactory.openSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User user = userMapper.findUserById(2);
        sqlSession.close();
        System.out.println(user);
    }

    @Test
    public void findUserByNameTest() throws Exception {
        SqlSession sqlSession = this.sqlSessionFactory.openSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> list = userMapper.findUserByName("mb");
        sqlSession.close();
        System.out.println(list);
    }
}

  注:mapper接口方法参数只能设置一个,我们可以使用包装类型的pojo满足不同的业务需求。
  通过SqlSession获取的代理对象,针对查询操作而言,根据mapper接口定义的查询结果返回类型而调用selectOneselectList方法。如果mapper方法定义的返回值类型为单个pojo对象(即非集合对象),则代理对象内部会使用selectOne查询数据库;如果mapper方法定义的返回值类型为集合对象,则代理对象内部会使用selectList查询数据库。(记住,如果使用selectOne查询多条记录的话,要抛出异常哦!!!

全局配置文件SqlMapConfig.xml

  MyBatis的全局配置文件SqlMapConfig.xml,配置内容如下:

- properties 属性
- settings 设置
- typeAliases 类型别名
- typeHandlers 类型处理器
- objectFactory 对象工厂
- plugins 插件
- environments 环境
|- environment 环境变量
|-- transactionManager 事务管理器
|-- dataSource 数据源
- databaseIdProvider 数据库厂商标识
- mappers 映射器

  这里将不对每个标签进行一一讲解,而是对某些入门所需的标签进行说明。
(1)properties
  使用properties可以加载外部的配置文件,并使用配置文件中的配置项。如:在config目录下,我们可以定义额外的配置文件,用来保存数据库的设置,如下:
  config.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///mydb_329?useUnicode=true&characterEncoding=UTF-8
jdbc.username=root
jdbc.password=

  在核心配置文件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 resource="config.properties"/>
    <!-- 和Spring整合后environments配置将不再使用 -->
    <environments default="development">
        <environment id="development">
            <!-- 使用JDBC事务管理,事务控制由MyBatis -->
            <transactionManager type="JDBC"/>
            <!-- 数据库连接池,由MyBatis管理 -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <!--<property name="url" value="jdbc:mysql:///mydb_329?useUnicode=true&amp;characterEncoding=UTF-8"/>-->
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <package name="com.wm103.mapper"/>
    </mappers>
</configuration>

  这样做的好处是,将项目中一些重要的配置,如数据库配置,进行统一管理,也可以共享配置,有利于后续的维护。
  除了加载配置文件的作用后,properties内部可以使用property子标签配置属性,如:

<properties resource="config.properties">
    <property name="jdbc.driver" value="com.mysql.jdbc.Driver"/>
</properties>

  如果属性在不只一个地方进行了配置,那么 MyBatis 将按照下面的顺序来加载:

  • 在 properties 元素体内指定的属性首先被读取。
  • 然后根据 properties 元素中的 resource 属性读取类路径下属性文件或根据 url 属性指定的路径读取属性文件,并覆盖已读取的同名属性。
  • 最后读取作为方法参数传递的属性,并覆盖已读取的同名属性(即在创建SqlSessionFactory时传入Properties对象)。

      因此,建议只采用加载外部配置文件的方式,将属性值定义在该文件中
      此外,值得注意的是,如果配置文件属性名同映射文件中SQL传入的参数对象的属性同名的话,在执行SQL语句时传入的参数对象的属性的值将为配置文件中同名的属性的值,而非statement传入的对象的属性值。如:
      config.properties 做如下设置:

username=root

  在映射文件中,如UserMapper.xml中:

<update id="updateUserByUsername" parameterType="com.wm103.po.User">
    UPDATE mb_user SET birthday = #{birthday}, address = #{address} WHERE username LIKE '%${username}%'
</update>

  这时使用该statement,传入User对象,以username属性作为where条件参数时,就会发现执行数据库操作时所执行的SQL语句并非同我们预想的一样。${username}很意外地使用了config.properties文件中username属性的值,而非我们传入的user对象的值。如:

@Test
public void updateUserByUsernameTest() {
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    User user = new User();
    user.setUsername("mb");
    user.setBirthday(new Date());
    user.setAddress("新地址23333");
    sqlSession.update("user.updateUserByUsername", user);
    sqlSession.commit();
    MyBatisUtil.closeSession(sqlSession);
}

  运行结果后,我们发现执行的SQL语句为:

UPDATE mb_user SET birthday = ?, address = ? WHERE username LIKE '%root%'

  因此,建议在properties文件中定义的属性名要有一定的特殊性
(2)settings(配置)
  MyBatis全局配置参数,该设置将会影响MyBatis的运行行为,如是否开启延迟加载、缓存配置等。这里先不做过多讲解,具体可参考官方文档。
(3)typeAliases(类型别名)
  在映射文件中,我们可能需要配置输入映射(parameterType)或输出映射(resultType),而输入映射或输出映射为对象类型的话,那么则需要配置该对象的全路径。如果存在过多的相同配置的映射类型的话,实际上将不方便开发,因此,可以在核心配置文件中使用typeAliases标签定义别名,后续映射类型使用定义的别名。
  在MyBatis中默认支持了许多别名,如:java.lang.Integer别名为int。也因为如此,我们在映射文件中,可以使用int作为输入映射类型或输出映射类型。如:

<select id="findUserById" parameterType="int" resultType="com.wm103.po.User">
    SELECT * FROM mb_user WHERE id=#{id}
</select>

  那么如何自定义别名呢?自定义别名的方式有两种:一种是单个定义别名;另一种是批量定义别名(这也是一种常用的方式)。
  单个定义别名,如下:

<typeAliases>
    <typeAlias type="com.wm103.po.User" alias="user"/>
</typeAliases>

  做如上定义后,我们可以直接使用user作为输入映射或输出映射的映射类型。
  批量定义别名,通过指定包名,MyBatis会自动扫描包中的po类,自动定义别名,而自定定义出来的别名是类名或首字母小写的类名,如User或user均可作为别名引用。如下:

<typeAliases>
    <!--<typeAlias type="com.wm103.po.User" alias="user"/>-->
    <package name="com.wm103.po"/>
</typeAliases>

(4)mappers(映射配置)

  • 通过resource加载单个映射文件,如下:
<mappers>
    <mapper resource="sqlmap/User.xml"/>
    <mapper resource="mapper/UserMapper.xml"/>
</mappers>
  • 批量加载mapper,通过指定mapper接口的包名,MyBatis会自动扫描包下的所有mapper映射文件进行加载。此时,需要遵循一些规范,包下的映射文件才会被扫描到且正确加载。规范如下:
1. mapper接口名同对应的映射文件的名称保持一致;
2. mapper接口和对应的映射文件在同一目录中;
3. 采用的是mapper代理方式

  设置批量加载mapper方式,如下:

<mappers>
    <mapper resource="sqlmap/User.xml"/>
    <!--<mapper resource="mapper/UserMapper.xml"/>-->
    <package name="com.wm103.mapper"/>
</mappers>

知识点扩展或参考

  1. MyBatis官方文档
  2. IDEA构建一个mybatis项目
  3. Mybatis配置之<properties>属性配置元素详述
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MyBatis框架自学之路——简易入门 的相关文章

  • Servlet中不可不知的Cookie技术

    目录 目录介绍Servlet中的CookieCookie重要知识点通过Cookie技术显示用户上次访问时间使用Cookie技术实现记录用户浏览过的商品 显示商品列表和浏览过的商品查看商品详情 xff08 使用Cookie记录浏览信息 xff
  • Servlet中不可不知的Session技术

    目录 目录介绍Session和Cookie的主要区别Session的创建Session的销毁Session的实现原理解决浏览器关闭后就立即丢失Session ID的问题浏览器禁用Cookie后如何使用Session技术 xff1f Sess
  • JSP知识随手记

    目录 目录介绍JSP运行原理JSP最佳实践JSP指令 page指令include指令taglib指令 JSP九大内置对象 out隐式对象pageContext隐式对象 JSP标签映射JSP知识点JSP与JavaBean 关于JavaBean
  • FileZilla连接Linux服务器(Ubuntu)

    目录 目录前言FileZilla使用ubuntu用户密钥的形式连接FileZilla使用root用户密码的形式连接参考 前言 这里使用的是Ubuntu服务器 xff0c 如果是Linux系统的服务器出现这样的问题 xff0c 可能解决方法也
  • JSP中的自定义标签

    目录 目录简介入门案例自定义标签功能扩展传统自定义标签的运行原理传统自定义标签的使用 控制JSP页面部分内容执行控制整个JSP页面是否执行控制标签体执行重复执行用标签修改JSP页面内容 简单标签的运行原理简单标签的使用 控制JSP页面部分内
  • JSP中使用简单标签自定义标签

    目录 目录简介使用标签控制页面逻辑的案例 开发防盗链标签开发cif标签开发cifcelse标签开发cforEach标签使用简单标签实现html转移标签 打包标签库 简介 让标签处理器类继承于SimpleTagSupport类实现自定义标签功
  • Struts2框架自学之路——轻松入门

    目录 目录简介Struts2中的Action Action类的配置webxml中Struts2的过滤器 Struts2的核心配置文件 标签package 标签package的属性 标签action 标签action的属性 标签result
  • 重拾Hibernate框架——入门

    目录 目录Hibernate入门 第一个Hibernate程序 实现数据库操作 Hibernate配置文件详解 Hibernate映射配置文件Hibernate核心配置文件 Hibernate的核心API ConfigurationSess
  • 重拾Hibernate框架——实体类、主键生成策略、session绑定本地线程

    目录 目录实体类持久化类的编写规则Hibernate主键生成策略实体类操作 案例准备对实体类CRUD操作 添加操作查询操作修改操作删除操作saveOrUpdate方法 实体类对象状态Hibernate一级缓存Hibernate事务操作 规范
  • 重拾Hibernate框架——一对多关联

    目录 目录前言一对多映射配置 创建实体类让两个实体类之间相互表示配置映射关系配置核心配置文件Hibernate工具类 一对多关联操作 级联保存级联删除修改操作 inverse属性 前言 这里将以公司和员工为例 xff0c 其中公司与员工是一
  • Visual C++2010学习版详细安装教程

    获取该资源花了本人很长时间 xff0c 为了你们需要VC2010系列的编程软件更容易 xff0c 本人把我找到VC2010系列安装包放在了我的百度网盘分享 xff0c 该资源来之不易 xff0c 请广大朋友们好好珍惜 xff01 由于我换了
  • 重拾Hibernate框架——多对多关联

    目录 目录前言多对多映射配置 创建实体类让两个实体类之间相互表示配置映射关系配置核心配置文件Hibernate工具类 多对多关联操作 级联保存级联删除一般不使用 维护第三张表关系 前言 这里将以用户和角色为例 xff0c 其中用户与角色是多
  • 重拾Hibernate框架——查询操作

    目录 目录前言OID查询对象导航查询HQL查询 查询所有条件查询排序查询分页查询投影查询聚合函数的使用 QBC查询 查询所有条件查询 Restrictions类的常用方法 排序查询 Order类的常用方法 分页查询统计查询 Projecti
  • Struts2框架自学之路——结果页面的配置

    目录 目录Struts2中结果页面的配置 全局结果页面局部结果页面result标签的type属性 Struts2中结果页面的配置 在struts xml核心配置文件中 xff0c 我们可以配置Action类的URL访问路径 xff0c 以及
  • Struts2框架自学之路——Action获取表单数据的方式以及表单数据的封装

    目录 目录Action获取表单数据的方式 通过ActionContext类获取使用ServletActionContext类获取通过特定接口访问在Action中操作域对象 Action中原始方式封装表单数据Struts2中表单数据的封装 属
  • Struts2框架自学之路——值栈

    目录 目录Servlet和Action的区别什么是值栈获取值栈对象值栈的内部结构向值栈存放数据 向值栈存放对象向值栈存放List集合 从值栈获取数据 获取字符串获取对象获取List集合其他操作 EL表达式获取值栈数据 Servlet和Act
  • Struts2框架自学之路——拦截器

    目录 目录Struts2拦截器概述重要知识点自定义拦截器 拦截器的结构自定义登录拦截器 创建登录访问的首页登录页面以及登录操作添加登录拦截器功能 Struts2拦截器概述 Struts2框架封装了很多功能 xff0c 而这些功能大多在拦截器
  • Linux简介及系统安装

    目录 目录Linux简介 Linux的应用Linux与Windows的不同字符界面的优势 Linux系统安装 VMware简介虚拟机的新建与设置注意点Linux的系统分区安装Linux系统Linux系统的安装日志 Linux简介 Linux
  • Linux常用命令

    目录 目录命令基本格式文件处理命令 目录或文件处理Linux中常见目录链接命令 搜索命令 文件搜索命令命令搜索命令字符串搜索命令find命令与grep命令的区别 帮助命令压缩与解压缩命令关机和重启命令其他常用命令 挂载命令用户登录查看和用户
  • 对php-fpm的理解重述

    目录 目录CGI的出现FastCGIphp fpm摘录 FPM的请求处理流程nginx转发请求给FPM 参考 CGI的出现 早期的Web服务器只能处理HTML等静态文件 xff0c 随着PHP等动态语言的出现 xff0c Web Serve

随机推荐

  • Shell编程——基础入门

    目录 目录Shell概述 Shell是什么Shell的分类 脚本执行方式 echo输出命令第一个脚本 Bash的基本功能 命令别名与快捷键历史命令 history命令历史命令的调用命令与文件补全 输入输出重定向 输出重定向输入重定向 多命令
  • Linux命令之<cp命令>

    cp命令用来复制文件或者目录 xff0c 是Linux系统中最常用的命令之一 一般情况下 xff0c shell会设置一个别名 xff0c 在命令行下复制文件时 xff0c 如果目标文件已经存在 xff0c 就会询问是否覆盖 xff0c 不
  • PHPer的进阶探索之旅

    目录 目录前言魔术常量PHP常量详解define和const的区别PHP中的闭包PSR 规范PHP命令空间Web性能优化与HTTP2 前言 作为一个PHPer xff0c 一直认为Java与PHP都 差不多 xff0c 尽管身边的人会说大型
  • Linux下的VIM编辑器

    目录 目录VIM编辑器的概述VIM编辑器的操作模式vim命令的使用操作模式的命令 底行模式的常用指令命令模式的常用指令VIM键位指令图 VIM编辑器的概述 VIM其实VI编辑器的升级版本 VIM相对于VI xff0c 增强的功能 xff1a
  • Linux中的磁盘管理

    目录 目录磁盘管理命令向服务器添加硬盘磁盘分区 分区模式之MBR分区分区模式之GPT分区 分区操作 Linux中的MBR分区Linux中的GPT分区 分区格式化操作挂载分区Linux中的swap分区 磁盘管理命令 xff08 1 xff09
  • Linux中的用户管理

    目录 目录概述关于用户组的配置文件关于用户的配置文件用户和用户组的基本命令 用户组操作用户操作 用户和用户组的进阶命令 主要组与附属组 其他命令 概述 使用操作系统的人 xff0c 我们称之为用户 在Linux中允许多个不同用户同时登录同一
  • Linux中的计划任务Crontab

    目录 目录介绍安装并检查Crontab服务入门栗子Crontab的基本组成 用户任务调度 crontab命令的使用及相关文件Crontab的任务配置格式 系统任务调度系统级任务调度与用户级任务调度 注意事项参考 介绍 Crontab是什么
  • MySQL易忘常用的知识点

    目录 目录前言WHEREDISTINCTGROUP BYSELECT语句完整的执行顺序NOT NULLNULL和default默认值MySQL中文字节问题关于MYSQL Incorrect string value参考 前言 这里介绍MyS
  • MySQL深度掌握之路

    目录 目录前言知识点 前言 知识点 MySQL要求AUTO INCREMENT列必须有某种索引 xff0c 如果没有索引 xff0c 那么表的定义就是不合法的 任何一个PRIMARY KEY列必须是NOT NULL的 如果定义没有设置为NO
  • Linux中Web环境的搭建LNMP

    目录 目录环境搭建准备 为Linux创建后续使用的用户XShell的上传下载上传安装包 Web服务器的搭建 目录的创建php fpm编译安装 安装GCC安装libxml2和libxml2 devel包安装BZip2包安装libcurl包安装
  • 微信第三方小程序授权开发之旅

    目录 目录开发准备开发流程注意事项 开发准备 授权方AppId第三方AppId 开发流程 注意事项 开发过程中 xff0c 处于测试阶段 xff08 未全网发布 xff09 xff0c 需要在微信第三方平台中设置授权测试公众号列表 xff0
  • Linux中的网络管理——计算机网络基础

    目录 目录OSI七层网络模型TCPIP协议四层模型OSI模型与TCPIP模型的比较IP地址 IP地址分类子网掩码 端口DNS DNS服务域名DNS查询 DNS查询过程DNS查询类型 网关 OSI七层网络模型 ISO OSI七层模型 需要说明
  • 在MySQL中使用MD5加密【入门体验】

    什么是MD5 xff1f MD5信息摘要算法 英语 MD5 Message Digest Agorithm xff0c 一种被广泛使用的密码散列函数 xff0c 可以产生出一个128位 16字节 的散列值 hash value xff0c
  • Linux中Web环境memcached和redis安装(FOR PHP)

    目录 目录前言php memcached扩展安装 服务器端安装客户端安装设置memcached开机自启脚本 创建脚本设置服务服务命令 php redis扩展安装 redis安装服务命令开放redis端口redis手动安装 修改redis配置
  • Linux中Web环境安装php的扩展

    目录 文章目录 目录前言安装imagick扩展安装ImageMagick安装php扩展imagick 安装PDO扩展安装PDO组件安装PDO MYSQL组件 前言 继上文 Linux中Web环境memcached和redis安装 xff08
  • Maven项目构建工具的入门使用

    目录 目录前言Maven的介绍及环境搭建创建Maven项目Maven的常用命令自动创建目录骨架Maven中的坐标和仓库 坐标仓库 关于仓库的介绍更改本地仓库的位置 Maven的生命周期和插件 生命周期插件 pom xml常见元素介绍Mave
  • Spring框架自学之路——AOP

    目录 目录AOP 介绍AOP底层原理核心概念 基于AspectJ的Spring AOP操作 AOP操作准备XML方式定义切点案例扩展注解方式 AOP 介绍 AOP xff0c 即面向切面编程 xff0c 简单来说其思想指的是在不修改原有代码
  • Spring框架自学之路——JdbcTemplate

    目录 目录介绍使用JdbcTemplate 准备工作添加操作更新操作删除操作查询操作 返回一个值返回对象 xff08 返回一行数据 xff09 返回List集合 xff08 返回多行数据 xff09 Spring配置c3p0连接池 c3p0
  • Spring框架自学之路——事务管理

    目录 目录前言介绍案例说明案例准备及问题分析声明式事务管理 事务管理器基于XML配置声明式事务 XML配置事务配置说明 基于注解实现声明式事务 注解配置 64 Transactional注意事项 知识点扩展或参考 前言 文中主要介绍的是Sp
  • MyBatis框架自学之路——简易入门

    目录 目录介绍入门案例 准备工作MyBatis的CURD MyBatis框架的基本原理使用MyBatis的工具类测试类查询操作 根据用户ID查询对应的用户记录根据用户名查询一条或多条用户记录 添加操作 自增主键的返回非自增主键的返回 删除操