MyBatis 簡單使用說明(2)

先簡單對MyBatis的使用作一個簡要說明,後邊會針對MyBatis幾個核心原理作重點說明。java

MyBatis簡單使用

使用MyBatis能夠分如下幾個關鍵點mysql

  • 引入MyBatis依賴
  • 配置mybatis-config.xml配置文件
  • 建立數據庫實體類與Mapper映射文件
  • 經過SqlSessionFactoryBuilder加載配置並使用

如下按步驟寫一個單元測試:redis

  1. 引入依賴
<!-- mybatis依賴包 --><dependency>
	<groupId>org.mybatis</groupId>
	<artifactId>mybatis</artifactId>
	<version>3.5.4</version></dependency><!-- 數據庫驅動 須要使用 5.1.40以上纔可解決mysql json格式亂碼問題 --><dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>5.1.40</version></dependency><!-- lombok --><dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
	<version>1.16.6</version></dependency>
  1. 編寫配置文件

mybatis-config.xmlsql

<?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="db.properties"></properties>
    <settings>
        <!-- 打印查詢語句 -->
        <setting name="logImpl" value="STDOUT_LOGGING" />

        <!-- 控制全局緩存(二級緩存),默認 true-->
        <setting name="cacheEnabled" value="false"/>

        <!-- 延遲加載的全局開關。當開啓時,全部關聯對象都會延遲加載。默認 false  -->
        <setting name="lazyLoadingEnabled" value="false"/>
        <!-- 當開啓時,任何方法的調用都會加載該對象的全部屬性。默認 false,可經過select標籤的 fetchType來覆蓋-->
        <setting name="aggressiveLazyLoading" value="true"/>
        <!--  Mybatis 建立具備延遲加載能力的對象所用到的代理工具,默認JAVASSIST -->
        <!--<setting name="proxyFactory" value="CGLIB" />-->
        <!-- STATEMENT級別的緩存,使一級緩存,只針對當前執行的這一statement有效,至關於關閉一級緩存 -->
        <!--
                <setting name="localCacheScope" value="STATEMENT"/>
        -->
        <setting name="localCacheScope" value="SESSION"/>
    </settings>

    <typeAliases>
        <typeAlias alias="user" type="com.freecloud.plug.mybatis.entity.User" />
        <typeAlias alias="myBatisJson" type="com.freecloud.plug.mybatis.entity.MyBatisJson" />
        <typeAlias alias="department" type="com.freecloud.plug.mybatis.entity.Department" />
        <typeAlias alias="userAndDepartment" type="com.freecloud.plug.mybatis.entity.UserAndDepartment" ></typeAlias>
    </typeAliases>

    <!-- 自定義類型轉換器 -->
    <typeHandlers>
            <typeHandler handler="com.freecloud.plug.mybatis.type.JsonTypeHandler"></typeHandler>
    </typeHandlers>

    <plugins>
        <plugin interceptor="com.freecloud.plug.mybatis.plugins.SQLExecuteTimeInterceptor">
            <property name="name" value="zhangsan" />
        </plugin>
        <plugin interceptor="com.freecloud.plug.mybatis.plugins.SimpleTableInterceptor"></plugin>
    </plugins>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/><!-- 單獨使用時配置成MANAGED沒有事務 -->
            <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="mapper/UserMapper.xml"/>
        <mapper resource="mapper/MyBatisJsonMapper.xml"/>
        <mapper resource="mapper/DepartmentMapper.xml"/>
    </mappers></configuration>

db.properties數據庫鏈接配置數據庫

jdbc.driver=com.mysql.jdbc.Driverjdbc.url=jdbc:mysql://127.0.0.1:3306/data_test?useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=truejdbc.username=rootjdbc.password=123456

初始化數據,用於後邊的單元測試。apache

## 部門表CREATE TABLE `department` (  `id` int(5) NOT NULL,  `name` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,  `parent_id` int(5) NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;## 員工表CREATE TABLE `user_department` (  `id` int(5) NOT NULL,  `name` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,  `age` int(4) DEFAULT NULL,  `default_department_id` int(5) NOT NULL,  `all_department_id` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;## 初始化部門insert into department values (1,'部門1',null);insert into department values (2,'部門2',1);insert into department values (3,'部門3',null);## 初始化員工insert into user_department values (1,'張三',18,1,'2,3');insert into user_department values (2,'李4',18,2,'1,2');insert into user_department values (3,'王5',18,3,'3');insert into user_department values (4,'趙6',18,1,'1');
  1. 數據庫實體類與mapper配置
/**
  * 業務實體對象
  */@Data@NoArgsConstructor@AllArgsConstructorpublic class User implements Serializable {    /** 主鍵ID */
    private Long id;    /** 姓名 */
    private String name;    /** 年齡 */
    private Integer age;
}

UserMapper.xml 映射文件json

