mybatis学习笔记(一):第一个 Mybatis 例子,Mybatis 的基本用法


/**
 * ORM:对象关系映射;是一种对象数据到关系数据映射的 规则(框架/工具);
 *  优点:
 *      1、完全面向对象的编程思想,无 SQL 出现;
 *      2、减少代码编写,提高工作效率;
 *      3、提高访问数据库的性能,降低访问数据库的频率;
 *      4、具有独立性,发生变化时,不会影响上层的实现;
 *
 * 回顾 JDBC 开发:
 *  优点:
 *      简单易学,上手快,非常灵活构建 SQL,效率高;
 *  缺点:
 *      代码繁琐,难以写出高质量的代码(例如,资源的释放,SQL 注入安全性等);
 *      开发者既要写业务逻辑,又要写对象的创建和销毁,必须管底层具体数据库的语法;
 *  适合于超大批量数据的操作,速度快;
 *  开发步骤:
 *      1、加载数据库驱动;
 *      2、通过 DriverManager 获取数据库的连接;
 *      3、通过 Connection 获取 Statement、PreparedStatement 对象;
 *      4、将 SQL 语句绑定到 Statement、PreparedStatement 中去,准备向数据库发送 SQL 语句;
 *      5、执行完 SQL 语句后,返回对象的结果;
 *      6、如果是查询的话,迭代结果集(ResultSet)进行处理;
 *      7、依次关闭连接对象:ResultSet、Statement、Connection;
 *      如果上述操作需要做 非查询的话,还需要事务支持:
 *          conn.setAutoCommit(false);      // 手动开启事务
 *          conn.commit()/conn.rollback();  // 提交/回滚事务
 *
 * 回顾 Hibernate 开发:
 *  优点:
 *      不用写 SQL,完全以面向对象的方式设计和访问,不用管底层具体数据库的语法;
 *  缺点:
 *      处理复杂业务时,灵活度差,复杂的 HQL 难写难理解,例如多表查询的 HQL 语句;
 *  适合于中小批量数据的操作,速度慢;
 *  开发步骤:
 *      1、创建 Configuration,加载 src/hibernate.cfg.xml 配置文件,该配置文件又会去加载 user.hbm.xml 映射文件;
 *      2、通过 Configuration 创建 SessionFactory;
 *      3、通过 SessionFactory 创建 Session;
 *      4、通过 Session 创建 Transaction;
 *      5、如果做 增、删、改 操作的话,一定要开启事务,如果做 查询 操作,事务可选;
 *      6、操作 Session 的常用 API,例如 save()、update()、saveOrUpdate()、delete()、get();
 *      7、事务提交,出错后事务回滚;
 *      8、关闭 Session;
 *
 * 什么是 Mybatis,有什么特点?
 *  1、基于上述 JDBC 和 Hibernate 的特点,Mybatis 处于他们中间,速度和难度 都是中等;
 *  2、Mybatis 原本是 apache 的一个开源项目 iBatis,2010 年这个项目由 apache software foundation
 *      迁移到了 google code,并且改名为 Mybatis,2013 年 11 月迁移到 Github;
 *  3、iBatis 一词来源于 internet 和 abatis 的组合,是一个基于 java 的持久层框架。iBatis 提供的持久层
 *      框架包括 SQL Maps 和 Data Access Objects(DAO);
 *  4、jdbc/dbUtils/springDao,Hibernate/springORM,Mybatis 同属于 ORM 解决方案之一;
 */

 项目结构:

开发步骤:

1、导入 mybatis 、mysql 和 oracle 依赖的 jar 包:

2、创建一个 测试表:

--mysql语法
create table students(
   id  int(5) primary key,
   name varchar(10),
   sal double(8,2)
);
--oracle语法
create table students(
   id  number(5) primary key,
   name varchar2(10),
   sal number(8,2)
);

3、创建一个和表对应的 实体类 Student.java:

package com.mybatis.demo;

/**
 * 实体类
 */
public class Student {
    private int id;
    private String name;
    private Double sal;

    public Student() {
    }

    public Student(int id, String name, Double sal) {
        this.id = id;
        this.name = name;
        this.sal = sal;
    }

    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 Double getSal() {
        return sal;
    }

    public void setSal(Double sal) {
        this.sal = sal;
    }

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

4、在 Student.java 同级目录下创建一个映射配置文件 StudentMapper.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">

<!-- namespace 是名称空间,理论上可以随便写,但必须保证唯一 -->
<mapper namespace="studentNamespace">

