Mybatis3详解(五)——通过Mapper接口(动态代理)加载映射文件(推荐)

1、前言

       前面学习了基于原生接口的xml版本创建Mybatis实例(Left hug链接Right hug),就是通过sqlSession对象调用其内部定义好的相对应的方法,包括增删改查方法,如selectOne、selectList、insert等等,但这种方式在实际中很少使用,不推荐。所以下面我们来学习一种在我们平时开发中最常用也是最实用的开发方式——通过Mapper接口(动态代理)加载映射文件。Mapper接口动态代理的方式需要程序员手动编写Mapper接口(相当于Dao接口),由Mybatis框架将根据接口定义创建接口的动态代理对象,代理对象的方法体实现Mapper接口中定义的方法。

       下面我们就来学习这种方法创建一个Mybatis的实例。

2、创建数据库

      创建数据库(user)和表(t_user),SQL脚本如下:

CREATE TABLE `t_user`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `age` int(11) NULL DEFAULT NULL,
  `birthday` date NULL DEFAULT NULL,
  `sex` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `address` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of t_user
-- ----------------------------
INSERT INTO `t_user` VALUES (1, '唐浩荣', 18, '2020-11-10', '1', '上海');
INSERT INTO `t_user` VALUES (2, '蔡徐坤', 18, '2018-01-18', '0', '北京');
INSERT INTO `t_user` VALUES (3, '黄飞鸿', 18, '2020-11-10', '1', '大清');
INSERT INTO `t_user` VALUES (4, '十三姨', 18, '2020-11-10', '0', '大清');
INSERT INTO `t_user` VALUES (5, '马保国', 18, '2020-11-10', '0', '深圳');

SET FOREIGN_KEY_CHECKS = 1;

       完成创建数据库和表的操作后如下图所示:

image

3、创建Maven项目

       在Eclipse或IDEA中创建一个Maven项目。

image

       然后导入pom依赖,如下:

    <dependencies>
        <!-- Mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.6</version>
        </dependency>
        <!-- mysql驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.21</version>
        </dependency>
        <!-- 日志处理 -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <!-- 单元测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

4、创建User实体

      创建一个User实体类,这里省略了getter、setter和toString方法,需自己加上。

/**
 * 用户实体类
 */
public class User {
    private int userId;
    private String userName;
    private int userAge;
    private Date userBirthday;
    private int userSex;
    private String userAddress;

    //getter、setter、toString方法省略......
}

5、创建Mybatis全局配置文件

       在resources目录中,创建Mybatis的全局配置文件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>
    <!--配置别名-->
    <typeAliases>
        <!-- 对包进行扫描,可以批量进行别名设置,设置规则是:获取类名称,将其第一个字母变为小写 -->
        <package name="com.thr.pojo"/>
    </typeAliases>
    <!-- 配置环境.-->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <!--注意:& 符号复制进去后要改成转义字符 &amp; 才能被系统识别-->
                <property name="url" value="jdbc:mysql://localhost:3306/user?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
</configuration>

       注意这里面配置了别名,扫描所有实体包,给实体类起个别名,别名就是小写字母的类名。

6、编写Mapper接口

       Mapper接口代码代码如下(命名不一定是XxxMapper,也可以是XxxDao等等):

public interface UserMapper {
    //查询所有用户
    List<User> selectAllUser();
    //根据id查询用户
    User selectUserById(Integer id);
    //根据用户名模糊查询用户列表
    List<User> selectUserByName(String userName);
    //添加用户
    Integer insertUser(User user);
    //修改用户信息
    Integer updateUser(User user);
    //删除用户
    Integer deleteUser(Integer id);
}

7、编写SQL映射文件

       在resources里创建目录:com/thr/mapper,然后在里面创建映射配置文件UserMapper.xml。注意:目录在创建时是斜杠(/)而不是点(.),如果用点(.)的话表示创建了一个名字为com.thr.mapper的文件,而不是com->thr->mapper的目录,到时候在加载映射文件的时候报错。

       编写映射文件的注意事项如下(非常重要!非常重要!非常重要!):

  • ①、创建的位置必须和Mapper接口在相同的包(目录)下。
  • ②、文件名的命名必须和Mapper接口名称相同,例如UserMapper.xml。
  • ③、命名空间namespace必须对应Mapper接口的全限定类名。
  • ④、增删改查元素中的id与Mapper接口中的方法必须对应。
  • ⑤、parameterType的类型必须和Mapper接口方法的输入参数类型相同。
  • ⑥、resultType的类型必须和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">
<!-- namespace:命名空间,它的作用就是对SQL进行分类化管理,可以理解为SQL隔离
	注意:使用mapper接口代理开发时,namespace有特殊且重要的作用,
	必须是对应的Mapper接口的全限定名,否则找不到sql映射
 -->
