栏目分类:
子分类:
返回
终身学习网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
终身学习网 > IT > 软件开发 > 后端开发 > Java

不会 MyBatis?看这篇文章就对了,吐血推荐

Java 更新时间:发布时间: 百科书网 趣学号
1. 为啥要用 MyBatis

我们作为一个程序员,主要工作归根结底就是和数据打交道。而使用 java 操作数据库的原始方式就是 JDBC。

先看看使用 JDBC 方式是如何操作数据库的:

// 1. 加载配置文件
Properties pro=new Properties();
pro.load(new FileReader("resource/jdbc.properties"));
// 2. 获取配置文件中连接数据库的信息
String url=pro.getProperty("url");
String user=pro.getProperty("user");
String password=pro.getProperty("password");
String driver=pro.getProperty("driver");
// 3. 加载数据库的驱动
Class.forName(driver);
// 4. 创建数据库的连接
Connection conn = DriverManager.getConnection(url, user, password);
 // 5. sql 语句
String sql = "select * from s_admin where username=? and password=?";
// 3. 创建执行sql的对象
ps = conn.prepareStatement(sql);
// 4. 给 ?赋值
ps.setString(1, username);
ps.setString(2, password);
// 5. 执行sql
ResultSet rs = ps.executeQuery();
// 6. 如果查询出数据,则返回该条数据
if (rs.next()) {
    Admin admin = new Admin();
    admin.setUsername(rs.getString("username"));
    admin.setPassword(rs.getString("password"));
    return admin;
// 7. 否则返回空
} else {
    return null;
}

看完上面的代码,我们发现了 JDBC 存在的问题:

1.每次操作我们都要创建 connection、Statement 等一些对象,操作完还要关闭、销毁这些对象。

2.ResultSet 不能帮我们完成数据库和实体对象的自动转换,我们还要手动赋值。

3.代码冗余,而且业务操作竟然和数据库操作混在一起,开发效率太低了。

真是越来越不想用 JDBC 了,那有没有一个玩意能帮我解决上面 JDBC 遇到的问题呢?

有的,盖世英雄MyBatis踩着七彩祥云来了。

2. MyBatis 简介

官网地址:

https://mybatis.org/mybatis-3/

MyBatis 是一个基于 java 的持久层框架,它内部封装了 jdbc。

开发人员只需要关注 sql 语句,不需要处理加载驱动、创建连接等繁琐的过程。

MyBatis 通过 xml 或注解两种方式配置 sql 语句,然后执行 sql 并将结果映射为 java 对象并返回。

名词解释:

框架:框架是系统中可复用的设计,其实就相当于一个封装了很多功能的工具。

持久层:就是和数据库打交道的那一层。

3. 环境搭建

1.创建数据库和表

我们使用 Navicat 创建数据库 mybatis_demo,然后创建 user 表。