    <!--
        resultMap 标签:映射实体与表的关系;
            id:为实体与表的映射 取一个任意的唯一编号;
            type:实体的全路径名;
        注意:
            映射实体类与表的关系时,此处并没有指定表的名字,
            是因为下面的 insert 语句中指出了要操作的表的名字;
    -->
    <resultMap id="studentMap" type="com.mybatis.demo.Student">
        <!--
            id 标签:映射主键属性;
                property:表示实体类中的属性;
                column:表示表中的主键;
        -->
        <id property="id" column="id"/>

        <!--
            result 标签:映射非主键属性;
                property:表示实体类中的属性;
                column:表示表中的字段;
        -->
        <result property="name" column="name"/>
        <result property="sal" column="sal"/>
    </resultMap>

    <!--
        insert 标签:表示标签中要写的是插入 sql 语句;
            id:为插入 sql 语句取一个任意唯一的编号;
        注意:
            "哈哈" 字符串用双引号可以插入到 mysql 数据库中,但是不能插入
            到 oracle 数据库中,会报错:"ORA-00984: 列在此处不允许";
            oracle 中 varchar2 类型的字段插入字符数据时只能用 单引号!
    -->
    <insert id="add1">
        insert into students(id, name, sal) values (1, '哈哈', 7000)
    </insert>

    <!--
        parameterType:表示 dao 中调用执行此 SQL 语句的方法传入的参数类型;如果是类的话,必须使用全路径名;
            如果 SQL 语句没有接收参数,可以不写 parameterType 属性;
            如果在 mybatis.xml 主配置文件中设置了类型别名,比如设置了 com.mybatis.demo.Student 的别名为 student,
            那么可以直接写成 parameterType="student";

