MyBatis主要組成部分
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方法提交或者回滾事物车猬。
映射器 (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è)配置屬性的元素,配置文件的上下文中使用镐作。
三種配置方式
- property子元素
- properties配置文件
- 程序參數(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ū)分大小寫(xiě)寻仗。
一個(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)樾?xiě)镶殷,故一定要避免重名。
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屬性有三種配置方式。
- JDBC焰望,采用JDBC方式管理事物骚亿,在獨(dú)立編碼中常常使用。
- MANAGED熊赖,采用容器的方式管理事物来屠,在JNDI數(shù)據(jù)源中使用。
- 自定義,由使用者自定義數(shù)據(jù)庫(kù)事物管理辦法俱笛,適用于特殊應(yīng)用捆姜。
- property元素可以配置數(shù)據(jù)源各類屬性,這里的autoCommit=false迎膜,則是要求數(shù)據(jù)源不自動(dòng)提交泥技。
- dataSource標(biāo)簽配置的是數(shù)據(jù)源的連接信息,type屬性提供數(shù)據(jù)庫(kù)的連接方式的配置磕仅,在mybatis中有幾種連接方式:
- UNPOOLED珊豹,非連接池?cái)?shù)據(jù)庫(kù)。
- POOLED榕订,連接池?cái)?shù)據(jù)庫(kù)
- JNDI店茶,JNDI數(shù)據(jù)源。
- 自定義數(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>
引入映射器的常用方法:
- 用文件路徑引入映射器
<mappers>
<mapper resource="com/learn/chapter3/mapper/roleMapper.xml"/>
</mappers>
- 用包名映入映射器
<mappers>
<package name="com.learn.chapter3.mapper"/>
</mappers>
- 用類注冊(cè)引入映射器
<mappers>
<mapper class="com.learn.chapter3.mapper.UserMapper"/>
<mapper class="com.learn.chapter3.mapper.RoleMapper"/>
</mappers>
- 用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ù)雜的元素孽亲。可以自定義參數(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