<mapper namespace="com.thr.mapper.UserMapper">
    <!-- 配置查询结果的列名和实体类的属性名的对应关系 -->
    <!--id:唯一标识,type:需要映射的java类型-->
    <resultMap id="userMap" type="com.thr.pojo.User">
        <!-- 与主键字段的对应,property对应实体属性,column对应表字段 -->
        <id property="userId" column="id"/>
        <!-- 与非主键字段的对应,property对应实体属性,column对应表字段 -->
        <result property="userName" column="username"/>
        <result property="userAge" column="age"/>
        <result property="userBirthday" column="birthday"/>
        <result property="userSex" column="sex"/>
        <result property="userAddress" column="address"/>
    </resultMap>

    <!-- 查询所有用户-->
    <select id="selectAllUser" resultMap="userMap">
        select * from t_user
    </select>
    <!--根据id查询用户-->
    <select id="selectUserById" parameterType="int" resultMap="userMap">
        select * from t_user where id = #{id}
    </select>
    <!-- 模糊查询,根据username字段查询用户-->
    <select id="selectUserByName" parameterType="string" resultMap="userMap">
        select * from t_user where username like concat('%',#{userName},'%')
    </select>
    <!--添加用户-->
    <insert id="insertUser" parameterType="user">
        insert into t_user(username,age,birthday,sex,address) values (#{userName},#{userAge},#{userBirthday},#{userSex},#{userAddress});
    </insert>
    <!--修改用户信息-->
    <update id="updateUser" parameterType="user">
        update t_user set username = #{userName},age = #{userAge},
        birthday = #{userBirthday},sex = #{userSex},address = #{userAddress}
        where id = #{userId}
    </update>
    <!--删除用户-->
    <delete id="deleteUser" parameterType="int">
        delete from t_user where id = #{id}
    </delete>
</mapper>

8、加载映射文件

       将上面创建的UserMapper.xml文件添加至全局配置文件mybatis-config.xml下。

image

    <mappers>
        <!-- 注册UserMapper.xml文件 -->
        <!-- 这种方式Mapper接口和mapper.xml文件可以不在一个包下 -->
        <!--<mapper resource="com/thr/mapper/UserMapper.xml"/>-->

        <!-- 注册Mapper接口 -->
        <!-- 通过注册Mapper接口方式: Mapper接口和mapper.xml必须在同一个包下,并且二者名字也必须相同-->
        <mapper class="com.thr.mapper.UserMapper"/>

        <!-- 扫描包下的所有mapper接口并进行注册,规则必须是同包同名 -->
        <!--<package name="com.thr.mapper"/>-->
    </mappers>

9、导入日志文件

       导入日志文件,在resources目录中创建log4j.properties文件,并且导入如下配置(如果log报错则以管理员的方式启动Eclipse或IDEA)。

log4j.rootLogger=DEBUG, Console
#Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
log4j.logger.java.sql.ResultSet=INFO
log4j.logger.org.apache=INFO
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG 

10、编写测试文件

       最后创建一个MybatisTest的测试类,其源代码如下所示:

package com.thr.test;

import com.thr.mapper.UserMapper;
import com.thr.pojo.User;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;


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

//Mybatis的测试
public class MybatisTest {
    //定义 SqlSession
    private SqlSession sqlSession = null;
    //定义 UserMapper对象
    private UserMapper mapper = null;

    @Before//在测试方法执行之前执行
    public void getSqlSession(){
        //1、加载 mybatis 全局配置文件
        InputStream is = MybatisTest.class.getClassLoader().getResourceAsStream("mybatis-config.xml");
        //2、创建SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        //3、根据 sqlSessionFactory 产生 session
        sqlSession = sqlSessionFactory.openSession();
        //4、创建Mapper接口的的代理对象,getMapper方法底层会通过动态代理生成UserMapper的代理实现类
        mapper = sqlSession.getMapper(UserMapper.class);
    }

    @After//在测试方法执行完成之后执行
    public void destroy() throws IOException {
        sqlSession.commit();
        sqlSession.close();

    }
    //查询所有用户数据
    @Test
    public void testSelectAllUser(){
        List<User> listUser = mapper.selectAllUser();
        for (User user : listUser) {
            System.out.println(user);
        }
    }
    //根据Id查询一个用户数据
    @Test
    public void testSelectUserById(){
        User user = mapper.selectUserById(1);
        System.out.println(user);
    }
    //模糊查询:根据 user 表的username字段
    @Test
    public void testSelectUserByName(){
        List<User> userList = mapper.selectUserByName("三");
        for(User user : userList){
            System.out.println(user);
        }
    }
    //添加一个用户数据
    @Test
    public void testInsertUser(){
        User user = new User();
        user.setUserName("纳兰元述");
        user.setUserAge(42);
        user.setUserBirthday(new Date());
        user.setUserSex(1);
        user.setUserAddress("大清");
        Integer i = mapper.insertUser(user);
        System.out.println( (i>0)? "添加成功!":"添加失败!");
    }
    //根据Id修改用户数据
    @Test
    public void testUpdateUser(){
        //如果设置的 id不存在,那么数据库没有数据更改
        User user = new User();
        user.setUserId(3);
        user.setUserName("梁宽");
        user.setUserAge(42);
        user.setUserBirthday(new Date());
        user.setUserSex(1);
        user.setUserAddress("大清");
        Integer i = mapper.updateUser(user);
        System.out.println( (i>0)? "修改成功!":"修改失败!");
    }
    //根据Id删除用户数据
    @Test
    public void testDeleteUser(){
        Integer i = mapper.deleteUser(3);
        System.out.println( (i>0)? "删除成功!":"删除失败!");
    }
}
原文地址:https://www.cnblogs.com/tanghaorong/p/13944848.html