美文网首页IT技术篇
MyBatis易懂教程

MyBatis易懂教程

作者: WJunF | 来源:发表于2019-05-08 08:38 被阅读0次

    MyBatis 教程


    假设数据库中存在一张表 person,它有两个字段,分别是主键和名字(id, name):

    -- 创建表 person

    create table person (id number primary key, name varchar2(20));

    -- 插入几条示例数据

    insert into person values (1, '周星驰');

    insert into person values (2, '张学友');

    insert into person values (3, '王家卫');

    commit;

    站在 ORM 的角度考虑,我们应该为这个表创建一个类,Person,它跟 person 表是对应关系。

    public class Person {

        private int id;

        private String name;

        // ...

    }

    如果按照 JDBC 的原生写法,我们从 person 表中

    读取 id 为 1 的数据

    删除 id 为 2 的数据

    大致要这么写:

    // 查询大约分下面几步

    // 1 ... jdbc 的方式获取数据库连接 Connection

    // 2 ... 将结果封装到 Person 类中

    // 3 ... 清理数据库连接,做好异常的处理

    ResultSet rs = conn.executeQuery("select * from person where id = 1");

    Person person = new Person(rs.getLong(1), rs.getString(2));

    // 删除类似

    // 1 ... jdbc 的方式获取数据库连接 Connection

    // 2 ... 执行删除

    // 3 ... 处理事务,关闭资源,处理异常

    conn.execute("delete from Person where id = 2");

    每次这么写很麻烦,容易出错。所以出现了一些 ORM 框架,帮助我们进行数据库连接。

    比如 hibernate。

    它的思路是,在实体对象中设置好映射和关联后,我们只需要对对象进行各种操作(增删改查等)。 框架会帮助我们把这些操作翻译成对数据库的操作。 \ 上面的功能,用 hibernate 实现,大致的代码为:

    // 1. 读取配置文件,建立 SessionFactory

    SessionFactory sessionFactory = new Configuration("hibernate.xml").config().buildSessionFactory();

    // 2. 获取一个连接(session)

    Session session = sessionFactory.getSession();

    // 3. 执行操作,查询、删除

    // 这是面向对象的语法。hibernate 负责将我们的操作翻译成相对应的 jdbc 操作

    // 这大大简化了我们的数据操作。

    Person tom = session.get(Person.class, 1);

    Person cat = session.get(Person.class, 2);

    session.delete(cat);

    session.save(cat);

    hibernate 非常强大,在它的基础上,形成了 JavaEE 的 ORM 标准 JPA。 但是 hibernate 也存在一些缺点,比如:

    相对比较重型,学习门槛高!!!

    过于面向对象,过度封装。

    虽然提升了开发效率,但是对执行效率有一定的牺牲(因为翻译成的 jdbc 操作未必是最优的)。所以,很难调优。

    不够灵活。

    所以,怎么兼顾 jdbc 和 hibernate 方式的优点,是很多人考虑的问题。于是 mybatis 出现了。

    它的思路很简单,例如,我们要对 person 表进行操作(查询和删除),在 jdbc 中对应两条语句:

    select id, name from person where id = 1;

    delete from person where id = 2;

    那是不是可以弄一个配置文件,为这两条语句分别取个名字呢? 下面示例 xml 里,为两条 sql 语句分别起了名字,叫 selectFromPerson 和 deleteFromPerson

    <mapper>

      <sql name="selectFromPerson">select id, name from person where id = 1</sql>

      <sql name="deleteFromPerson">delete from person where id = 2</sql>

    </mapper>

    然后,我们可以这样调用:

    // 初始化 mybatis,加载配置文件和数据库信息,封装到一个对象里,这里叫 SqlSessionFactory

    SqlSessionfactory sqlsessionfactory = 初始化代码;

    // 如果要查询

    // 首先,mybatis 需要去寻找名字叫 "selectFromPerson" 的 sql 语句。

    // 然后,通过我们给的数据库配置,它会帮我们连接数据库,执行上面查到的语句,封装结果到 Person 对象里。

    // 所以,差不多是这样的代码:

    Person de = (Person) sqlsessionfactory.getSession().exec("selectFromPerson");

    // 如果要删除,也是类似的逻辑

    sqlsessionfactory.getSession().exec("deleteFromPerson");

    我们看到,通过这种方式,我们只需要将要用到的 sql 语句,整理并放到配置文件中就行了。 而执行的过程和封装的过程,交给 mybatis 帮助我们完成。这样,就有下面优点:

    轻量级

    灵活

    方便

    当然,在实际的过程中,会有很多 sql 语句,也会有其他复杂配置。 为了不至于配置文件过大而导致维护麻烦,mybatis 将配置文件分为了两类:

    一个核心配置文件,里面配置数据库信息,还有指定其他的 mapper 文件。

    多个 mapper 文件。虽然所有的 sql 放在一个 xml 中也没问题。但基于单一原则(还有其他原因),我们应该将操作不同表的语句分开来放在不同文件里。这样便于维护使用。

    上面只是示例伪代码,下面才是 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="开发环境">

        <!-- 配置我们在生产环境中使用的数据库 -->

        <environment id="生产环境">

          <!-- 配置使用 jdbc 内建的事务处理 -->

          <transactionManager type="JDBC"/>

          <!-- 设置数据源 -->

          <dataSource type="POOLED">

            <property name="driver" value="${driver}"/>

            <property name="url" value="${url}"/>

            <property name="username" value="${username}"/>

            <property name="password" value="${password}"/>

          </dataSource>

        </environment>

        <environment id="开发环境">

          <transactionManager type="JDBC"/>

          <dataSource type="POOLED">

            <property name="driver" value="${driver}"/>

            <property name="url" value="${url}"/>

            <property name="username" value="${username}"/>

            <property name="password" value="${password}"/>

          </dataSource>

        </environment>

      </environments>

      <!-- 指定各个 mapper 文件 -->

      <mappers>

        <mapper resource="t/mapper/PersonMapper.xml"/>

      </mappers>

    </configuration>

    然后是 PersonMapper.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="t.dao.PersonDao">

      <!-- 这里,比我们上面的示例复杂了一点点。因为想要 mybatis 帮助我们更好做事,就要告诉她更多信息。 -->

      <!-- 首先,根据操作的不同,划分了不同的节点,比如 select 表示查询语句,delete 表示删除语句 -->

      <!-- 再次,关于 sql 名字,因为上面指定了 namespace,所以,我们下面这条 sql 的全名就是 t.dao.UserDao.selectFromPerson -->

      <!-- resultType: 告诉 mybatis,将查询出来的数据封装成 Person 类型 -->

      <!-- parameterType: 给我们的 sql 语句传一个参数进来 -->

      <select id="selectFromPerson" parameterType="java.lang.Integer" resultType="t.model.Person">

        SELECT id, name FROM person WHERE id=#{id}

      </select>

      <delete id="deleteFromPerson" parameterType="java.lang.Integer">

        delete from person where id=#{id}

      </delete>

    </mapper>

    配置文件有了,下面就是调用的方式:

    // 1 ... 读取核心配置文件,创建 sessionfactory

    InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");

    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

    // 2 ... 获取 session

    SqlSession session = sqlSessionFactory.openSession();

    // 3 ... 进行查询,配置文件里,查询的 sql 语句我们给的名字是 t.dao.PersonDao.selectFromPerson,所以,查询如下

    Person person = (Person) session.selectOne("t.dao.PersonDao.selectFromPerson", 1);

    // 4 ... 进行删除,相应 sql 语句为 t.dao.PersonDao.deleteFromPerson

    session.delete("t.dao.PersonDao.deleteFromPerson", 2);

    // 5 ... 释放资源

    session.close();

    这样就 OK 了,这基本是 Mybatis 的全部了(虽然还有很多细节没说)。

    当然,你有没有觉得,下面这样的语句写多了也会抓狂。

    Person person = (Person) session.selectOne("t.dao.PersonDao.selectFromPerson", 1);

    因为,sql 的名字写短了容易起冲突,写长了不好记,容易写错,并且因为是字符串 IDE 也不好给出相应提醒。另外,需要自己动手转型,也麻烦。

    怎么办?再封装一丢丢就好了。

    既然我们给这条 sql 起的名字是 t.dao.PersonDao.selectFromPerson,那么,我们就按照这个写法,创建相应的接口呗。

    也就是:复辟我们的 dao 层!

    package t.dao;

    public interface PersonDao {

        Person selectFromPerson(int id);

        void deleteFromPerson(int id);

    }

    这样,整个调用的代码就变成了:

    // 1 ... 读取核心配置文件,创建 sessionfactory

    InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");

    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

    // 2 ... 获取 session

    SqlSession session = sqlSessionFactory.openSession();

    // 3 ... mybatis 根据 PersonDao 接口生成相应的代理对象(代理模式,还记得吗)。

    PersonDao personDao = session.getMapper(PersonDao.class);

    // 4 ... 我们调用这个代理对象的相应方法

    // mybatis 会通过反射的方式,查询到这个 PersonDao 的全类名为 t.dao.PersonDao,我们调用的方法名为 selectFromPerson,所以她也就明白了:

    //  -- 我们是想要执行 t.dao.PersonDao.selectFromPerson 这条 sql 语句

    //  -- 返回的数据应该封装成 Person

    // 所以 mybatis 就会去找名字为 t.dao.PersonDao.selectFromPerson 的 sql 语句,查询到,封装结果到 Person 里。

    Person person = personDao.selectFromPerson(1);

    // 5 ... 释放资源

    session.close();

    有没有发现,这样封装了一下,好像事情变得更面向对象了,操作起来更爽手了。

    也就这么简单。

    我们的 MyBatis 教程。就这样结束了。

    MyBatis + Spring

    第一步,创建 Gradle 项目,引入相应 jar 包

    compile (

            // Databases

            "cn.easyproject:ojdbc7:12.1.0.2.0",

            "c3p0:c3p0:0.9.1.2",

            // Spring

            "org.springframework:spring-web:$springVersion",

            "org.springframework:spring-aop:$springVersion",

            "org.springframework:spring-orm:$springVersion",

            // MyBatis And Plugin

            "org.mybatis:mybatis:3.4.2",

            "org.mybatis:mybatis-spring:1.3.1"

            )

    配置文件

    我们可以将 mybatis 的核心配置文件合并到 spring 中:

    <?xml version="1.0" encoding="UTF-8"?>

    <beans xmlns="http://www.springframework.org/schema/beans"

          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

          xmlns:context="http://www.springframework.org/schema/context"

          xmlns:tx="http://www.springframework.org/schema/tx"

          xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

      <!-- 外部资源文件 -->

      <context:property-placeholder location="classpath:db.properties" ignore-unresolvable="true"/>

      <!-- 配置数据源 -->

      <!-- 这里使用的是 c3p0,比较经典的商业上比较成熟的数据源管理包 -->

      <!-- Spring 也内置了一个数据源管理类,我们开发环境可以用,但生产环境就不要用了。因为它太简陋了。 -->

      <!-- 现在使用比较多的,还有阿里云的数据源管理 jar 包,你们可以自行查询 -->

      <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">

        <property name="user" value="${user}"/>

        <property name="password" value="${password}"/>

        <property name="jdbcUrl" value="${url}"/>

        <property name="driverClass" value="${driver}"/>

      </bean>

      <!-- 将 Sqlsessionfactory 的生成工作交给 spring -->

      <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

        <!-- 指明使用的数据源 -->

        <property name="dataSource" ref="dataSource"/>

        <!-- 指明所有的 mapper 文件。虽然,也可以通过注解配置 mybatis,但在实际过程中,尽量用 xml 少用注解,因为这样便于维护。切记。-->

        <property name="mapperLocations" value="classpath:mybatis/*.xml"/>

        <!-- 指明默认的实体类的包名,如果指定了,我们在 mapper 里的 resultType="t.model.User" 可以简写为 resultType="User" -->

        <property name="typeAliasesPackage" value="classpath:t.model"/>

      </bean>

      <!--

          如果仅配置了 sqlSessionFactory,在代码中,调用 selectFromPerson,我们需要这样写:

          // 先通过容器获取 sessionfactory

          @Resource SqlSessionFactory sqlSessionFacotory;

          // 得到 mapper

          PersonDao personDao = sqlSessionFacotory.getMapper(PersonDao.class);

          // 执行方法

          personDao.selectFromPerson(1);

          但是,如果能将代码简化成这种形式,岂不是更美?

          // 直接从容器里取出初始化好的 personDao

          @Resource PersonDao personDao;

          // 指定方法

          personDao.selectFromPerson(1);

          想这样吗?可以,只需要在 Spring 中配置一个后置处理器就好了。

          简而言之,让 spring 在初始化好后,将 basePackage 里的所有接口都通过 mybatis 产生相应的代理类,然后放到容器里。

          这样,我们以后用的时候,只需要到容器里去拿就可以了。

      -->

      <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">

        <property name="basePackage" value="it.dao"/>

        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>

      </bean>

      <!-- 下面是声明式事务,跟之前差不多的 -->

      <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

        <property name="dataSource" ref="dataSource"/>

      </bean>

      <tx:annotation-driven proxy-target-class="true"/>

    </beans>

    使用,比如,在 PersonService 类里面

    @Service

    @Transactional

    public class PersonService {

        @Resource

        private PersonDao personDao;

        public getPersonById(int id) {

            return personDao.selectFromPerson(id);

        }

    }

    相关文章

      网友评论

        本文标题:MyBatis易懂教程

        本文链接:https://www.haomeiwen.com/subject/hrploqtx.html