1 本章前言

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

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

2 创建数据库

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

DROP TABLE IF EXISTS `t_user`;
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,
  `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 = 8 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
 
-- ----------------------------
-- Records of t_user
-- ----------------------------
INSERT INTO `t_user` VALUES (1, '奥利给', 18, '男', '上海');
INSERT INTO `t_user` VALUES (2, '蔡徐坤', 18, '男', '北京');
INSERT INTO `t_user` VALUES (3, '黄飞鸿', 42, '男', '大清');
INSERT INTO `t_user` VALUES (4, '十三姨', 18, '女', '大清');
INSERT INTO `t_user` VALUES (5, '梁宽', 42, '男', '大清');

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 方法,需自己加上。

@Data
public class User {
    private int userId;
    private String userName;
    private int userAge;
    private String 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.entity"/>
    </typeAliases>
 
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=GMT%2B8&amp;useUnicode=true&amp;characterEncoding=utf-8"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
</configuration>

6 编写 Mapper/Dao 接口

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

public interface UserMapper {
    List<User> selectAllUser(); //查询所有用户
    User selectUserById(Integer id); //根据 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 的文件,而不是 comthrmapper 的目录,到时候在加载映射文件的时候报错。

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

  • XML 文件名的命名必须和 Mapper 接口名称相同,例如 UserMapper.xml。
  • SQL 映射文件中 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">
 
<mapper namespace="com.thr.mapper.UserMapper">
    <resultMap id="userMap" type="com.thr.entity.User">
        <id property="userId" column="id"/>
        <result property="userName" column="username"/>
        <result property="userAge" column="age"/>
        <result property="userSex" column="sex"/>
        <result property="userAddress" column="address"/>
    </resultMap>
 
    <select id="selectAllUser" resultMap="userMap">
        select * from t_user;
    </select>
    <select id="selectUserById" parameterType="int" resultMap="userMap">
        select * from t_user where id = #{id};
    </select>
    <select id="selectUserByName" parameterType="int" resultMap="userMap">
        select * from t_user where username like '%${value}%';
    </select>
    <insert id="insertUser" parameterType="com.thr.entity.User">
        insert into t_user(username, age, sex, address)
        values (#{userName}, #{userAge}, #{userSex}, #{userAddress});
    </insert>
    <update id="updateUser" parameterType="com.thr.entity.User">
        update t_user set username = #{userName},age = #{userAge},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 下。

注意:通过注册 Mapper 接口或者包扫描的方式创建 mapper.xml,它的位置必须和 Mapper 接口在相同的包或者相同目录下才能获取到对应的 xml 文件。

...
</environments>
<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.xml 文件(这种方式打印的数据更加清晰),并且导入如下配置(如果 log 报错则以管理员的方式启动 Eclipse 或 IDEA)。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
 
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
 
 <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
   <param name="Encoding" value="UTF-8" />
   <layout class="org.apache.log4j.PatternLayout">
    <param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m  (%F:%L) \n" />
   </layout>
 </appender>
 <logger name="java.sql">
   <level value="debug" />
 </logger>
 <logger name="org.apache.ibatis">
   <level value="info" />
 </logger>
 <root>
   <level value="debug" />
   <appender-ref ref="STDOUT" />
 </root>
</log4j:configuration>

10 编写测试文件

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

public class MybatisTest {
    private SqlSession sqlSession = null;
    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);
		//可以查看 Dao 对象的类
		// UserMapper = {$ Proxy4@1615 } " org.apache.ibatis.binding.MapperProxy@7586beff
		System.out.println("mapper="+mapper.getClass().getName());
    }
 
    @After//在测试方法执行完成之后执行,这里也有提交事务和关闭资源
    public void destroy() throws IOException {
        sqlSession.commit();
        sqlSession.close();
    }
    //查询所有用户数据
    @Test
    public void testSelectAllUser(){
        List<User> listUser = mapper.selectAllUser();
    }
    //根据 Id 查询一个用户数据
    @Test
    public void testSelectUserById(){
        User user = mapper.selectUserById(1);
    }
    //模糊查询:根据 user 表的 username 字段
    @Test
    public void testSelectUserByName(){
        List<User> userList = mapper.selectUserByName("三");
    }
    //添加一个用户数据
    @Test
    public void testInsertUser(){
        User user = new User();
        user.setUserName("法外狂徒张三");
        user.setUserAge(42);
        user.setUserSex("男");
        user.setUserAddress("中国监狱");
        Integer i = mapper.insertUser(user);
        System.out.println(i);
        System.out.println( (i>0)? "添加成功!":"添加失败!");
    }
    //根据 Id 修改用户数据
    @Test
    public void testUpdateUser(){
        //如果设置的 id 不存在,那么数据库没有数据更改
        User user = new User();
        user.setUserId(3);
        user.setUserName("梁宽");
        user.setUserAge(42);
        user.setUserSex("男");
        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)? "删除成功!":"删除失败!");
    }
}