1. 程式人生 > 其它 >Mybatis基本應用

Mybatis基本應用

1. 框架

  軟體開發常用的是架構是三層架構,包括持久層,業務層和表現層

  • 持久層:主要完成與資料庫相關的操作,CRUD
  • 業務層:主要根據功能需求完成業務邏輯的定義與實現
  • 表現層: 主要完成與使用者的互動
  • 表現出調研業務層,業務層呼叫持久層,利用javabean實體物件傳遞資料

  框架封裝了冗餘且重用率低的程式碼,利用反射與動態代理機制,實現程式碼通用性。

  • 常見的框架型別
    • 持久層框架用於解決資料持久化的框架: mybatis,hibernate,spring jdbc等
    • 全棧框架能在各層都給出解決方法:spring
    • 表現層框架專注於解決與使用者互動的框架:spring mvc, struts2等
    • SSM=spring mvc+ spring + mybatis
    • SSH=spring jdbc + spring +hibernate

2.mybatis

mybatis是一個基於ORM的半自動輕量級持久層框架,對jdbc的操作資料庫的過程進行封裝。

  • 原始jdbc存在的問題
    • 資料庫連線建立、釋放頻繁造成系統資源浪費從而影響系統性能 --- 使用資料庫連線池初始化連線資源
    • SQL語句在程式碼中硬編碼,程式碼不移維護 --- 將SQL語句寫到配置檔案xml中
    • 查詢操作時,需要手動將結果集封裝到實體中 --- 利用反射內省等底層技術自動將實體與表進行屬性和欄位的自動對映
  • ORM 物件關係對映
    • O 物件模型Object javabean物件
    • R relational 關係型資料庫的資料結構
    • M mapping對映 從資料庫到物件模型的對映,通過xml實現
    • ORM跟蹤實體變化,並將實體的變化對映翻譯成SQL指令碼執行到資料庫中去

3. mybatis快速入門

  • 建立資料庫及實體表
CREATE DATABASE `mybatis_db`;

USE `mybatis_db`;
CREATE TABLE `user` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`username` VARCHAR(32) NOT NULL COMMENT '使用者名稱稱',
`birthday` DATETIME
DEFAULT NULL COMMENT '生日', `sex` CHAR(1) DEFAULT NULL COMMENT '性別', `address` VARCHAR(256) DEFAULT NULL COMMENT '地址',PRIMARY KEY (`id`) ) ENGINE=INNODB DEFAULT CHARSET=utf8; -- insert.... INSERT INTO `user`(`id`,`username`,`birthday`,`sex`,`address`) VALUES (1,'子 慕','2020-11-11 00:00:00','','北京海淀'),(2,'應顛','2020-12-12 00:00:00','','北 京海淀');
  • 建立maven工具,匯入依賴,包括mysql驅動,mybatis,junits測試單元
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>mybatis_quickstart</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!--指定編碼和版本-->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
        <java.version>1.11</java.version>
        <maven.compiler.source>1.11</maven.compiler.source>
        <maven.compiler.target>1.11</maven.compiler.target>
    </properties>

    <dependencies>
       <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
            <scope>runtime</scope>
        </dependency>

<!-- mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.4</version>
        </dependency>

<!-- junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>


</project>
  • 編寫實體類表
package com.rf.domain;

import java.util.Date;

public class User {
//    `id` INT(11) NOT NULL AUTO_INCREMENT,
    private  int id;
//`username` VARCHAR(32) NOT NULL COMMENT '使用者名稱稱',
    private String username;
//`birthday` DATETIME DEFAULT NULL COMMENT '生日',
    private Date birthday;
//`sex` CHAR(1) DEFAULT NULL COMMENT '性別',
    private String sex;
//`address` VARCHAR(256) DEFAULT NULL COMMENT '地址',PRIMARY KEY (`id`)
    private String address;

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", birthday=" + birthday +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                '}';
    }

    public int getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getSex() {
        return sex;
    }

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

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}
  • 編寫mapper對映配置檔案,在java.com.rf.mapper下