<?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="com.freecloud.plug.mybatis.dao.UserMapper">
    <!-- 聲明這個namespace使用二級緩存 -->
    <!--    <cache/>-->

    <!-- 使用Redis做爲二級緩存 -->
    <!--
        <cache type="org.mybatis.caches.redis.RedisCache"
               eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
    -->
    <cache type="org.apache.ibatis.cache.impl.PerpetualCache"
           size="1024"
           eviction="LRU"
           flushInterval="120000"
           readOnly="false"/>

    <resultMap id="BaseResultMap" type="user">
        <id column="id" property="id" jdbcType="INTEGER"/>
        <result column="name" property="name" jdbcType="VARCHAR"/>
        <result column="age" property="age" jdbcType="INTEGER"/>
    </resultMap>

    <!-- 對象關聯查詢,一條sql直接查詢   -->
    <resultMap id="UserAndDepartmentResultMap" type="userAndDepartment">
        <id column="id" property="id" jdbcType="INTEGER"/>
        <result column="name" property="name" jdbcType="VARCHAR"/>
        <result column="age" property="age" jdbcType="INTEGER"/>
        <association property="defaultDepartment" javaType="com.freecloud.plug.mybatis.entity.Department" >
            <id column="department_id" property="id"></id>
            <result column="department_name" property="name" ></result>
        </association>
    </resultMap>

    <!-- 聯合查詢,會產生 N+1的問題 -->
    <resultMap id="UserAndDepartmentResultMap1" type="userAndDepartment">
        <id column="id" property="id" jdbcType="INTEGER"/>
        <result column="name" property="name" jdbcType="VARCHAR"/>
        <result column="age" property="age" jdbcType="INTEGER"/>
        <!-- 此處能夠誇namespace調用,但要保證當前應用加載對應mapper -->
        <association property="defaultDepartment" column="default_department_id"
                     javaType="com.freecloud.plug.mybatis.entity.Department"
                     select="com.freecloud.plug.mybatis.dao.DepartmentMapper.byId"  ></association>
    </resultMap>

    <!-- 聯合查詢,一對多 -->
    <resultMap id="UserAndDepartmentResultMap2" type="userAndDepartment">
        <id column="id" property="id" jdbcType="INTEGER"/>
        <result column="name" property="name" jdbcType="VARCHAR"/>
        <result column="age" property="age" jdbcType="INTEGER"/>
        <!-- 此處能夠誇namespace調用,但要保證當前應用加載對應mapper --><!--        <association property="defaultDepartment" column="default_department_id"--><!--                     javaType="com.freecloud.plug.mybatis.entity.Department"--><!--                     select="com.freecloud.plug.mybatis.dao.DepartmentMapper.byId"  ></association>-->

        <collection property="departmentList" column="all_department_id"
                    ofType="com.freecloud.plug.mybatis.entity.Department"
                    select="com.freecloud.plug.mybatis.dao.DepartmentMapper.byIds"></collection>
    </resultMap>


    <select id="byId" resultMap="BaseResultMap" statementType="PREPARED" >
        select * from user_department where id = #{id}    </select>


    <insert id="save" parameterType="user" >
        insert into user_department (id,name,age)
        values (#{id},#{name},#{age})    </insert>

    <update id="update" parameterType="user">
        update user_department        <set>
            <if test="name != null">
                name = #{name}            </if>
            <if test="age != null">
                ,age = #{age}            </if>
        </set>
        where id = #{id}    </update>


    <select id="getUserAndDepartmentById" parameterType="long" resultMap="UserAndDepartmentResultMap" >
        select a.id,a.name,a.age,b.id as department_id,b.name as department_name
        from user_department a
        left join department b
        on a.default_department_id = b.id
        where a.id = #{id}    </select>


    <select id="getUserAndDepartmentById1" parameterType="long" resultMap="UserAndDepartmentResultMap1" >
        select *
        from user_department a
        where a.id = #{id}    </select>

    <select id="getUserAndDepartmentById2" parameterType="long" resultMap="UserAndDepartmentResultMap2" >
        select *
        from user_department a
        where a.id = #{id}    </select></mapper>

mapper調用接口,方法名要到Mapper.xml文件中的配置的Id相同,不然沒法映射成功。api

public interface UserMapper {    /**
     * 根據主鍵查詢
     * @param id
     * @return
     */
    public User byId(Long id);    /**
     * 新增
     * @param user
     * @return
     */
    public void save(User user);    /**
     * 修改
     * @param user
     */
    public void update(User user);    /**
     * 多表關聯查詢
     * @param id
     * @return
     */
    public UserAndDepartment getUserAndDepartmentById(Long id);    /**
     * 關聯查詢,有N + 1問題
     * @param id
     * @return
     */
    public UserAndDepartment getUserAndDepartmentById1(Long id);    /**
     * 關聯查詢,1對多
     * @param id
     * @return
     */
    public UserAndDepartment getUserAndDepartmentById2(Long id);
}
  1. 單元測試
package com.freecloud.plug.mybatis;import com.freecloud.common.LoggerUtil;import com.freecloud.plug.mybatis.dao.UserMapper;import com.freecloud.plug.mybatis.entity.User;import com.freecloud.plug.mybatis.entity.UserAndDepartment;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.Before;import org.junit.Test;import java.io.IOException;import java.io.InputStream;/**
 * @Author: maomao
 * @Date: 2021-04-08 11:36
 */public class MyBatisTest {    private SqlSessionFactory sqlSessionFactory;    @Before
    public void init() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }    /**
     * 使用mybatis api 方式硬編碼方式
     */
    @Test
    public void testApiStatement(){
        SqlSession sqlSession = sqlSessionFactory.openSession();        try {
            sqlSession.selectOne("com.freecloud.plug.mybatis.dao.UserMapper.byId",1);
        }finally {
            sqlSession.close();
        }
    }    /**
     * 測試使用mapper包裝直接使用接口調用
     */
    @Test
    public void testMapperInterface(){
        SqlSession sqlSession = sqlSessionFactory.openSession();        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            User user = userMapper.byId(1L);
            LoggerUtil.printThread(user.toString());
        }finally {
            sqlSession.close();
        }
    }    /**
     * 多表關聯查詢
     */
    @Test
    public void testUserAndDepartment(){
        SqlSession sqlSession = sqlSessionFactory.openSession();        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            UserAndDepartment user = userMapper.getUserAndDepartmentById(1L);
            LoggerUtil.printThread(user.toString());
        }finally {
            sqlSession.close();
        }
    }    /**
     * 關聯查詢,有N + 1問題
     */
    @Test
    public void testUserAndDepartment1(){
        SqlSession sqlSession = sqlSessionFactory.openSession();        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            UserAndDepartment user = userMapper.getUserAndDepartmentById1(1L);
            LoggerUtil.printThread(user.toString());
        }finally {
            sqlSession.close();
        }
    }    /**
     * 關聯查詢,1對多
     */
    @Test
    public void testUserAndDepartment2(){
        SqlSession sqlSession = sqlSessionFactory.openSession();        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            UserAndDepartment user = userMapper.getUserAndDepartmentById2(1L);
            LoggerUtil.printThread(user.toString());
        }finally {
            sqlSession.close();
        }
    }
}

