MyBatis的基本使用

1、MyBatis的基本介绍

1.1、MVC三层架构

MVC三层架构:M 数据访问层、V 界面层、C 业务逻辑层。

三层的职责:

  • V 界面层:View 对数据的展示代码,比如JSP、html页面,就是专门用来展示数据,美化页面的。
  • C 业务逻辑层:Controller 控制,接收界面层传递的数据,计算逻辑,调用数据访问层来获取数据并且交付给界面层展示。比如:Servlet、service
  • M 数据访问层:Model 模型,代表着业务逻辑代码与数据库代码,就是访问数据,对数据库进行增删改查等等。

三层的处理请求的交互:

用户 ---> 界面层 ---> 业务逻辑层 ---> 数据访问层 ---> DB数据库

 

1.2、mybatis的基本介绍

MyBatis 本是apache的一个开源项目iBatis,2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis,是一个基于Java的持久层框架。
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

 

为什么使用 mybatis ?在传统的 JDBC 中,我们除了需要自己提供 SQL 外,还必须操作 Connection、Statment、ResultSet,不仅如此,为了访问不同的表,不同字段的数据,我们需要些很多雷同模板化的代码,显得繁琐又枯燥。

而我们在使用了 MyBatis 之后,只需要提供 SQL 语句就好了,其余的诸如:建立连接、操作 Statment、ResultSet、释放资源、处理 JDBC 相关异常等等都可以交给 MyBatis 去处理,我们的关注点于是可以就此集中在 SQL 语句上,关注在增删改查这些操作层面上。mybatis 提供了循环 SQL,可以将查询的结果集封装为 java 对象、list 集合。并且 MyBatis 支持使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。

 

2、mybatis 的基本使用

新建一个 maven JavaSE 项目。先需要添加依赖,除了 mybatis 依赖外还需要添加 mysql 的驱动依赖:

<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>5.1.12</version>
</dependency>
<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>3.5.1</version>
</dependency>

新建一个 resources 目录,在该目录下添加 mybatis 的配置文件 mybatis-config.xml。 

项目的最终目录结构如下:

 

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>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/test"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="sqlmap/user.xml"/>
    </mappers>
</configuration>

上面的配置文件中,我们指定了一个 sql 映射文件 sqlmap/user.xml 文件。我们在 resources 目录下新建一个 sqlmap 目录,在该文件夹下建立 sql 的映射文件。

在 sqlmap 文件夹下建立 user.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="user">
    <select id="findUserById" resultType="entity.User">
        select * from user where id = #{id}
    </select>

    <select id="findUserInfo" resultType="entity.User">
        select id,name,password from user where id = #{id}
    </select>
</mapper>

sql 映射文件中在 mapper 标签下写 sql 语句,mapper 标签的 namespace 指定命名空间,命名空间应该唯一,名称可以自定义。sql 语句中通过 id 唯一标识该语句,在使用 sql 时通过 “命名空间.id” 形式来使用。resultType 指定的是 select 语句的查询结果类型。

 

然后建一个实体类。我们要查询的是 user 表信息,该表结构如下:

所以我们建一个 User 实体类,该实体类必须有无参构造函数,否则可能会有问题。

package entity;

public class User {
    private Integer id;
    private String name;
    private String password;

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

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

然后是 UserDao 接口类:

package dao;

import entity.User;

import java.io.IOException;

public interface UserDao {
    User finUserById(Integer userId) throws IOException;
}

UserDaoImpl 实现类:

package dao.impl;
import dao.UserDao;
import entity.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;


public class UserDaoImpl implements UserDao {
    @Override
    public User finUserById(Integer userId) throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        
        //获取sqlsession对象
        SqlSession session = factory.openSession();
        //执行sql语句。通过sql映射文件中,sql语句的标识来指定需要执行的sql语句
        User resultUser = session.selectOne("user.findUserById", userId); //参数一:namespace.id
        //关闭sqlsession对象
        session.close();
        return resultUser;
    }
}

最后通过一个单元测试类来测试:

package test;

import dao.UserDao;
import dao.impl.UserDaoImpl;
import entity.User;
import org.junit.Test;

import java.io.IOException;

public class Test01 {
    @Test
    public void test01() throws IOException {
        UserDao userDao = new UserDaoImpl();
        User user = userDao.finUserById(1);
        System.out.println(user);
    }
}

 

2.1、mybatis 查询

大致流程跟上面一样,只需修改 sql 映射文件如下:

<?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="user">
    <select id="findUserById" parameterType="int" resultType="entity.User">
        select * from user where id = #{id}
    </select>

    <select id="listUser" resultType="entity.User">
        select * from user
    </select>
</mapper>

使用单元测试类来查询,查询语句如下:

public class Test01 {
    @Test
    public void test02() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        //获取sqlsession对象
        SqlSession session = factory.openSession();

        //查询对象
        User resultUser = session.selectOne("user.findUserById", 1); //参数一:namespace.id
        System.out.println("查询对象的结果:" + resultUser);

        //查询list集合
        List list = session.selectList("user.listUser");
        System.out.println("查询集合的结果:" + list);