CREATE TABLE `user` (
  `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
  `name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '姓名',
  `sex` varchar(1) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '性别',
  `age` int DEFAULT NULL COMMENT '年龄',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;



2.创建 Maven 项目

File -> New -> Project -> Maven



引入依赖


    
    
        junit
        junit
        4.12
        test
    
    
    
        mysql
        mysql-connector-java
        8.0.27
    
    
    
        org.mybatis
        mybatis
        3.5.3
    


3.创建实体类

User 类:

public class User {
    private int id;
    private String name;
    private String sex;
    private int age;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

4.创建 Dao 接口

public interface UserDao {
    
    List  getAll();
}

5.创建 sql 映射文件

这是一个 mybatis 使用的配置文件,专门用来写 sql 语句的。

它是一个 xml 文件,因为 sql 语句包含在 mapper 标签中,所以又叫 mapper 文件。一般来说一个表对应一个 xml 文件。

规定:文件名称要和接口保持一致。

UserDao.xml:





  
      select * from user
  



6.创建 MyBatis 主配置文件

主配置文件也是 xml 文件。

mybatis-config.xml:




    
    
    
        
    

    
    
        
        
            
            
            
            
                
                
                
                
                
            
        
    

    
    
        
    


7.编写测试类

public class UserTest {

    @Test
    public void testUser() throws IOException {
        // 1.读取配置文件
        InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
        // 2.创建 SqlSessionFactory 工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        // 3.获取 SqlSession 对象
        SqlSession session = factory.openSession();
        // 4.使用 SqlSession 创建 Dao 接口的代理对象
        UserDao userDao = session.getMapper(UserDao.class);
        // 5.执行接口的方法
        List userList = userDao.getAll();
        userList.forEach(user ->{
            System.out.println("姓名:"+user.getName()+",性别:"+user.getSex()+",年龄:"+user.getAge());
        });
    }
}

8.执行结果

9.完整目录结构

4. MyBatisUtil

上面测试代码中读取配置文件、获取 sqlsession 对象等都是一些重复性的操作,我们可以将这些代码封装到一个工具类中。

MyBatisUtil:

public class MyBatisUtil {

    // 定义 SqlSessionFactory
    private static SqlSessionFactory factory;

    // 使用静态块只创建一次 SqlSessionFactory
    static {
        try {
            // 读取配置文件
            InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
            // 创建 SqlSessionFactory 对象
            factory = new SqlSessionFactoryBuilder().build(in);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 获取 SqlSession 对象
    public static SqlSession getSqlSession() {
        SqlSession sqlSession = factory.openSession();
        return sqlSession;
    }

    // 提交事务
    public static void commit(SqlSession sqlSession) {
        if (null != sqlSession) {
            sqlSession.commit();
        }
        close();
    }

    // 回滚事务
    public static void rollBack(SqlSession sqlSession) {
        if (null != sqlSession) {
            sqlSession.rollback();
        }
        close();
    }

    // 关闭 SqlSession
    public static void close() {
        SqlSession sqlSession = getSqlSession();
        if (null != sqlSession) {
            sqlSession.close();
        }
    }
}
5. 增删改查

这里我们使用 MyBatisUtil 实现用户的增删改查操作。

UserDao:

public interface UserDao {

    // 获取所有用户信息
    List getAll();

    // 新增用户
    boolean add(User user);

    // 修改用户
    boolean update(User user);

    // 删除用户
    boolean delete(int id);
}

UserDao.xml:





    
    select * from user

为了简化代码,MyBatis 允许我们给全路径名起一个简单的别名,一般是实体类的类名。我们可以在 mybatis-config.xml 里面这样配置:



    

上面 name 的值一般是实体类所在包的全路径,配置完之后我们就可以直接用 user 代替 com.xxl.model.User 了。


  select name from user where id = #{id}

对象类型

接口方法

 User getUser(int id);

mapper 文件:


    select * from user

② resultMap

当数据库表中的列名和实体类的属性名不一致的时候,我们可以使用 resultMap 定义 sql 的结果和 java 对象属性的映射关系。

例如:


   
    
    
    



    select * from user where name like '%${value}%'

方式二


    select * from user where id = #{uId}



    delete from user where id = #{user_id}

多个参数

1.传递多个参数

传输多个参数,Mybatis会将这些参数放到map集合里面,可以通过 @Param 指定mapper 文件中参数的名字。例如:

接口:

List getUser(@Param("userName") String name,@Param("userSex") int age);

mapper 文件:


    select * from user where name = #{userName} and age = #{userAge}

9. 动态 SQL

动态 SQL 是 MyBatis 强大特性之一,主要用于解决查询条件不确定的情况,它可以极大的简化我们拼装 SQL 的操作。

1.if 标签

If 标签用于完成简单的判断,当标签中 test 的值为 true 时,会将其包含的 SQL 片段拼接到其所在的 SQL 语句中。

语法格式:

 sql 片段 

例如:


    select id,name,age,sex from user
   
       
           and name = #{name}
       
   

3.trim 标签

trim 标签可以在条件判断完的 sql 语句前后添加或者去掉指定的字符。

  • prefix: 添加前缀
  • prefixOverrides: 去掉前缀
  • suffix: 添加后缀
  • suffixOverrides: 去掉后缀

例如:


    select id,name,age,sex from user
    
        
            
                id = #{id}
            
            
                name =  #{name}
            
            
                sex = '男'
            
        
    

5.set 标签

set 标签主要是用于解决修改操作中 sql 语句中可能多出逗号的问题。

例如:


    update user
    
        
            name = #{name},
        
        
            sex = #{sex},
        
        
            age = #{age}
        
    
    where id = #{id}

6.foreach 标签

foreach 标签主要用于循环迭代。

  • collection: 要迭代的集合
  • item: 当前从集合中迭代出的元素
  • open: 开始字符
  • close:结束字符
  • separator: 元素与元素之间的分隔符
  • 迭代的是List集合: index表示的当前元素的下标
  • 迭代的Map集合: index表示的当前元素的key

例如:


    select
    
    from user

10. 注解式开发

通过观察 Mapper 文件我们发现,Mapper 文件的核心就是与 Dao 做接口映射,然后里面写一些 sql 语句。

那我能不能不要 mapper 文件,直接在接口里面写 sql 语句?可以的,MyBatsi 为我们提供了注解式开发。

1.修改主配置文件

虽然不用写 mapper 文件了,但是我们要在接口里面写 sql 语句,你得让 MyBatis 知道吧。所以需要告诉 MyBatis 带有注解的接口在哪里。



   

  1. 注解式开发
public interface UserDao {
    // 获取所有用户信息
    @Select("select * from user")
    List getUser();

    // 新增用户
    @Insert("insert into user(name,sex,age) values(#{name},#{sex},#{age})")
    boolean add(User user);

    // 修改用户
    @Update("update user set name = #{name}, sex = #{sex},age = #{age} where id = #{id}")
    boolean update(User user);

    // 删除用户
    @Delete("delete from user where id = #{id}")
    boolean delete(int id);
}

3.测试

  @Test
  public void testGetAll(){
      // 1.获取 SqlSession 对象
      SqlSession session = MyBatisUtil.getSqlSession();
      // 2.使用 SqlSession 创建 Dao 接口的代理对象
      UserDao userDao = session.getMapper(UserDao.class);
      // 3.执行接口的方法
      List userList = userDao.getUser();
      userList.forEach(user ->{
          System.out.println("姓名:"+user.getName()+",性别:"+user.getSex()+",年龄:"+user.getAge());
      });
      // 4.关闭 SqlSession
      MyBatisUtil.close();
  }

执行结果:

11. 关联关系

一对一

例如:一个人对应一张身份证,一张身份证对应一个人。在 MyBatis 的 mapper 文件中使用 association 处理一对一关系。

创建表:

A 表的一条记录,对应 B 表的一条记录,且 A 的主键作为 B 表的外键。这主要看以哪张表为中心。

下面例子中将用户信息表的主键(id)作为用户表的外键(info_id)。

用户表:user

CREATE TABLE `user` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
  `name` varchar(20) DEFAULT NULL COMMENT '姓名',
  `sex` varchar(1) DEFAULT NULL COMMENT '性别',
  `age` int(11) DEFAULT NULL COMMENT '年龄',
  `info_id` int(11) DEFAULT NULL COMMENT '用户信息id',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
INSERT INTO `mybatis_demo`.`user`(`id`, `name`, `sex`, `age`, `info_id`) VALUES (1, '张三', '男', 18, 1);
INSERT INTO `mybatis_demo`.`user`(`id`, `name`, `sex`, `age`, `info_id`) VALUES (2, '李四', '男', 19, 2);


用户信息表:user_info

CREATE TABLE `user_info` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `number` varchar(20) DEFAULT NULL COMMENT '身份证编号',
  `address` varchar(50) DEFAULT NULL COMMENT '家庭地址',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;
INSERT INTO `mybatis_demo`.`user_info`(`id`, `number`, `address`) VALUES (1, '411121200302174025', '上海外滩');
INSERT INTO `mybatis_demo`.`user_info`(`id`, `number`, `address`) VALUES (2, '411121200222154554', '北京三里屯');

用户实体类:User

public class User {
    private int id;
    private String name;
    private String sex;
    private int age;
    // 用户信息属性
    private UserInfo userInfo;

    public UserInfo getUserInfo() {
        return userInfo;
    }

    public void setUserInfo(UserInfo userInfo) {
        this.userInfo = userInfo;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + ''' +
                ", sex='" + sex + ''' +
                ", age=" + age +
                '}';
    }
}

用户信息类:

public class UserInfo {
    private int id;
    private String number;
    private String address;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "UserInfo{" +
                "id=" + id +
                ", number='" + number + ''' +
                ", address='" + address + ''' +
                '}';
    }
}

UserDao:

public interface UserDao {
    
    List getAll();
}

UserDao.xml:




    
    
        
        
        
        
        
        
            
            
            
        
    

    
        select d.id depId,d.name depName,e.id empId,e.name empName,e.age,e.sex
        from department d
        left join employee e
        on d.id  = e.dep_id
    

测试代码:

@Test
public void testDepartmentGetAll(){
    // 1.获取 SqlSession 对象
    SqlSession session = MyBatisUtil.getSqlSession();
    // 2.使用 SqlSession 创建 Dao 接口的代理对象
    DepartmentDao departmentDao = session.getMapper(DepartmentDao.class);
    // 3.执行接口的方法
    List departmentList = departmentDao.getAll();
    departmentList.forEach(department ->{
        System.out.println("部门:"+department+" 员工:"+department.getEmployeeList());
    });
    // 4.关闭 SqlSession
    MyBatisUtil.close();
}

测试结果:

多对多

例如:例如一个学生可以有多门课程,一门课程可以属于多个学生。多对多可以理解为是一对多和多对一的组合。要实现多对多,一般都需要有一张中间表(也叫关联表),形成多对多的形式。

创建表:

学生表:student

CREATE TABLE `student` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
  `name` varchar(20) DEFAULT NULL COMMENT '姓名',
  `sex` varchar(1) DEFAULT NULL COMMENT '性别',
  `age` int(11) DEFAULT NULL COMMENT '年龄',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;
INSERT INTO `mybatis_demo`.`student`(`id`, `name`, `sex`, `age`) VALUES (1, '张三', '男', 18);
INSERT INTO `mybatis_demo`.`student`(`id`, `name`, `sex`, `age`) VALUES (2, '李四', '女', 21);
INSERT INTO `mybatis_demo`.`student`(`id`, `name`, `sex`, `age`) VALUES (3, '王五', '男', 19);


课程表:course

CREATE TABLE `course` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) DEFAULT NULL COMMENT '课程名称',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4;
INSERT INTO `mybatis_demo`.`course`(`id`, `name`) VALUES (1, 'java开发');
INSERT INTO `mybatis_demo`.`course`(`id`, `name`) VALUES (2, '数据结构');
INSERT INTO `mybatis_demo`.`course`(`id`, `name`) VALUES (3, '大数据开发');
INSERT INTO `mybatis_demo`.`course`(`id`, `name`) VALUES (4, '云原生开发');


学生-课程关联表:student_course

CREATE TABLE `student_course` (
  `student_id` int(11) NOT NULL,
  `course_id` int(11) NOT NULL,
  PRIMARY KEY (`student_id`,`course_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `mybatis_demo`.`student_course`(`student_id`, `course_id`) VALUES (1, 2);
INSERT INTO `mybatis_demo`.`student_course`(`student_id`, `course_id`) VALUES (1, 3);
INSERT INTO `mybatis_demo`.`student_course`(`student_id`, `course_id`) VALUES (2, 1);
INSERT INTO `mybatis_demo`.`student_course`(`student_id`, `course_id`) VALUES (2, 2);
INSERT INTO `mybatis_demo`.`student_course`(`student_id`, `course_id`) VALUES (3, 3);
INSERT INTO `mybatis_demo`.`student_course`(`student_id`, `course_id`) VALUES (3, 4);

学生实体类:

public class Student {
    private int id;
    private String name;
    private String sex;
    private int age;
    private List courseList;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public List getCourseList() {
        return courseList;
    }

    public void setCourseList(List courseList) {
        this.courseList = courseList;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + ''' +
                ", sex='" + sex + ''' +
                ", age=" + age +
                '}';
    }
}

课程实体类:

public class Course {
    private int id;
    private String name;
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Course{" +
                "id=" + id +
                ", name='" + name + ''' +
                '}';
    }
}

StudentDao:

public interface StudentDao {

   List getAll();
}

StudentDao.xml:





    
        
        
        
        
        
        
            
            
        
    

    

测试代码:

@Test
  public void testStudentGetAll(){
      // 1.获取 SqlSession 对象
      SqlSession session = MyBatisUtil.getSqlSession();
      // 2.使用 SqlSession 创建 Dao 接口的代理对象
      StudentDao studentDao = session.getMapper(StudentDao.class);
      // 3.执行接口的方法
      List studentList = studentDao.getAll();
      studentList.forEach(student ->{
          System.out.println("学生:"+student+" 课程:"+student.getCourseList());
      });
      // 4.关闭 SqlSession
      MyBatisUtil.close();
  }

测试结果:

12. 分页插件

我们之前在写分页的时候,不仅要自定义一个 Page 类,还要拼接 sql 语句,最后还要封装数据。真的是”恶心他妈妈给恶心开门——恶心到家了。“

为了解决这个问题,MyBatis 为我们提供了一个通用的分页工具:PageHelper。

使用步骤:

1.引入依赖



    com.github.pagehelper
    pagehelper
    5.1.4

2.修改主配置文件

在 environments 标签之前添加:


    

3.准备数据

4.测试代码

  @Test
  public void testGetAll(){
      // 1.获取 SqlSession 对象
      SqlSession session = MyBatisUtil.getSqlSession();
      // 2.使用 SqlSession 创建 Dao 接口的代理对象
      UserDao userDao = session.getMapper(UserDao.class);
      // 3.执行接口的方法
      Page page = PageHelper.startPage(2, 3);
      List userList = userDao.getUser();
      System.out.println("当前页:"+page.getPageNum());
      System.out.println("每页条数:"+page.getPageSize());
      System.out.println("总条数:"+page.getTotal());
      System.out.println("总页数:"+page.getPages());
      System.out.println("-------------------------");
      userList.forEach(user ->{
          System.out.println("姓名:"+user.getName()+",性别:"+user.getSex()+",年龄:"+user.getAge());
      });
      // 4.关闭 SqlSession
      MyBatisUtil.close();
  }

5.执行结果

转载请注明:文章转载自 www.051e.com
本文地址:http://www.051e.com/it/889163.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 ©2023-2025 051e.com

ICP备案号:京ICP备12030808号