<?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="UserMapper">
<!-- 查詢所有-->
    <select id="findAll" resultType="com.rf.domain.User">
        select * from user
    </select>

<!-- 插入操作-->
    <insert id="saveUser" parameterType="com.rf.domain.User">
        insert into user (username,birthday,sex,address) values  (#{username},#{birthday},#{sex},#{address})
    </insert>

<!-- 修改操作-->
<update id="updateUser" parameterType="com.rf.domain.User">
    update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id = #{id}
</update>
    
<!--  刪除操作-->
    <delete id="deleteUser" parameterType="int">
        delete from user where id=#{id}
    </delete>

</mapper>
  • 編寫sqlMapConfig.xml核心配置檔案,只有一份,在resource檔案下
<?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="mysql">
        <environment id="mysql">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///mybatis_db"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
                
            </dataSource>
        </environment>
    </environments>

<!--    對映檔案配置-->
    <mappers>
<!--  單個檔案對映-->
        <mapper resource="com/rf/domain/User.java"></mapper>
        
<!--  批量對映-->
<!--        <package name="com/rf/domain"/>-->
    </mappers>
    
</configuration>
  • 測試程式碼
import com.rf.domain.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 org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;

public class UserTest {
    private SqlSession sqlSession;

    @Test
    public void testfindAll() throws IOException {
        //1.載入核心配置檔案import org.apache.ibatis.io.Resources;
        InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.獲取SqlSessionFactory 工廠物件
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //3.獲取會話物件
        SqlSession sqlSession = sessionFactory.openSession();
        //4.執行SQL語句
        List<User> users = sqlSession.selectList("UserMapper.findAll");
        for (User user : users) {
            System.out.println(user);
        }
        //5.釋放資源
        sqlSession.close();
    }

    @Test
    public void testsaveUser() throws IOException {
        //1.載入核心配置檔案import org.apache.ibatis.io.Resources;
        InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.獲取SqlSessionFactory 工廠物件
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //3.獲取會話物件,這裡未設定自動提交
        SqlSession sqlSession = sessionFactory.openSession();
        //4.執行SQL語句
        User user = new User();
        user.setUsername("xiaoming");
        user.setBirthday(new Date());
        user.setSex("男");
        user.setAddress("北京朝陽");
        sqlSession.insert("UserMapper.saveUser", user);
        // 一定手動提交
        sqlSession.commit();

        //5.釋放資源
        sqlSession.close();
    }

    @Test
    public void testupdateUser() throws IOException {
        //1.載入核心配置檔案import org.apache.ibatis.io.Resources;
        InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.獲取SqlSessionFactory 工廠物件
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //3.獲取會話物件
        SqlSession sqlSession = sessionFactory.openSession();
        //4.執行SQL語句
        //4.執行SQL語句
        User user = new User();
        user.setId(3);
        user.setUsername("lucy");
        user.setBirthday(new Date());
        user.setSex("女");
        user.setAddress("北京");
        sqlSession.update("UserMapper.updateUser",user);
        sqlSession.commit();
        //5.釋放資源
        sqlSession.close();
    }

    @Test
    public void testdeleteUser() throws IOException {
        //1.載入核心配置檔案import org.apache.ibatis.io.Resources;
        InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.獲取SqlSessionFactory 工廠物件
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //3.獲取會話物件
        SqlSession sqlSession = sessionFactory.openSession();
        //4.執行SQL語句
        List<User> users = sqlSession.selectList("UserMapper.deleteUser", 4);
        sqlSession.commit();
        //5.釋放資源
        sqlSession.close();
    }
}
  • 注意事項
    • 進行增刪改操作時要提交事務commit,否則在建立會話物件時就設定自動提交為true
    • SQL語句中使用#{字串}方式引用傳遞的單個引數
    • 在對映檔案中使用parameterType設定插入的資料型別,使用resultType設定返回的封裝型別

4. 核心配置檔案概述

  • SqlMapConfig.xml檔案層級關係,設定時參照該順序
  • environments 資料庫環境的配置,支援多環境配置
    • 事務管理器transactionManager
      • JDBC 直接使用了JDBC的提交和回滾設定,依賴於從資料來源得到的連線來管理事務作業域
      • MANAGED 讓容器接管事務的生命週期
    • 資料來源dataSource
      • POOLED 利用資料連線池
      • UNPOOLED 不使用資料連線池,每次都單獨建立並關閉連線
      • JNDI 為了能在如EJB或應用伺服器這類容器中使用,容器可以集中或在外部配置資料來源,然後放置JNDI 上下文的資料來源引用
  • properties 將資料來源的配置單獨抽取為一個properties檔案,載入外在配置
jdbc.driver= com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis_db
jdbc.username=root
jdbs.password=123456
<?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>

    <properties resource="jdbc.properties"></properties>
<!--    執行環境配置-->
    <environments default="mysql">
        <environment id="mysql">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
                
            </dataSource>
        </environment>
    </environments>

<!--    對映檔案配置-->
    <mappers>
<!--  單個檔案對映-->
        <mapper resource="com/rf/mapper/UserMapper.xml"></mapper>

<!--  批量對映-->
<!--        <package name="com/rf/domain"/>-->
    </mappers>
    
</configuration>
  • typeAliases起別名,簡化對映檔案java型別
<!-- 查詢所有-->
    <select id="findAll" resultType="user">
        select * from user
    </select>
<!--  起別名-->
    <typeAliases>
        <typeAlias type="com.rf.domain.User" alias="user"></typeAlias>
    </typeAliases>
  • mappers 對映檔案配置
1. 使用相對於類路徑的資源引用,例如:
<mapper resource="org/mybatis/builder/userMapper.xml"/>
2. 使用完全限定資源定位符(URL),例如:
<mapper url="file:///var/mappers/userMapper.xml"/>3. 使用對映器介面實現類的完全限定類名,例如:
<mapper class="org.mybatis.builder.userMapper"/>
4. 將包內的對映器介面實現全部註冊為對映器,例如:
<package name="org.mybatis.builder"/>

5. mybatis API 引用

  SqlSession工廠構建器SqlSessionFactoryBuilder,通過載入mybatis的核心檔案的輸入流的形式構建一個SqlSessionFactory物件。Resources 工具類,這個類在 org.apache.ibatis.io 包中。Resources 類幫助你從類路徑下、檔案系統或一個 web URL 中載入資原始檔

SqlSession工廠物件SqlSessionFactory 建立SqlSession 例項

SqlSession會話物件進行CRUD

  • mybatis基本原理
  • mybatis動態代理
    • 傳統dao模式需要編寫dao介面和實現類,實現類中存在mybatis模板重複,實現類呼叫方法時xml檔案中的sql statement硬編碼到java程式碼中
    • 採用mybatis的基於代理介面方式實現持久層的開發,只需要編寫Mapper介面,mybatis會動態生成實現類的物件
  • Mapper.xml對映檔案中的namespacemapper介面的全限定名相同
  • Mapper介面方法名和Mapper.xml對映檔案中定義的每個statementid相同
  • Mapper介面方法的輸入引數型別和mapper.xml對映檔案中定義的每個sqlparameterType的型別相同
  • Mapper介面方法的輸出引數型別和mapper.xml對映檔案中定義的每個sqlresultType的型別相同
  • 內部執行原理:mapper是一個代理物件,是有MapperProxy代理產生的,MapperProxy使用invoke方法,最終呼叫了mapperMethod.execute(SqlSession,args),而該方法execute最終執行的是SqlSession的CRUE操作。