Mybatis_1

发布于:2025-07-24 ⋅ 阅读:(10) ⋅ 点赞:(0)

什么是MyBatis

MyBatis是一款优秀的持久层框架,用于简化JDBC的开发。

JDBC流程(√的部分是MyBatis已经集成的):

MyBatis本来是Apache的一个开源项目iBatis,2010年这个项目于由apache迁移到了google code,并且改名为MyBatis。2013年11月迁移到Github。

官网:MyBatis中文网

简单来说MyBatis是更简单完成程序和数据库交互的框架,也就是简单的操作和读取数据库工具。接下来,我们就通过一个入门程序,感受一下如何通过Mybatis来操作数据库。

MyBatis入门 

准备

项目创建

需要在我们之前spring web和lombok依赖的基础上,引入mybatis framework和mysql的驱动包。(这里springBoot版本选择较低的且不带snapshop的版本,否则可能无法引入mybatis framework依赖)。

数据准备
-- 创建数据库
DROP DATABASE IF EXISTS mybatis_test;

CREATE DATABASE mybatis_test DEFAULT CHARACTER SET utf8mb4;

-- 使用数据数据
USE mybatis_test;

-- 创建表[用户表]
DROP TABLE IF EXISTS userinfo;
CREATE TABLE `userinfo` (
        `id` INT ( 11 ) NOT NULL AUTO_INCREMENT,
        `username` VARCHAR ( 127 ) NOT NULL,
        `password` VARCHAR ( 127 ) NOT NULL,
        `age` TINYINT ( 4 ) NOT NULL,
        `gender` TINYINT ( 4 ) DEFAULT '0' COMMENT '1-男 2-女 0-默认',
        `phone` VARCHAR ( 15 ) DEFAULT NULL,
        `delete_flag` TINYINT ( 4 ) DEFAULT 0 COMMENT '0-正常, 1-删除',
        `create_time` DATETIME DEFAULT now(),
        `update_time` DATETIME DEFAULT now(),
        PRIMARY KEY ( `id` ) 
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4; 

-- 添加用户信息
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'admin', 'admin', 18, 1, '18612340001' );
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'zhangsan', 'zhangsan', 18, 1, '18612340002' );
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'lisi', 'lisi', 18, 1, '18612340003' );
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'wangwu', 'wangwu', 18, 1, '18612340004' );

企业建表规范:

1、字段名统一小写,单词之间使用下划线分割

2、建表字段:自增字段,更新时间、创建时间

删除标志:

常见方案:物理删除(delete)/逻辑删除(update)

创建对应实体类userinfo:

@Data
public class Userinfo {
    //实体类的属性需要与表中的字段名一一对应
    private Integer id;
    private String username;
    private String password;
    private Integer age;
    private Integer gender;
    private String phone;
    private Integer deleteFlag;
    private Date createTime;
    private Date updateTime;
}

 配置数据库连接字符串

yml文件配置:

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver

注意:password处需要改为当前数据库的密码。端口号3306/后面跟的是数据库的名称。如果使用MySql是5.x之前需要将driver-class-name改为com.mysql.jdbc.Driver。

写持久层代码

在项目中,创建持久层接口UserMapper:

@Mapper
public interface UserMapper {
    //查询所有用户
    @Select("select * from userinfo")
    List<Userinfo> select();
}

Mybatis的持久层接口规范一般都叫XxxMapper

@Mapper:表示的是Mybatis中的Mapper接口

程序运行时,框架会自动生成接口的实现类对象(代理对象),并交给Spring的IoC容器管理

@Select:代表的是select查询,也就是注解对应方法具体内容的实现。 

单元测试

按住Alt+Insert,按图示进行点击,Idea会自动生成测试类。

测试代码:

@SpringBootTest
class UserMapperTest {
    @Autowired
    private UserMapper mapper;
    @Test
    void select() {
        System.out.println(mapper.select());
    }
}

注意:这里一定要加上@SpringBootTest注解,如果不加,无法拿到mapper对象,会报空指针异常。(加上了注解,该测试类在运行时,就会自动加载Spring运行环境)。 

测试结果:

常见问题
问题1:sql错误

如图,使查询语句错误:

 问题2:陪置信息错误(检查账号密码)

这里我们故意输入一个错误的密码:

问题3:未配置数据库

这里我们将配置数据库的代码注掉:

问题4 :数据库不存在

如图,将数据库改为一个不存在的数据库

问题5:表不存在 

将表名改成一个不存在的表:

问题6:方法名重复 

MyBatis基本操作

MyBatis打印日志 

在配置文件中进行如下配置:

mybatis:
  configuration: # 配置打印 MyBatis⽇志
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

重新运行程序:

参数传递

可以在sql语句中使用” #{参数名} “来获取方法中的参数。

    //传递一个参数
    @Select("select * from userinfo where username = #{username}")
    List<Userinfo> select2(String username);

测试用例: 

@Test
    void testSelect() {
        System.out.println(mapper.select2("zhangsan"));
    }

测试结果:

更改sql语句#{ }中的方法参数名: 

    //传递一个参数
    @Select("select * from userinfo where username = #{name}")
    List<Userinfo> select2(String username);

可以看到可以正常获取:但是当我们传递的参数是多个时(此时sql语句中的#{ }中的参数名仍然与方法中的不同):

//传递多个参数
    @Select("select * from userinfo where delete_flag = #{deleteFlag} and age = #{age}")
    List<Userinfo> select3(Integer flag,Integer age);
}

测试用例: 

  @Test
    void select3() {
        System.out.println(mapper.select3(0, 18));
    }