        在 sql 语句中用占位符取值 (#{id}, #{name}, #{sal}),实际是调用 Student 对象的 getter 方法取值;
        Student 对象是 dao 中调用此 SQL 语句时传入的;
    -->
    <insert id="add2" parameterType="com.mybatis.demo.Student">
        insert into students(id, name, sal) values (#{id}, #{name}, #{sal})
    </insert>

</mapper>

5、在 src 目录下创建一个数据库配置文件 db.properties:

mysql.driver=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/mybatis
mysql.username=root
mysql.password=root

oracle.driver=oracle.jdbc.driver.OracleDriver
oracle.url=jdbc:oracle:thin:@localhost:1521:orcl
oracle.username=scott
oracle.password=tiger

6、在 src 目录下创建 mybatis 主配置文件 mybatis.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>

    <!--
        加载 src 路径下的 配置文件(db.properties);
        下面通过 ${ 键 } 获取对应的值;
    -->
    <properties resource="db.properties"/>

    <!--
        设置类型别名:在映射文件中所有的 com.mybatis.demo.Student 类型都可以使用 student 代替
    -->
    <typeAliases>
        <typeAlias type="com.mybatis.demo.Student" alias="student"/>
    </typeAliases>

    <!-- 设置一个默认的连接环境信息 -->
    <environments default="mysql_developer">

        <!-- 连接环境信息:取一个任意唯一的名字 -->
        <environment id="mysql_developer">
            <!-- mybatis 使用 jdbc 事务管理方式 -->
            <transactionManager type="jdbc"/>
            <!-- mybatis 使用连接池方式来获取连接 -->
            <dataSource type="pooled">
                <!--
                    配置与数据库交互的4个必要属性 ;
                    ${mysql.driver}:表示获取 db.properties 配置文件中 mysql.driver 的值;
                -->
                <property name="driver" value="${mysql.driver}"/>
                <property name="url" value="${mysql.url}"/>
                <property name="username" value="${mysql.username}"/>
                <property name="password" value="${mysql.password}"/>
            </dataSource>
        </environment>

        <!-- 连接环境信息:取一个任意唯一的名字 -->
        <environment id="oracle_developer">
            <!-- mybatis 使用 jdbc 事务管理方式 -->
            <transactionManager type="jdbc"/>
            <!-- mybatis 使用连接池方式来获取连接 -->
            <dataSource type="pooled">
                <!-- 配置与数据库交互的4个必要属性 -->
                <property name="driver" value="${oracle.driver}"/>
                <property name="url" value="${oracle.url}"/>
                <property name="username" value="${oracle.username}"/>
                <property name="password" value="${oracle.password}"/>
            </dataSource>
        </environment>

    </environments>

    <!-- 加载映射文件 -->
    <mappers>
        <mapper resource="com/mybatis/demo/StudentMapper.xml"/>
    </mappers>

</configuration>

7、创建一个工具类 MybatisUtils.java:

package com.mybatis.demo;

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.Reader;
import java.sql.Connection;

/**
 * 工具类
 */
public class MybatisUtils {

    /**
     * 禁止外界通过 new 方法创建 工具类对象:构造方法私有化;
     */
    private MybatisUtils(){}

    /**
     * 创建一个线程对象,目的是将 SqlSession 和当前线程绑定到一起,线程结束,SqlSession 销毁;
     */
    private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<>();
    /**
     * SqlSession 工厂
     */
    private static SqlSessionFactory sqlSessionFactory;

    /**
     * 类加载的时候 自动加载 src/mybatis.xml 配置文件
     */
    static {
        try {
            // 加载配置文件
            Reader reader = Resources.getResourceAsReader("mybatis.xml");
            // 根据配置文件构造 SqlSession 工厂
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取 SqlSession
     */
    public static SqlSession getSession() {
        // 从当前线程中获取 SqlSession
        SqlSession sqlSession = threadLocal.get();
        // 如果线程中没有 SqlSession 的话
        if (sqlSession == null) {
            // 找 SessionFactory 创建一个 SqlSession
            sqlSession = sqlSessionFactory.openSession();
            // 将当前线程与 SqlSession 绑定到一起
            threadLocal.set(sqlSession);
        }
        // 返回 SqlSession 对象
        return sqlSession;
    }

    /**
     * 关闭 SqlSession,并与当前线程分离
     */
    public static void closeSqlSession() {
        // 从当前线程中获取 SqlSession
        SqlSession sqlSession = getSession();
        // 如果有的话就关闭
        if (sqlSession != null) {
            // 关闭
            sqlSession.close();
            // 分离当前线程与 SqlSession,目的是让 GC 尽早回收
            threadLocal.remove();
        }
    }

    /**
     * 测试是否连接成功
     */
    public static void main(String[] args){
        Connection connection = MybatisUtils.getSession().getConnection();
        System.out.println(connection);
    }
}

8、创建一个 StudentDao.java 类进行测试:

package com.mybatis.demo;

import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

/**
 * 持久层
 */
public class StudentDao {

    /**
     * 增加学生:不带参数
     */
    public void add1() throws Exception{
        SqlSession sqlSession = null;
        try {
            // 获取 SqlSession 对象
            sqlSession = MybatisUtils.getSession();
            // 开始事务(默认开始)

            /**
             * 执行 insert 操作;
             * insert 的 sql 语句是从 StudentMapper.xml 映射文件中读取的;
             * 参数为 名称空间.insert标签的id;
             * 即 执行 insert 操作的 sql 语句是从 id 为 add1 的 <insert/> 标签中读取的;
             */
            int num = sqlSession.insert("studentNamespace.add1");
            System.out.println("本次操作影响了 " + num + "行");

            // 提交事务(手动提交)
            sqlSession.commit();
        }catch (Exception e){
            e.printStackTrace();
            // 回滚事务
            sqlSession.rollback();
            throw e;
        }finally {
            // 关闭
            MybatisUtils.closeSqlSession();
        }
    }

    /**
     * 增加学生:带参数
     */
    public void add2(Student student) throws Exception{
        SqlSession sqlSession = null;
        try{
            sqlSession = MybatisUtils.getSession();

            /**
             * 执行 insert 操作;
             * sql 语句是从 id 为 add2 的 <insert/> 标签中读取的;
             * 参数2 student 是 实体类对象;
             */
            int num = sqlSession.insert("studentNamespace.add2", student);
            System.out.println("本次操作影响了 " + num + "行");

            sqlSession.commit();    // 提交事务
        }catch (Exception e){
            e.printStackTrace();
            sqlSession.rollback();  // 回滚事务
        }finally {
            MybatisUtils.closeSqlSession();
        }
    }

    /**
     * 测试
     */
    public static void main(String[] args) throws Exception{
        StudentDao dao = new StudentDao();
        dao.add1();
        dao.add2(new Student(2, "呵呵", 8000D));
    }
}

Mybatis 工作流程:

1)通过 Reader 对象读取 src 目录下的 mybatis.xml 配置文件(该文本的位置和名字可任意);

2)通过 SqlSessionFactoryBuilder 对象创建 SqlSessionFactory 对象;

3)从当前线程中获取 SqlSession 对象;

4)事务开始,在 mybatis 中默认;

5)通过 SqlSession 对象读取 StudentMapper.xml 映射文件中的操作编号,从而读取 sql 语句;

6)事务提交,必写;

7)关闭 SqlSession 对象,并且分开当前线程与 SqlSession 对象,让 GC 尽早回收;

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章