1 本章前言

注解映射,在方法上添加 SQL 语句注解。不推荐,会使得可读性很差。仅作为了解。

2 创建数据库

创建数据库(mybatis)和表(t_user),完成创建数据库和表的操作后如下图所示:

image

插入一些测试数据:

INSERT INTO `t_user` VALUES (1, '奥利给', '2002-04-28', 18, '男', '上海');
INSERT INTO `t_user` VALUES (2, '蔡徐坤', '2001-06-08', 18, '男', '北京');
INSERT INTO `t_user` VALUES (3, '马保国', '2004-11-12', 42, '男', '深圳');
INSERT INTO `t_user` VALUES (4, '十三姨', '1998-01-18', 18, '女', '大清');

3 创建 Maven 项目

导入 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>
    <!--导入lombok 支持@Data注解-->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.4</version>
        <scope>provided</scope>
</dependency>
</dependencies>

4 创建 User 实体

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

@Data
public class User {
    private int userId;
    private String userName;
    private int userAge;
    private Date userBirthday;
    private String userSex;
    private String userAddress;
}

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 接口

当使用了注解的方式就不在需要 XXXMapper.xml 文件了。

6.1 单表 CRUD

public interface UserMapper {
    @Select("select * from t_user")
    @Results(id = "userMap",value = {
            @Result(property = "userId", column = "id",id = true),
            @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"),
    })
    List<User> selectAllUser();
 
    @Select("select * from t_user where id = #{id}")
    @ResultMap("userMap")
    User selectUserById(Integer id);
 
    @Select("select * from t_user where username like concat('%',#{userName},'%') and address like concat('%',#{userAddress},'%')")
    @ResultMap("userMap")
    List<User> selectUserByNameAndAddress(@Param("userName") String userName,@Param("userAddress") String userAddress);
 
    @Insert("insert into t_user(username,age,birthday,sex,address) values " +
            "(#{userName},#{userAge},#{userBirthday},#{userSex},#{userAddress});")
    Integer insertUser(User user);
 
    @Update("update t_user set username = #{userName},age = #{userAge}, birthday = #{userBirthday}," +
            "sex = #{userSex},address = #{userAddress} where id = #{userId}")
    Integer updateUser(User user);
 
    @Delete("delete from t_user where id = #{id}")
    Integer deleteUser(Integer id);
}

6.2 @ResultMap

查询操作得到包含多个列的集合,将列值转为对象属性使用结果映射的功能,注解 @Results,@ResultMap 能够帮助我们完成此功能。

@Results 用于定义结果映射,每个列和 Java 对象属性的一一对应。

@ResultMap 指定使用哪个结果映射,两种方式可以使用@Results,另一种 XML 文件。

需求:执行多个 select 语句,使用结果映射转换数据库记录为 Java Object。

6.3 SQL 提供者

我们能在方法上面直接编写 SQL 语句。使用 Text Block 编写长的语句。方法上编写 SQL 显的不够简洁。MyBatis 提供了 SQL 提供者的功能。将 SQL 以方法的形式定义在单独的类中。 Mapper 接口通过引用 SQL 提供者中的方法名称,表示要执行的 SQL。

SQL 提供者有四类@SelectProvider,@InsertProvider,@UpdateProvider,@DeleteProvider。

SQL 提供者首先创建提供者类,自定义的。类中声明静态方法,方法体是 SQL 语句并返回 SQL。例如:

public static String selectById() {
        return "SELECT * FROM users WHERE id = #{id}";
}

其次 Mapper 接口的方法上面,应用@SelectProvider(type = 提供者类.class, method = “方法名称”)

step1: 创建 SQL 提供者

public class SqlProvider {
 
  public static String selectArticle(){
    return """
        select id,user_id,title,summary,read_count,create_time,update_time
        from article where id=#{articleId}
        """;
  }
 
 public static String updateTime(){
    return """
        update article set update_time=#{newTime}  where id=#{id}
        """;
  }
}

step2: 创建 mapper 接口

public interface ArticleRepository {
 
  @Select("")
  @Results(id = "BaseMapper", value = {
      @Result(id = true, column = "id", property = "id"),
      @Result(column = "user_id", property = "userId"),
      @Result(column = "read_count", property = "readCount"),
      @Result(column = "create_time", property = "createTime"),
      @Result(column = "update_time", property = "updateTime"),
  })
  ArticlePO articleMapper();
 
  //查询
  @ResultMap("BaseMapper")
  @SelectProvider(type = SqlProvider.class,method = "selectArticle")
  ArticlePO selectById(Integer id);
 
  //更新
  @UpdateProvider(type = SqlProvider.class,method = "updateTime")
  int updateTime(Integer id, LocalDateTime newTime);
}

6.4 注解汇总

Mybatis 中一些常用注解介绍:

  • @Select()、@Insert()、@Update()、@Delete() :基本增删改查注解

  • @Results() :结果映射的列表,相当于 resultMap 标签,id 表示结果映射的名字,value 表示的是 @Result 的数组。注意:@Results 需要和@Select 配合使用,单独的@Results 不会被识别。

  • @Result() :在列和属性或字段之间的单独结果映射。属性有:id, column, property, javaType , jdbcType , typeHandler, one, many。

属性名描述
id是一个布尔值,表示是否为主键
column数据库字段名或者其别名(这个别名是数据库起的,如 username as name)
property实体类属性名
javaType映射 java 的类型
jdbcType映射数据库类型
typeHandler数据库与 Java 类型匹配处理器(可以参考前面的 TypeHandler 部分)
one属性是单独的联系,用来一对一操作, 和 <association> 相似
many属性是对集合而言的,用来一对多操作 , 和 <collection>相似
  • @One :一对一注解。Select 属性必须是已映射语句的完全限定名 (也就是接口的方法),它可以加载合适类型的实例。 FetchType 会覆盖全局的配置参数 lazyLoadingEnabled。
@Result(property = "property", column = "column", javaType = User.class,one=@One(select = "com.thr.mapper.XxxMapper.Method_Name",fetchType = FetchType.DEFAULT)),
  • @Many :一对多注解。Select 属性必须是已映射语句的完全限定名 (也就是接口的方法),它可以加载合适类型的实例的集合,fetchType 会覆盖全局的配置参数 lazyLoadingEnabled。
@Result(property = "property", column = "column", javaType = User.class,many=@Many(select = "com.thr.mapper.XxxMapper.Method_Name",fetchType = FetchType.DEFAULT)),
  • @ResultMap() :用来引用定义的结果映射的列表 (@Results)。这使得注解的@Select 可以复用那些定义在 ResultMap 中的内容。如果同一@Select 注解中还存在@Results 或者@ConstructorArgs,那么这两个注解将被此注解覆盖。

  • @Param() :如果 Mapper 接口中的方法需要多个参数,,这个注解可以被应用于映射器的方法参数来给每个参数一个名字。否则,多参数将会以它们的顺序位置来被命名 (不包括任何 RowBounds 参数) 比如:#{param1} , #{param2} 等 (这是默认的)。使用 @Param (“userName”),SQL 参数就应该被命名为 #{userName}。

7 导入日志文件

导入日志文件,在 resources 目录中创建 log4j.xml 文件(这种方式打印的数据更加清晰),并且导入如下配置。

<?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>

8 编写测试代码

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

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);
    }
    //模糊查询:根据username和address字段
    @Test
    public void testSelectUserByName(){
        List<User> userList = mapper.selectUserByNameAndAddress("三","大");
        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("男");
        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.setUserBirthday(new Date());
        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)? "删除成功!":"删除失败!");
    }
}