        //关闭sqlsession对象
        session.close();

    }
}

查询结果:

 

2.2、mybatis 增删改

增删改操作跟查询操作差不多,但是 mybatis 中默认是不会自动提交事务的,所以在进行增删改操作时一定要手动去提交事务,否则不会生效。

sql 映射文件如下:

<?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="user">
    <insert id="adduser" parameterType="entity.User">
        insert into user (id, name, password) values (#{id},#{name},#{password})
    </insert>

    <delete id="deleteuser" parameterType="entity.User">
        delete from user where id = #{id}
    </delete>

    <update id="updateuser" parameterType="entity.User">
        update user set name=#{name} where id=#{id}
    </update>
</mapper>

在 sqlmapper 映射文件中,parameterType 指定的是要求输入参数的类型,resultType 指定的是输出的结果类型。

使用单元测试类来进行增删改,语句如下:

public class Test01 {
    @Test
    public void test03() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        //获取sqlsession对象。
        SqlSession session = factory.openSession();  //通过openSession()获取的是非自动提交的对象,可以通过openSession(true)来获取自动提交的sqlsession对象,这样就不用再手动commit了。

        //增加操作
        User user1 = new User();
        user1.setId(6);
        user1.setName("newUser");
        user1.setPassword("123");
        int addResult = session.insert("user.adduser", user1);
        //一定要手动提交事务。或者最后再一起提交也行
        session.commit();
        System.out.println("增加操作的结果:" + addResult);

        //删除操作
        User user2 = new User();
        user2.setId(2);
        int delResult = session.delete("user.deleteuser", user2);
        //手动提交事务
        session.commit();
        System.out.println("删除操作的结果:" + delResult);

        //修改操作
        User user3 = new User();
        user3.setId(3);
        user3.setName("newName");
        int updateResult = session.update("user.updateuser", user3);
        //手动提交事务
        session.commit();
        System.out.println("删除操作的结果:" + updateResult);

        //关闭sqlsession对象
        session.close();
    }
}

mybatis 中通过 openSession() 默认获取的是非自动提交的对象,可以通过 openSession(true) 来获取自动提交的 sqlsession 对象,这样就不用再手动 commit 了。

操作结果:

 

3、mybaits 的配置文件

3.1、mybatis 配置文件

MyBatis 的配置文件 mybatis-config.xml 包含了数据库连接信息,同时还包含了 Mapper 映射文件的加载路径、全局参数以及类别别名等一系列MyBatis的核心配置信息。

<?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>
    
    <!--环境配置,即数据库的连接信息,可以配置多个。
        default指定默认使用哪个数据库配置信息
    -->
    <environments default="development">

        <!--environment:一个数据库的配置信息。id指定该配置的名称,名称可自定义-->
        <environment id="development">

            <!--transactionManager指定mybatis的事务管理器。type:jdbc 表示使用jdbc中的connection对象的commit、rollback做事务管理-->
            <transactionManager type="JDBC"/>
            
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/test"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    
    <mappers>
        <!--每个mapper标签指定一个sql映射文件的位置-->
        <mapper resource="sqlmap/user.xml"/>
    </mappers>
</configuration>

MyBatis 使用场景: 在进行 MyBatis 开发时,我们的大部分精力都放在了 SQL 映射文件上。 MyBatis 的特点就是以 SQL 语句为核心的不完全的 ORM(关系型映射)框架。与 Hibernate 相比,Hibernate 的学习成本比较高,而 SQL 语句并不需要开发人员完成,只需要调用相关 API 即可。这对于开发效率是一个优势,但是缺点是没办法对 SQL 语句进行优化和修改。而 MyBatis 虽然需要开发人员自己配置 SQL 语句,MyBatis 来实现映射关系,但是这样的项目可以适应经常变化的项目需求。所以使用 MyBatis 的场景是:对 SQL 优化要求比较高,或是项目需求或业务经常变动。

 

3.1.1、使用独立的JDBC配置文件

我们可以把 jdbc 的配置单独作为一个配置文件,然后再在 mybatis 的配置文件中引入 jdbc 的配置文件作为 jdbc 的配置。

在 resource 目录下新建一个 jdbc.properties 配置文件:

 该文件内容如下:

prop.driverClass=com.mysql.jdbc.Driver
prop.url=jdbc:mysql://localhost:3306/test
prop.username=root
prop.password=123456s

在 mybatis 中引入该配置文件中的配置:

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

    <!--引入jdbc配置文件。文件路径是相对于类根路径-->
    <properties resource="jdbc.properties"></properties>

    <!--环境配置,即数据库的连接信息,可以配置多个。
        default指定默认使用哪个数据库配置信息
    -->
    <environments default="development">
        <!--environment:一个数据库的配置信息。id指定该配置的名称,名称可自定义-->
        <environment id="development">
            <!--transactionManager指定mybatis的事务管理器。type:jdbc 表示使用jdbc中的connection对象的commit、rollback做事务管理-->
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${prop.driverClass}"/>
                <property name="url" value="${prop.url}"/>
                <property name="username" value="${prop.username}"/>
                <property name="password" value="${prop.password}"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <!--每个mapper标签指定一个sql映射文件的位置-->
        <mapper resource="sqlmap/user.xml"/>
        <mapper resource="sqlmap/student.xml"/>
    </mappers>