测试结果: 可以看到报错结果显示没有找到deleteFlag这个参数。

想要解决这个问题一共有三种方法:

方法1:保持sql语句中的#{ }的参数名和方法参数名一致。

 //传递多个参数
    @Select("select * from userinfo where delete_flag = #{deleteFlag} and age = #{age}")
    List<Userinfo> select3(Integer deleteFlag,Integer age);

测试结果:

方法2:在sql中使用param+数字来标记参数 

 //传递多个参数
    @Select("select * from userinfo where delete_flag = #{param1} and age = #{param2}")
    List<Userinfo> select3(Integer deleteFlag,Integer age);

测试结果: 方法3:在方法中使用@Param设置别名

//传递多个参数
    @Select("select * from userinfo where delete_flag = #{deleteFlag} and age = #{age}")
    List<Userinfo> select3(@Param("deleteFlag") Integer flag, Integer age);

测试结果: 

阿里巴巴开发手册建议的写法(如果是使用阿里云创建项目则一定要加上@Param注解):

    //阿里巴巴开发手册建议的写法
    @Select("select * from userinfo where delete_flag = #{deleteFlag} and age = #{age}")
    List<Userinfo> select4(@Param("deleteFlag")Integer deleteFlag,@Param("age")Integer age);

如果结果集只有一个对象时可以使用对象进行接收:

@Select("select * from userinfo where username = #{name}")
    Userinfo select5(String username);

测试代码

    @Test
    void select5() {
        System.out.println(mapper.select5("lisi"));
    }

 测试结果:

 如果返回对象有多个,但是仍然使用对象接收:

  @Select("select * from userinfo where delete_flag = #{deleteFlag} and age = #{age}")
    Userinfo select4(@Param("deleteFlag")Integer deleteFlag,@Param("age")Integer age);

测试代码 :

    @Test
    void select4() {
        System.out.println(mapper.select4(0,18));
    }

可以看到,在对象有多个时并不能采用对象进行接收。因此,在实际开发中查询操作建议都使用List进行接收。

增(Insert)

//增删改返回的都是Integer
    @Insert("insert  into userinfo (username,password,age,gender) values (#{username},#{password},#{age},#{gender}) ")
    //因为传入的属性较多,所以使用对象传递
    Integer insert1(Userinfo userinfo);

 测试代码:

  @Test
    void insert1() {
        Userinfo userinfo = new Userinfo();
        userinfo.setAge(30);
        userinfo.setUsername("tianqi");
        userinfo.setPassword("tianqi");
        userinfo.setGender(2);
        mapper.insert1(userinfo);
    }

 测试结果:

如果使用了@Param修改参数,则在sql中需要使用对象.参数进行获取。 

    @Insert("insert into userinfo (username,password,age,gender) values (#{userinfo.username},#{userinfo.password},#{userinfo.age},#{userinfo.gender})")
    Integer insert2(@Param("userinfo")Userinfo userinfo);

测试代码: 

 @Test
    void insert2() {
        Userinfo userinfo = new Userinfo();
        userinfo.setAge(30);
        userinfo.setUsername("zhaoliu");
        userinfo.setPassword("zhaoliu");
        userinfo.setGender(2);
        Integer i = mapper.insert2(userinfo);
        System.out.println("返回"+i+"条数据");
    }

测试结果: 

 

 返回主键

Insert语句默认返回的是受影响的行数,但是有些情况下,数据插入之后,还需要有后续的关联操作,需要获取到新插入的数据id。

如果要拿到自增id,需要在Mapper接口的方法上添加一个@Options的注解

   @Options(useGeneratedKeys = true,keyProperty = "id")
    //增删改返回的都是Integer
    @Insert("insert  into userinfo (username,password,age,gender) values (#{username},#{password},#{age},#{gender}) ")
    //因为传入的属性较多,所以使用对象传递
    Integer insert1(Userinfo userinfo);

useGeneratedKeys:这会令MyBatis使用JDBC的getGenerateKeys方法来取出由数据库内部生成的主键(比如:Mysql的自增主键,默认值:false)

keyProperty:指定能够唯一识别对象的属性,MyBatis会使用getGenerateKeys的返回值或insert语句的selectKey子元素设置它的值,默认值:未设置。

测试代码:

 @Test
    void insert1() {
        Userinfo userinfo = new Userinfo();
        userinfo.setAge(30);
        userinfo.setUsername("tianqi");
        userinfo.setPassword("tianqi");
        userinfo.setGender(2);
        Integer i = mapper.insert1(userinfo);
        System.out.println("返回"+i+"条数据,id:"+userinfo.getId());
    }

测试结果:

删(delete)

接口代码:

  //删除
    @Delete("delete from userinfo where id = #{id}")
    Integer delete(Integer id);

测试代码:

  @Test
    void delete() {
        Integer delete = mapper.delete(10);
        System.out.println("删除"+delete+"条数据");
    }

测试结果:

改(update)

mapper代码:

    //改
    @Update("update userinfo set username = #{userinfo.username},password = #{userinfo.password},gender = #{userinfo.gender},age = #{userinfo.age} where id = #{userinfo.id}")
    Integer update(@Param("userinfo")Userinfo userinfo);

测试代码 :

   @Test
    void update() {
        Userinfo userinfo = new Userinfo();
        userinfo.setUsername("zhangsan333");
        userinfo.setAge(10);
        userinfo.setGender(1);
        userinfo.setPassword("zhangsan333");
        userinfo.setId(11);
        Integer update = mapper.update(userinfo);
        System.out.println("更新"+update+"条数据");
    }

测试结果: