MyBatis入門

MyBatis主要組成部分

clipboard.png
1. SqlSessionFactoryBuilder(構(gòu)造器)

根據(jù)配置信息或代碼生成SqlSessionFactory接口

2. SqlSessionFactory(工廠接口)

依靠工廠來(lái)生成SQLSesson(會(huì)話)

3. SqlSession(sql處理器)

既可以發(fā)送SQL去執(zhí)行并返回結(jié)果,也可以獲取Mapper的接口

4. SQL Mqapper(映射規(guī)則及SQL定義)

MyBatis的新設(shè)計(jì)組件,由Java接口和XML文件(或注解)構(gòu)成,需要給出對(duì)應(yīng)的SQL和映射規(guī)則。負(fù)責(zé)發(fā)送SQL去執(zhí)行。并返回結(jié)果。

SqlSessionFactory

MyBatis的應(yīng)用都是以SqlSessionFactory的實(shí)例為中心。SqlSessionFactory的實(shí)例是由SqlSessionFactoryBuilder生成的。

注:SqlSessionFactory是一個(gè)工廠接口,不是實(shí)現(xiàn)類

SqlSessionFactory的任務(wù)是創(chuàng)建SQLSession。SQLSession類似于JDBC的Connection對(duì)象。

可用XML配置和代碼方式創(chuàng)建SQLSessionFactory,推薦使用XML配置方法

SQLSession

SqlSession是一個(gè)接口類,相當(dāng)于前臺(tái),主要和程序員交接,調(diào)用Executor接口執(zhí)行相應(yīng)操作。SqlSession在中間負(fù)責(zé)接收功能參數(shù),之后返回結(jié)果(是一個(gè)黑箱操作)

SQLSession類似于JDBC中的Connection對(duì)象,需要及時(shí)關(guān)閉

SQLSession的執(zhí)行包括兩種方法:1.獲取映射器,讓映射器通過(guò)命名空間和方法名稱找到對(duì)應(yīng)的SQL,發(fā)送到數(shù)據(jù)庫(kù)并執(zhí)行。2.直接通過(guò)命名信息去執(zhí)行SQL并返回結(jié)果。在SQLSession層可以通過(guò)update,insert,select,delete等方法,帶上SQL的id來(lái)操作在XML中配置的SQL,進(jìn)而完成工作。也支持事物,通過(guò)commit和rollback方法提交或者回滾事物。


clipboa1rd.png

映射器 (XML Mapper和Java接口)

映射器是由Java接口和XML文件(或注解)組成,作用是:

  • 定義參數(shù)類型。
  • 描述緩存。
  • 描述SQL語(yǔ)句。
  • 定義查詢結(jié)果和POJO的映射關(guān)系。

映射器有兩種實(shí)現(xiàn)方式,1. xml文件描述。2. java代碼實(shí)現(xiàn),添加注解方式。

建議使用xml方式

MyBatis生命周期

SQLSessionFactoryBuilder

利用xml配置文件或java編碼構(gòu)建SQLSessionFactory,可構(gòu)建多個(gè)SQLSessionFactory。它是一個(gè)構(gòu)建器,一旦構(gòu)建出SQLSessionFactory,它的作用就完成了。只存在于方法的局部,作用就是生產(chǎn)SQLSessionFactory。

SQLSessionFactory

SQLSessionFactory的作用是創(chuàng)建SQLSession,每次訪問(wèn)數(shù)據(jù)庫(kù)都需要它來(lái)創(chuàng)建SQLSession,所以SQLSessionFactory存在于MyBatis的整個(gè)生命周期。

通常一個(gè)數(shù)據(jù)庫(kù)對(duì)應(yīng)一個(gè)SQLSessionFactory,避免消耗過(guò)多的數(shù)據(jù)庫(kù)連接資源。

SQLSession

SQLSession是一個(gè)會(huì)話,它的生命周期是在請(qǐng)求數(shù)據(jù)庫(kù)處理事務(wù)的過(guò)程當(dāng)中,相當(dāng)于JDBC的Connection對(duì)象,屬于==線程不安全對(duì)象==,在涉及多線程時(shí)需格外注意,操作數(shù)據(jù)庫(kù)需要注意其隔離級(jí)別,數(shù)據(jù)庫(kù)鎖等高級(jí)特性。創(chuàng)建并使用完SQLSession后必須及時(shí)

關(guān)閉,減少資源占用。

Mapper

Mapper是一個(gè)接口,沒(méi)有任何實(shí)現(xiàn)類,作用是發(fā)送SQL,再返回需要的結(jié)果或執(zhí)行SQL修改數(shù)據(jù)庫(kù)的數(shù)據(jù)。 它是在一個(gè)SQLSession事物的方法中使用的,然后廢棄。

Mybatis設(shè)置

<?xml version = "1.0" encoding = "UTF-8"?>
<configuration><!--配置-->
    <properties/><!--屬性-->
    <settings/><!--設(shè)置-->
    <typeAliases/><!--類型命名-->
    <typeHandlers/><!--類型處理器-->
    <objectFactory/><!--對(duì)象工廠-->
    <plugins/><!--插件-->
    <environments><!--配置環(huán)境-->
        <environment><!--環(huán)境變量-->
            <transactionManager/><!--事物管理器-->
            <dataSource/><!--數(shù)據(jù)源-->
        </environment>
    </environments>
    <databaseIdProvider/><!--數(shù)據(jù)庫(kù)廠商標(biāo)識(shí)-->
    <mappers/><!--映射器-->
</configeration>    
    

properties元素

properties是個(gè)配置屬性的元素,配置文件的上下文中使用。

三種配置方式

  1. property子元素
  2. properties配置文件
  3. 程序參數(shù)配置

property子元素

property子元素配置代碼如下:

<properties>
    <property name = "dirver" value = "com.mysql.jdbc.Dirver"/>
    <property name = "url" value = "jdbc:mysql://localhost:3306/mybatis"/>
    <property name = "username" value = "root"/>
    <property name = "password" value = "123"/>
</properties>

這樣我們就可以在上下文中使用配置好的properties屬性值。

<dataSourse type = "POOLED">
    <property name = "dirver" value = "${dirver}"/>
    <property name = "url" value = "${url}"/>
    <property name = "username" value = "${username}"/>
    <property name = "password" value = "${password}"/>
</dataSourse>

properties配置文件

使用properties配置文件可讓多個(gè)配置文件重復(fù)使用

<!--jdbc.properties-->
dirver = com.mysql.jdbc.Dirver
url = jdbc:mysql://localhost:3306/mybatis
username = root
password = 123

引用變量代碼如下:

<properties resource = "jdbc.properties"/>

程序參數(shù)傳遞

在實(shí)際對(duì)于用戶名密碼需要進(jìn)行加密處理,則需要讓jdbc.properties中的username和password兩個(gè)屬性使用加密字符串,需要在生產(chǎn)SQLSessionFactory之前轉(zhuǎn)化為明文,使用系統(tǒng)提供的decode(str)方法解密。使用代碼方式創(chuàng)建SQLSessionFactory:

InputStream cfgStream = null;
reader cdgReader = null;
InputStream proStream = null;
Reader proReader = null;
Properties properties = null;
try{
    //讀入配置文件流
    cfgStream = Resources.getResourceAsStream("MyBatis-config.xml");
    cfgReader = new InputStreamReader(cfgStream);
    //讀入屬性文件
    proStream = Resources.getResourceAsStream("jdbc.properties");
    proReader = new InputStreamReader(proStream);
    properties = new Properties();
    properties.load(proReader);
    //解密為明文
    properties.setProperty("username",decode(properties.getProperty("username")));
    properties.setProperty("password",decode(properties.getProperty("password")));
}catch (IOException ex){
    Logger.getLogger(SqlSessionFactoryUtil.class.getName()).log(Level.SERVRE,null,ex);
}
sysnchronized(CLASS_LOCK){
    if(sqlSessionFactory == null){
        //使用屬性來(lái)創(chuàng)建SQLSessionFactory
        sqlSessionFactory = new SqlSessionFactoryBuilder().builder(cfgReader,properties);
    }
}

三種配置優(yōu)先級(jí)

通過(guò)方法傳遞 > 讀取properties文件 > property直接指定

三種方法不要混合使用,容易造成管理混亂。
優(yōu)先使用讀取properties文件方式。

設(shè)置

設(shè)置(setting)是MyBatis最復(fù)雜的一塊配置,也是最重要的配置塊之一。
它會(huì)改變MyBatis的運(yùn)行行為,但是即使不配置setting,MyBatis也能正常使用。
完整的setting配置如下:

<settings>
    <setting name = "cacheEnabled" value = "true"/>
    <setting name = "lazyLoadingEnabled" value = "true"/>
    <setting name = "multipleResultSetsEnabled" value = "true"/>
    <setting name = "useColumnLabel" value = "true"/>
    <setting name = "useGenerateKeys" value = "false"/>
    <setting name = "autoMappingBehavior" value = "PARTIAL"/>
    <setting name = "defaultExcutorType" value = "SIMPLE"/>
    <setting name = "defaultStatementTimeout" value = "25"/>
    <setting name = "safeRowBoundsEnabled" value = "false"/>
    <setting name = "mapUnderscoreToCamelCase" value = "false"/>
    <setting name = "localCacheScope" value = "SESSION"/>
    <setting name = "jdbcTypeForNull" value = "OTHER"/>
    <setting name = "lazyLoadTriggerMethods" value = "equals,clone,hashCode,toString"/>
</settings>

大多時(shí)候不必配置他們,或只需配置少數(shù)幾項(xiàng)。

別名

別名(typeAliases)是一個(gè)指代名稱,當(dāng)遇到類全限定名過(guò)長(zhǎng)時(shí),我們使用typeAliases去代替它。這個(gè)名稱在MyBatis上下文中使用。別名在MyBatis中分為系統(tǒng)定義別名和自定義別名兩類。

別名不區(qū)分大小寫。

一個(gè)typeAliases的實(shí)例是在解析配置文件時(shí)生成的,然后長(zhǎng)期保存在configuration對(duì)象中,當(dāng)我們使用時(shí)就不必再次運(yùn)行生成實(shí)例了。

系統(tǒng)自定義別名

MyBatis系統(tǒng)定義了一些經(jīng)常使用的類型的別名,例如:數(shù)值,字符串,日期集合等,可以在MyBatis中直接調(diào)用,不要重復(fù)定義把他們覆蓋。

自定義別名

MyBatis允許自定義別名,代碼例如:

<!--自定義別名-->
<typeAliases>
    <typeAlias alias = "role" type = "com.learn.chapter2.po.Role"/>
</typeAliases>

當(dāng)自定義別名過(guò)多時(shí),可以定義自動(dòng)掃描包的范圍,并在需要定義的類的上方加注解即可批量定義別名。

<!--掃描包,批量定義別名-->
<typeAliases>
    <package name = "com.learn.chapter2.po"/>
    <package name = "com.learn.chapter3.po"/>
</typeAliases>
/*
*別名注解
*/
@Alias("role")
public class Role{
    //some code
}

不加注解也能加載別名,默認(rèn)將類名第一個(gè)字母變?yōu)樾?,故一定要避免重名?/p>

typeHandler類型處理器

MyBatis在預(yù)處理語(yǔ)句(prepareStatment)中設(shè)置一個(gè)參數(shù),或從結(jié)果集(ResultSet)中取出一個(gè)值時(shí),都會(huì)用注冊(cè)了的typeHandler進(jìn)行處理。

由于數(shù)據(jù)庫(kù)的廠商不同,不同的廠商設(shè)置的參數(shù)可能不同,數(shù)據(jù)庫(kù)也可以自定義數(shù)據(jù)類型,typeHandler允許根據(jù)項(xiàng)目的需要自定義設(shè)置java傳遞到數(shù)據(jù)庫(kù)的參數(shù)中,或者從數(shù)據(jù)庫(kù)讀出數(shù)據(jù),也需要進(jìn)行特殊處理,這些都是在自定義typeHandler中處理,尤其是枚舉類型常常需要使用typeHandler來(lái)進(jìn)行轉(zhuǎn)換。

typeHandler分為系統(tǒng)定義和自定義兩種,一般系統(tǒng)定義可滿足絕大部分功能。自定義typeHandler務(wù)必小心謹(jǐn)慎。

typeHandler常用配置為javaType和jdbcType,作用是將JavaType轉(zhuǎn)化為jdbcType,或者將數(shù)據(jù)庫(kù)取出結(jié)果從jdbcType轉(zhuǎn)化為JavaType。

.......

ObjectFactory

mybatis在構(gòu)建一個(gè)結(jié)果返回的時(shí)候,需要用到ObjectFactory(對(duì)象工廠)去構(gòu)建POJO,在MyBatis中也可以定制自己的對(duì)象工廠。一般使用默認(rèn)的ObjectFactory即可。

自定義ObjectFactory需要進(jìn)行配置

<objectFactory type="com.learn.chapter3.objectFactory.MyObjectFactory">
    <property name="name" value="MyObjectFactory" />
</objectFactory>

自定義ObjectFactory需要刷新ObjectFactory接口,而系統(tǒng)自帶的DefaultObjectfactory已經(jīng)實(shí)現(xiàn)了ObjectFactory接口,故只需讓myObjectFactory基礎(chǔ)DefaultObjectFactory即可。實(shí)例如下:


//MyObjectFactory
packgae com.learn.chapter3.objectFactory;
improt java util.List;
import java.util.Properties;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.log4j.Logger;

public class MyObjectFactory extends DefaultObjectFactory{
    
    private static final long serialVerSionUID = -381482721604028629L;
    Logger log = Logger.getLogger(MyobjectFactory.class);
    
    @Override
    public void setProperties(Properties prprty){
        log.info("定制屬性:"+prprty);
        super.setProperties(prprts);
    }
    
    @Override
    public <T> T create(Class<T> type){
        log.info("使用定制對(duì)象工廠的create的方法構(gòu)建單個(gè)對(duì)象");
        return super.create(type);
    }
    
    @Override
    public <T> T create(Class<T> type, List<Class<?>> list, List<Objetc> list1){
        log.info("使用定制對(duì)象工廠的create方法構(gòu)建列表對(duì)象");
        return super.create(type,list,list1);
    }
    
    @Override
    public <T> boolean isCollection(Class<T> type){
        return super.isCollection(type);
    }
    
}

插件

比較復(fù)雜,會(huì)出現(xiàn)一些覆蓋MyBatis內(nèi)部核心的行為。

environment配置環(huán)境

注冊(cè)數(shù)據(jù)源

配置環(huán)境可以注冊(cè)多個(gè)數(shù)據(jù)源(dataSource),每個(gè)數(shù)據(jù)源需要進(jìn)行數(shù)據(jù)庫(kù)源配置及數(shù)據(jù)庫(kù)事物(transactionManager)配置。

連接池?cái)?shù)據(jù)配置示例:

<environments default="development">
    <environment id="development">
        <transactionManager type="JDBC">
            <property name="autoCommit" value="false"/>
        </transactionManager>
        <dataSource type="POOLED">
            <property name="dirver" value="com.mysql.jdbc.Dirver"/>
            <property name="url" value="jdbc:mysql://localhost:3306/oa"/>
            <property name="username" value="root"/>
            <property name="password" value="123"/>
        </dataSource>
    </environment>
</environments>

上述代碼中environments中default屬性,標(biāo)明在缺省情況下啟用哪個(gè)數(shù)據(jù)源。

  • environment元素是配置一個(gè)數(shù)據(jù)源的,屬性id是設(shè)置這個(gè)數(shù)據(jù)源的標(biāo)識(shí),以方便mybatis在上下文中使用它。
  • transactionManager配置數(shù)據(jù)源的數(shù)據(jù)庫(kù)事物,其中type屬性有三種配置方式。
  1. JDBC,采用JDBC方式管理事物,在獨(dú)立編碼中常常使用。
  2. MANAGED,采用容器的方式管理事物,在JNDI數(shù)據(jù)源中使用。
  3. 自定義,由使用者自定義數(shù)據(jù)庫(kù)事物管理辦法,適用于特殊應(yīng)用。
  • property元素可以配置數(shù)據(jù)源各類屬性,這里的autoCommit=false,則是要求數(shù)據(jù)源不自動(dòng)提交。
  • dataSource標(biāo)簽配置的是數(shù)據(jù)源的連接信息,type屬性提供數(shù)據(jù)庫(kù)的連接方式的配置,在mybatis中有幾種連接方式:
  1. UNPOOLED,非連接池?cái)?shù)據(jù)庫(kù)。
  2. POOLED,連接池?cái)?shù)據(jù)庫(kù)
  3. JNDI,JNDI數(shù)據(jù)源。
  4. 自定義數(shù)據(jù)源。
    其中property元素是定義數(shù)據(jù)庫(kù)連接的各類參數(shù)。

數(shù)據(jù)庫(kù)事物

數(shù)據(jù)庫(kù)事務(wù)Mybatis交由SqlSession控制,可以通過(guò)SqlSession提交(commit)或者回滾(rollback)。插入一個(gè)角色對(duì)象,如果成功就提交,否則就回滾。

try{
    sqlSession = SqlSessionFactoryUtil.openSqlSession();
    RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
    int count = roleMapper.insertRole(role);
    sqlSession.commit();
    return count;
}catch(Exception ex){
    sqlSession.rollback();
}finally{
    sqlSession.close();
}

大部分時(shí)候都是用Spring框架控制數(shù)據(jù)庫(kù)事物

dataSourceIdProvider數(shù)據(jù)庫(kù)廠商標(biāo)識(shí)

可選擇使用系統(tǒng)默認(rèn)規(guī)則和不使用系統(tǒng)默認(rèn)規(guī)則。

引入映射器的方法

映射器是mybatis最復(fù)雜,最核心的組件。

  • 首先定義映射器接口
package com.learn.chapter3.mapper;
import java.util.List;
import com.learn.chapter3.po.Role;
public interface RoleMapper {
    public Role getRole(Long id);
}
  • 其次給出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="com.learn.chapter3.mapper.RoleMapper">
<select id="getRole" paramenterType="long" resultType="com.learn.chapter3.po.Role">
    select id,role_name as roleName, note from t_role where id=#{id}
</select>
</mapper>

引入映射器的常用方法:

  1. 用文件路徑引入映射器
<mappers>
    <mapper resource="com/learn/chapter3/mapper/roleMapper.xml"/>
</mappers>

  1. 用包名映入映射器
<mappers>
    <package name="com.learn.chapter3.mapper"/>
</mappers>

  1. 用類注冊(cè)引入映射器
<mappers>
    <mapper class="com.learn.chapter3.mapper.UserMapper"/>
    <mapper class="com.learn.chapter3.mapper.RoleMapper"/>
</mappers>

  1. 用userMapper.xml引入映射器
<mappers>
    <mapper url="file:///var/mappers/com/learn/chapter3/mapper/roleMapper/xml"/>
    <mapper url="file:///var/mappers/com/learn/chapter3/mapper/RoleMapper.xml"/>
</mappers>

映射器

MyBatis是針對(duì)映射器構(gòu)造的SQL構(gòu)建的輕量級(jí)框架,并且通過(guò)配置生成對(duì)應(yīng)的JavaBean返回給調(diào)用者,這些配置主要便是映射器。

映射器的主要元素

  • select ,查詢語(yǔ)句,最常用最復(fù)雜的元素??梢宰远x參數(shù),返回結(jié)果集等
  • insert, 插入語(yǔ)句。執(zhí)行后返回一個(gè)整數(shù),代表插入的條數(shù)。
  • update,更新語(yǔ)句。執(zhí)行后返回一個(gè)整數(shù),代表更新的條數(shù)。
  • delete,刪除語(yǔ)句。執(zhí)行后返回一個(gè)整數(shù),代表刪除的條數(shù)。
  • parameterMap,定義參數(shù)映射關(guān)系。即將被刪除的元素,不建議使用。
  • sql, 允許定義一部分的SQL,然后可在各個(gè)地方引用它。
  • resultMap, 用來(lái)描述從數(shù)據(jù)庫(kù)中結(jié)果集中來(lái)加載對(duì)象,最復(fù)雜,最強(qiáng)大的元素。
  • cache,給命名空間緩存配置。
  • cache-ref,其他命名空間緩存配置引用。

select

簡(jiǎn)單select數(shù)據(jù)類型的例子

<select id="countFirstName" parameterType="String" resultType="int">
    select count(*) as total from t_user where name like concat(#{firstName},'%')
</select>

在Dao接口中定義方法

public int countFirstName(String firstName);
  • id 標(biāo)出了這條sql
  • paramenterType 定義參數(shù)類型
  • resultType定義了返回值類型

自動(dòng)映射

setting元素中有autoMappingBehavior參數(shù),當(dāng)它不設(shè)置為NONE時(shí),MyBatis會(huì)設(shè)置自動(dòng)映射功能。只要返回的Sql的列名和javaBean的屬性一致,mybatis會(huì)幫我們回填這些字段,無(wú)需任何配置。

注:數(shù)據(jù)庫(kù)規(guī)范單詞間用下劃線分隔,java中使用駝峰式命名,可以使用列的別名使mybatis自動(dòng)映射,也可以直接配置文件中開(kāi)啟駝峰式命名方式。

傳遞多個(gè)參數(shù)

使用map傳遞多個(gè)參數(shù)

使用Map接口作為參數(shù)實(shí)現(xiàn)多參數(shù)傳遞

<select id="findRoleByMap" parameterType="map" resultMap="roleMap">
    select id, role_name, note 
    from t_role
    where role_name like concat('%',#{roleName},'%')
    and note like concat('%',#{note},'%')
</select>

RoleDao接口:

public List<Role> findRoleByMap(Map<String,String> params);

參數(shù)傳遞代碼如下:

Map<String,String> paramsMap = new HashMap<String,String>();
    paramsMap.put("roleName", "me");
    paramsMap.Put("note","te");
role 
clipbo32ard.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. 簡(jiǎn)介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL、存儲(chǔ)過(guò)程以及高級(jí)映射的優(yōu)秀的...
    笨鳥(niǎo)慢飛閱讀 6,229評(píng)論 0 4
  • MyBatis是一個(gè)可以自定義SQL、存儲(chǔ)過(guò)程和高級(jí)映射的持久層框架。MyBatis 摒除了大部分的JDBC代碼、...
    七寸知架構(gòu)閱讀 6,823評(píng)論 6 56
  • 什么是mybatis MyBatis 是支持定制化 SQL、存儲(chǔ)過(guò)程以及高級(jí)映射的優(yōu)秀的持久層框架。MyBatis...
    seadragonnj閱讀 2,397評(píng)論 0 7
  • 第一次看見(jiàn)這句話是在蔡崇達(dá)的《皮囊》中。當(dāng)他開(kāi)始回頭觀望自己過(guò)往的生命歷程時(shí),看到一個(gè)與當(dāng)時(shí)自己不一樣的視角。而這...
    洛瑤的樂(lè)園閱讀 487評(píng)論 0 2
  • 第一題 在不同領(lǐng)域我們總能看到像天才一樣的人,感覺(jué)他比別人都有天賦。但是經(jīng)過(guò)作者30多年對(duì)這些“天才”研究發(fā)現(xiàn),這...
    小莎妹兒閱讀 181評(píng)論 0 0

友情鏈接更多精彩內(nèi)容