</configuration>

 

3.2、配置日志

在使用 mybatis 进行开发的时候,如果我们要想从 sql 的映射文件中找出最终执行的完整的 sql 会非常的难,这个时候我们可以通过配置日志来将最终执行的完整的 sql 打印出来。

配置日志只需在 mybatis 的配置文件中添加以下配置:

<!--配置日志-->
<settings>
    <setting name="logImpl" value="STDOUT_LOGGING" />
</settings>

配置文件示例:

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

    <!--配置日志-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING" />
    </settings>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>

            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/test"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="sqlmap/user.xml"/>
    </mappers>
</configuration>

属性名:logImpl

描述:指定 MyBatis 所用日志的具体实现,未指定时将自动查找。

有效值:SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING

配置日志之后,我们通过 mybatis 执行 sql,可以在控制台看到日志输出信息,类似如下:

 

4、mapper代理开发模式

通过使用 Mapper 代理的开发方式,程序员只需要编写 mapper 的接口类(相当于dao接口)即可,而不用再写 dao 的实现类,这样能让代码更加方便简洁。Mybatis 会自动地为接口类生成动态代理实现类

不过要实现 mapper 代理的开发方式,需要遵循一些开发规范:

  1. sql mapper 映射文件的 namespace 写成接口类的完整类名。即 接口类的完整类名 == 映射文件的 namespace
  2. sql mapper 映射文件中的 sql 语句的 id 和接口类的方法名称相同。即 接口类的方法名 == 映射文件的 sql 的id
  3. 接口类的方法参数只能有一个,且类型要和 sql mapper 映射文件中 sql 语句的 parameterType 的值保持一致。即 接口类的方法的参数 == 映射文件的 sql 的 parameterType
  4. 接口类方法的返回值类型要和 sql mapper 映射文件中 sql 语句的 resultType 值或 resultMap 中的 type 值保持一致。即 接口类的返回值 == 映射文件的 sql 的 resultType

 

Mybatis 会自动地为接口类生成动态代理实现类,并创建该类的对象。

在调用方法时,mybatis 会根据接口类的方法名来找到 sql 映射文件中对应的 sql 语句。并且 mybatis 通过接口类中方法的返回值可以确定应该调用 sqlsession 中的那个方法来进行 sql 操作,比如如果返回值是 list,则调用 selectList() 方法

 

4.1、mapper 代理开发模式的使用

mapper 代理开发模式跟正常使用 mybatis 差不多,只不过 sql mapper 映射文件和接口类需要符合一定的规范。

实现示例:

下面操作的是 student 表,表结构如下:

 

首先建立 sql 映射文件,映射文件 namespace 应该是接口类的完整类名。映射文件 student.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="dao.StudentDao">
    <select id="findStudentById" parameterType="int" resultType="entity.Student">
        select * from student where id = #{id}
    </select>
    <select id="findStudentAll" resultType="entity.Student">
        select * from Student
    </select>
    <insert id="insertStudent" parameterType="entity.Student">
        insert into Student(id,name,age) values(#{id},#{name},#{age})
    </insert>
    <delete id="deleteStudentById" parameterType="int">
        delete from Student where id=#{id}
    </delete>
    <update id="updateStudentName" parameterType="entity.Student">
        update Student set name=#{name} where id=#{id}
    </update>
</mapper>

下面建立 StudentDao 接口类,只需要接口类接口,无需书写实现类,Mybatis 会自动地为接口类生成动态代理实现类。

接口类的方法名、参数和返回值要和 sql 映射文件中定义的对应,StudentDao 接口类代码:

package dao;

import entity.Student;

import java.util.List;

public interface StudentDao {
    public Student findStudentById(int id);
    public List<Student> findStudentAll();
    public void insertStudent(Student Student);
    public void deleteStudentById(int id);
    public void updateStudentName(Student Student);
}

然后就可以使用 mybatis 进行操作 sql 了。下面使用单元测试类进行测试:

public class Test02 {

    @Test
    public void test01() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession session = factory.openSession();

        StudentDao studentDao = session.getMapper(StudentDao.class);

        //查询对象
        Student student = studentDao.findStudentById(2);
        System.out.println(student);

        //查询集合
        List list = studentDao.findStudentAll();
        System.out.println(list);

        //增加
        Student student1 = new Student();
        student1.setName("aa");
        student1.setAge(33);
        studentDao.insertStudent(student1);

        //删除
        studentDao.deleteStudentById(2);

        //修改
        Student student2 = new Student();
        student2.setId(1);
        student2.setName("newName");
        studentDao.updateStudentName(student2);

        //需要手动提交事务
        session.commit();

        session.close();
    }
}

 

posted @ 2021-07-28 12:31  wenxuehai  阅读(240)  评论(0编辑  收藏  举报
//右下角添加目录