MyBatis的基础操作
- 1.打印日志
 - [2. 参数传递](#2. 参数传递)
 - 
- 2.1不传参
 - [2.2 固定参数](#2.2 固定参数)
 
 - [3. 增(Insert)](#3. 增(Insert))
 - 
- [3.1 用对象接参](#3.1 用对象接参)
 - [3.2 用@param注解接收参数](#3.2 用@param注解接收参数)
 - [3.3 返回主键](#3.3 返回主键)
 
 - [4. 删(Delete)](#4. 删(Delete))
 - 
- [4.1 用Integer接参](#4.1 用Integer接参)
 - [4.2 用对象接参](#4.2 用对象接参)
 
 - [5. 改(Update)](#5. 改(Update))
 - [6. 查(Select)](#6. 查(Select))
 - 
- [6.1 查](#6.1 查)
 - [6.2 拼接SQL语句](#6.2 拼接SQL语句)
 - [6.3 列名和属性名匹配](#6.3 列名和属性名匹配)
 - 
- [6.3.1 起别名 as](#6.3.1 起别名 as)
 - [6.3.2 结果映射 @Result](#6.3.2 结果映射 @Result)
 - [6.3.3 配置文件中开启驼峰命令](#6.3.3 配置文件中开启驼峰命令)
 
 
 
1.打印日志
在Mybatis当中我们可以借助⽇志, 查看到sql语句的执⾏、执⾏传递的参数以及执⾏结果
在配置⽂件中进⾏配置即可
在Applicaion.yml配置文件中添加:
            
            
              java
              
              
            
          
          mybatis:
  configuration: # 配置打印 MyBatis⽇志
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
        或,在Applicaion.properties配置文件中添加:
            
            
              java
              
              
            
          
          mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
        当我们在测试类中运行后,可以在控制面板中看到打印的详细日志:

在下面的章节中可通过起别名来解决该问题
2. 参数传递
2.1不传参
查询所有的用户(不传参):
            
            
              java
              
              
            
          
          @Mapper
public interface UserInfoMapper {
	// 查询所有用户
    @Select("select * from user_info")
    List<UserInfo> queryAllUser();
}
        运行结果:
从MySQL中查询的结果:

Java中UserInfo类的属性:

为什么有的属性为空值呢?
说明MySQL的对象与Java的对象之间的映射出现了问题,通常是java对象的属性和MySQL对象的字段没有对应上

2.2 固定参数
需求: 查找id=4的用户,对应的SQL就是: select * from user_info where id=4
            
            
              java
              
              
            
          
          @Mapper
public interface UserInfoMapper {
    
    @Select("select * from user_info where id =4 ")
    UserInfo queryById();
}
        但是这样的话, 只能查找id=4 的数据, 所以SQL语句中的id值不能写成固定数值,需要变为动态的数值解决⽅案:在queryById⽅法中添加⼀个参数(id),将⽅法中的参数,传给SQL语句
使⽤ #{} 的⽅式获取⽅法中的参数:
            
            
              java
              
              
            
          
          @Mapper
public interface UserInfoMapper {
    @Select("select * from user_info")
    List<UserInfo> queryAllUser();
    // 获取参数中的 id
    @Select("select * from user_info where id = #(id) ")
    UserInfo queryById(Integer id);
}
        如果mapper接⼝⽅法形参只有⼀个普通类型的参数,#{...} ⾥⾯的属性名可以随便写,如:#{id}、#{value}。建议和参数名保持⼀致
添加测试⽤例:

也可以通过 @Param , 设置参数的别名, 如果使⽤ @Param 设置别名, #{...}⾥⾯的属性名必须和@Param 设置的⼀样:
            
            
              java
              
              
            
          
          @Mapper
public interface UserInfoMapper {
    // 获取参数中的 UserId
    @Select("select * from user_info where id = #{userId} ")
    UserInfo queryById(@Param("userId") Integer id);
}
        3. 增(Insert)
3.1 用对象接参
Mapper接口:
            
            
              java
              
              
            
          
          @Mapper
public interface UserInfoMapper {
    @Insert("insert into user_info (username, password, age, gender, phone) values(#{username}, #{password}, #{age}, #{gender}, #{phone})")
    Integer insert(UserInfo userInfo); //用UserInfo获取
}
        解释:自动从userInfo对象中找出username、password等属性
测试代码:
            
            
              java
              
              
            
          
          @Slf4j
@SpringBootTest //启动Sring 容器
class UserInfoMapperTest {
    @Autowired
    private UserInfoMapper userInfoMapper;
    @Test
    void insert() {
        UserInfo userInfo =new UserInfo();
        userInfo.setUsername("liming");
        userInfo.setPassword("liming");
        userInfo.setAge(18);
        userInfo.setGender(1);
        userInfo.setPhone("888888");
        userInfoMapper.insert(userInfo);
    }
}
        运行结果:

在mysql中查询:

3.2 用@param注解接收参数
下面代码中的SQL语句是拼接的(用两行表示):
            
            
              java
              
              
            
          
          @Mapper
public interface UserInfoMapper {
    @Insert("insert into user_info (username, password, age, gender, phone)"+
    "values(#{username}, #{password}, #{age}, #{gender}, #{phone})")
    Integer insert(@Param("userInfo") UserInfo uInfo);
}
        测试代码:
            
            
              java
              
              
            
          
          @Slf4j
@SpringBootTest //启动Sring 容器
class UserInfoMapperTest {
    @Test
    void insert() {
        UserInfo userInfo =new UserInfo();
        userInfo.setUsername("lisi");
        userInfo.setPassword("lisi");
        userInfo.setAge(20);
        userInfo.setGender(1);
        userInfo.setPhone("888888");
        userInfoMapper.insert(userInfo);
    }
}
        运行结果:

报错解释:SQL语句中的#{username}找不到在哪,但是有一个参数userInfo
说明重命名后不能自动从对象userInfo中找出username属性,重命名对象后需要在@Insert中准确表达插入属性的来源:
            
            
              java
              
              
            
          
          @Mapper
public interface UserInfoMapper {
    @Insert("insert into user_info (username, password, age, gender, phone)"+
            " values(#{userInfo.username}, #{userInfo.password}, #{userInfo.age},"+ "" +
            " #{userInfo.gender}, #{userInfo.phone})")
    Integer insert(@Param("userInfo") UserInfo uInfo);
}
        运行结果:

MySQL中:

3.3 返回主键
Insert 语句默认返回的是受影响的⾏数,但有些情况下, 数据插⼊之后, 还需要有后续的关联操作, 需要获取到新插⼊数据的id
⽐如订单系统
当我们下完订单之后, 需要通知物流系统, 库存系统, 结算系统等, 这时候就需要拿到订单ID
如果想要拿到⾃增id, 需要在Mapper接⼝的⽅法上添加⼀个Options的注解:
            
            
              java
              
              
            
          
          @Mapper
public interface UserInfoMapper {
    @Options(useGeneratedKeys= true, keyProperty = "id") //把返回的主键赋值给id
    @Insert("insert into user_info (username, password, age, gender, phone)"+
            "values(#{username}, #{password}, #{age}, #{gender}, #{phone})")
    Integer insert(UserInfo userInfo);
}
        解释:
useGeneratedKeys:这会令 MyBatis 使⽤ JDBC 的 getGeneratedKeys ⽅法来取出由数据库内部⽣成的主键(⽐如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的⾃动递增字段),默认值:false.
keyProperty:指定能够唯⼀识别对象的属性,MyBatis 会使⽤ getGeneratedKeys 的返回值或 insert 语句的 selectKey ⼦元素设置它的值,默认值:未设置(unset)
测试代码:
            
            
              java
              
              
            
          
          @Slf4j
@SpringBootTest //启动Sring 容器
class UserInfoMapperTest {
    @Autowired
    private UserInfoMapper userInfoMapper;
    @Test
    void insert() {
        UserInfo userInfo =new UserInfo();
        userInfo.setUsername("lisi");
        userInfo.setPassword("lisi");
        userInfo.setAge(20);
        userInfo.setGender(1);
        userInfo.setPhone("888888");
        Integer count = userInfoMapper.insert(userInfo);
        log.info("影响的行数:"+count + "  返回的id:"+ userInfo.getId());
    }
}
        运行结果:

注意: 设置 useGeneratedKeys=true 之后, 方法返回值依然是受影响的行数,自增id会返回到上述 keyProperty 指定的属性中.
4. 删(Delete)
4.1 用Integer接参
Mapper接口:
            
            
              java
              
              
            
          
          @Mapper
public interface UserInfoMapper {
    @Delete("delete from user_info where id = #{id}")
    Integer delete(Integer id);
}
        测试代码:
            
            
              java
              
              
            
          
          @Slf4j
@SpringBootTest //启动Sring 容器
class UserInfoMapperTest {
    @Test
    void delete() {
        Integer count = userInfoMapper.delete(1);
    }
}
        运行结果:

MySQL:

4.2 用对象接参
mapper接口:
            
            
              java
              
              
            
          
          @Mapper
public interface UserInfoMapper {
    @Delete("delete from user_info where id = #{id}")
    Integer delete(UserInfo userInfo);
}
        测试代码:
            
            
              java
              
              
            
          
              @Test
    void delete() {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(2);
        Integer count = userInfoMapper.delete(userInfo);
    }
}
        运行结果:

MySQL:

5. 改(Update)
mapper接口:
            
            
              java
              
              
            
          
          @Mapper
public interface UserInfoMapper {
    @Update("update user_info set username=#{username} where id = #{id} ")
    Integer update(UserInfo userInfo);
}
        测试代码:
            
            
              java
              
              
            
          
          @Slf4j
@SpringBootTest //启动Sring 容器
class UserInfoMapperTest {
    @Test
    void update() {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(9);
        userInfo.setUsername("88888");
        userInfoMapper.update(userInfo);
    }
}
        运行结果:

MySQL:

6. 查(Select)
6.1 查
mapper接口:
            
            
              java
              
              
            
          
          @Mapper
public interface UserInfoMapper {
    // 注意,企业中尽量不用 *
    @Select("select username, password, age, gender, phone,delete_flag,create_time,update_time from user_info")
    List<UserInfo> queryAllUser();
}
        测试代码:
            
            
              java
              
              
            
          
          @Slf4j
@SpringBootTest //启动Sring 容器
class UserInfoMapperTest {
    @Test
    void queryAllUser() {
        List<UserInfo> list = userInfoMapper.queryAllUser();
        for(Object item: list) {
            log.info(item.toString());
        }
    }
}
        运行结果:

6.2 拼接SQL语句
下面代码中的SQL语句是拼接的(用两行表示):
            
            
              java
              
              
            
          
          @Mapper
public interface UserInfoMapper {
    // 注意,企业中尽量不用 *
    @Select("select username, password, age, gender, phone,delete_flag,create_time,update_time"+
            "from user_info")
    List<UserInfo> queryAllUser();
}
        运行结果:

SQL语句错误,再看日志里面的结果可以发现update_time和from写一起了

正确的SQL拼接:
            
            
              java
              
              
            
          
          @Mapper
public interface UserInfoMapper {
    // 注意,企业中尽量不用 *
    @Select("select username, password, age, gender, phone,delete_flag,create_time,update_time"+
            " from user_info")
    List<UserInfo> queryAllUser();
}
        图解:

运行结果:

上述图片中看到的是SQL语句运行的结果,java对象映射的结果如下:
该Mapper接口如下:
            
            
              java
              
              
            
          
          @Mapper
public interface UserInfoMapper {
    // 注意,企业中尽量不用 *
    @Select("select id,username, password, age, gender, phone,delete_flag,create_time,update_time"+
            " from user_info")
    List<UserInfo> queryAllUser();
}
        运行结果:

上述图片是SQL语句运行的结果,查询的结果映射到java对象中的结果是:

从运⾏结果上可以看到, 我们SQL语句中, 查询了delete_flag, create_time, update_time, 但是这⼏个属性却没有赋值.
MyBatis 会根据方法的返回结果进⾏赋值.
方法用对象 UserInfo接收返回结果, MySQL 查询出来数据为⼀条, 就会自动赋值给对象.
方法用List接收返回结果, MySQL 查询出来数据为多条时, 也会⾃动赋值给List。
但是⽅法使⽤UserInfo接收,MySQL 查询返回的数据为多条时, MyBatis执⾏就会报错。
原因分析 :
当对象中有多个属性时,自动映射查询结果时,MyBatis 会获取结果中返回的列名并在 Java 类中查找相同名字的属性。 这意味着如果发现了 id 列和 id 属性,MyBatis 会将列 id的值赋给 id 属性,如果发现了delete_flag列和 deleteFlag属性,MyBatis 不会将delete_flag列的值赋给 deleteFlag属性。

解决方法在下面的章节
6.3 列名和属性名匹配
6.3.1 起别名 as
在SQL语句中,给列名起别名,保持别名和实体类属性名⼀样(Mapper接口):
            
            
              java
              
              
            
          
          @Mapper
public interface UserInfoMapper {
    // 注意,企业中尽量不用 *
    @Select("select id, username, password, age, gender, phone,"+
            "delete_flag as deleteFlag,create_time as createTime,"+
            "update_time as updateTime"+
            " from user_info")
    List<UserInfo> queryAllUser();
}
        测试代码:
            
            
              java
              
              
            
          
          @Slf4j
@SpringBootTest //启动Sring 容器
class UserInfoMapperTest {
    @Test
    void queryAllUser() {
        List<UserInfo> list = userInfoMapper.queryAllUser();
        for (Object item : list) {
            log.info(item.toString());
        }
    }
}
        运行结果:

6.3.2 结果映射 @Result
需要使用@Result注解进行映射(Mapper接口):
            
            
              java
              
              
            
          
          @Mapper
public interface UserInfoMapper {
    @Results({
            @Result(column="delete_flag", property="deleteFlag"),
            @Result(column="create_time", property="createTime"),
            @Result(column="update_time", property="updateTime")
    })
    // 注意,企业中尽量不用 *
    @Select("select id,username, password, age, gender, phone,delete_flag,create_time,update_time "+
            " from user_info")
    List<UserInfo> queryAllUser();
}
        一个@Results可以被重复使用,给@Results设置id,其他的方法使用@ResultMap时只需要指定value就行了:
            
            
              java
              
              
            
          
          @Mapper
public interface UserInfoMapper {
	// 设置Result id
    @Results(id ="queryAllUser" , value={
            @Result(column="delete_flag", property="deleteFlag"),
            @Result(column="create_time", property="createTime"),
            @Result(column="update_time", property="updateTime")
    })
    // 注意,企业中尽量不用 *
    @Select("select id,username, password, age, gender, phone,delete_flag,create_time,update_time "+
            " from user_info")
    List<UserInfo> queryAllUser();
    // 使用ResultMapper
    @ResultMap(value ="queryAllUser")
    @Select("select id,username, password, age, gender, phone,delete_flag,create_time,update_time "+
            " from user_info")
    List<UserInfo> queryAllUser_2();
        
测试代码:
            
            
              java
              
              
            
          
          @Slf4j
@SpringBootTest //启动Sring 容器
class UserInfoMapperTest {
    @Test
    void queryAllUser() {
        List<UserInfo> list = userInfoMapper.queryAllUser();
        for (Object item : list) {
            log.info(item.toString());
        }
    }
}
        运行结果:

图解:

6.3.3 配置文件中开启驼峰命令
在配置文件Application.yml文件中添加如下的配置:
            
            
              java
              
              
            
          
          mybatis:
  configuration:
    map-underscore-to-camel-case: true #配置驼峰⾃动转换
        在配置文件Application.properties文件中添加如下的配置:
            
            
              java
              
              
            
          
          mybatis.configuration.map-underscore-to-camel-case: true #配置驼峰⾃动转换
        Mapper接口:
            
            
              java
              
              
            
          
          @Mapper
public interface UserInfoMapper {
    @Select("select id,username, password, age, gender, phone,delete_flag,create_time,update_time "+
            " from user_info")
    List<UserInfo> queryAllUser();
}
        测试代码:
            
            
              java
              
              
            
          
          @Slf4j
@SpringBootTest //启动Sring 容器
class UserInfoMapperTest {
    @Test
    void queryAllUser() {
        List<UserInfo> list = userInfoMapper.queryAllUser();
        for (Object item : list) {
            log.info(item.toString());
        }
    }
}
        运行结果:

数据库的字段名 => 类的属性名
驼峰命名规则: abc_xyz => abcXyz
表中字段名:abc_xyz
类中属性名:abcXyz