使用以上例子,就能夠運行起來MyBatis。看單元測試中的使用方法,分別描述了幾種常見方式。緩存

  • 使用傳統硬編碼直接經過Mapper映射器中配置的ID訪問
  • 使用一個空接口實現方法調用(無實現類),使用www.phone-8.com,sqlSession.getMapper(UserMapper.class);方式獲取實例執行
  • 對象關聯性查詢一對多、一對一形式

核心對象

在單元測試類中咱們看到了MyBatis裏面的幾個核心對象:安全

  • SqlSessionFactoryBuiler
  • SqlSessionFactory
  • SqlSession
  • Mpper

這幾個核心對象在MyBatis的整個工做流程裏面的不一樣環節發揮做用。若是咱們不用容器,本身去管理這些對象的話,咱們必須考慮一個問題:何時建立和銷燬這些對象?

在一些分佈式應用裏,多線程高併發場景中,若是要寫出高效的代碼,就必須瞭解這四個對象的生命週期。

SqlSessionFactoryBuiler

它是用來構建SqlSessionFactory與解析mybatis-config等配置的,而SqlSessionFactory只須要一個,因此只要構建了一個SqlSessionFactory以後它的使命就完成了,也就沒有存在的必要了。因此它的生命週期只存在於方法的局部

SqlSessionFactory

SqlSessionFactory是用來建立SqlSession的,每次訪問數據庫都須要建立一個回話。由於咱們一直有建立會話的須要,因此SqlSessionFactory應該存在於應用的整個生命週期中(做用域是應用做用域)。建立SqlSession只須要一個實例來作這件事就能夠了,不然會形成混亂和資源浪費。因此咱們應該採用單例模式。

通常工廠類在都應該是單例模式。

SqlSession

SqlSession是一個會話,由於它不是線程安全的,不能在線程間共享。因此咱們在請求開始的時候建立一個SqlSession對象,在請求結束時要及時關閉它。也能夠把它理解成Jdbc 的Connection鏈接。

Mapper

實際是Mapper是一個代理對象,是從SqlSession中獲取的。

UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

它的做用是發送Sql來操做數據庫的數據。它應該在一個SqlSession事務方法以內。

對象 做用域
SqlSessionFactoryBuilder 方法局部(method)
SqlSessionFactory 應用級別(application)
SqlSession 請求和操做(request、method)
Mapper 方法(method)

以上就是四個核心對象的生命週期。

相關文章
相關標籤/搜索