Mybatis配置文件如何進行配置呢?
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-1RAhWZql-1609136973478)(https://imgkr.cn-bj.ufileos.com/768074eb-5e03-4ad1-81ee-5432b6614e4a.jpg)]
Mybatis配置文件配置的方式
- properties
- settings
- typeAliases
- typeHandlers
- objectFactory
- plugins
- environments
- transactionManager
- dataSource
- mappers
案例實操
1. properties
這些屬性都是可外部配置且可動態(tài)替換的,既可以在典型的 Java 屬性文件中配置,亦可通過 properties 元素的子元素來傳遞。例如:
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis" />
<property name="username" value="root" />
<property name="password" value="root" />
其中的屬性就可以在整個配置文件中使用來替換需要動態(tài)配置的屬性值。比如:
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
如何配?
在config.xml 文件中<configuration>引入子標簽
<properties resource="jdbc.properties"></properties>
并修改原有數(shù)據(jù)源連接相關(guān)配置如下:
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments>
即可完成。
2. settings(了解)
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-lATdekkB-1609136973486)(https://imgkr.cn-bj.ufileos.com/d0372a13-d467-4f73-a99b-45dfa35973b2.png)]
這是MyBatis 修改操作運行過程細節(jié)的重要的步驟。下方這個表格描述了這些設(shè)置項、含義和默認值。一般我們用默認即可(詳細解釋見官網(wǎng)文檔)
對應(yīng)xml配置如下(開發(fā)中一般采用默認配置即可):
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="multipleResultSetsEnabled" value="true"/>
<setting name="useColumnLabel" value="true"/>
<setting name="useGeneratedKeys" value="false"/>
<setting name="autoMappingBehavior" value="PARTIAL"/>
<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
<setting name="defaultExecutorType" value="SIMPLE"/>
<setting name="defaultStatementTimeout" value="25"/>
<setting name="defaultFetchSize" value="100"/>
<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>
3.typeAliases
類型別名是為 Java 類型設(shè)置一個短的名字。它只和 XML 配置有關(guān),存在的意義僅在于用來減少類完全限定名的冗余。例如:
Configuration 標簽下添加
<typeAliases>
<typeAlias alias="customer" type="com.xxx.pojo.Customer" />
</typeAliases>
修改CustomerMapper.xml 文件
<!-- 查詢客戶-->
<select id="queryCustomerById" parameterType="int" resultType="customer">
SELECT id,user_name 'userName' FROM yg_customer WHERE id=#{id}
</select>
也可以指定一個包名(大家最喜歡的方式),MyBatis 會在包名下面搜索需要的 Java Bean,比如:
<typeAliases>
<!-- <typeAlias alias="customer" type="com.xxx.pojo" /> -->
<package name="com.xxx.pojo"/>
</typeAliases>
每一個在包com.xxx.pojo 中的 Java Bean,在沒有注解的情況下,會使用 Bean 的首字母小寫的非限定類名來作為它的別名。 比如com.xxx.pojo.Customer 的別名為customer ;
若有注解,則別名為其注解值。 注解名@Alias(value=“user”)
同樣mybatis已經(jīng)為我們構(gòu)建了相應(yīng)的類型別名,它們都是大小寫不敏感的,需要注意的是由基本類型名稱重復(fù)導(dǎo)致的特殊處理。
| 別名 | 映射的類型 |
|---|---|
| _byte | Byte |
| _long | Long |
| _short | Short |
| _int | Int |
| _integer | Int |
| _double | Double |
| _float | Float |
| _boolean | Boolean |
| string | String |
| byte | Byte |
| long | Long |
| short | Short |
| int | Integer |
| integer | Integer |
| double | Double |
| float | Float |
| boolean | Boolean |
| date | Date |
| decimal | BigDecimal |
| bigdecimal | BigDecimal |
| object | Object |
| map | Map |
| hashmap | HashMap |
| list | List |
| arraylist | ArrayList |
| collection | Collection |
| iterator | Iterator |
4.typeHandlers 類型處理器(面試有可能會問)
無論是 MyBatis 在預(yù)處理語句(PreparedStatement)中設(shè)置一個參數(shù)時,還是從結(jié)果集中取出一個值時, 都會用類型處理器將獲取的值以合適的方式轉(zhuǎn)換成 Java 類型。下表描述了一些默認的類型處理器。
| BooleanTypeHandler | java.lang.Boolean, boolean | 數(shù)據(jù)庫兼容的 BOOLEAN |
|---|---|---|
| ByteTypeHandler | java.lang.Byte, byte | 數(shù)據(jù)庫兼容的 NUMERIC 或 BYTE |
| ShortTypeHandler | java.lang.Short, short | 數(shù)據(jù)庫兼容的 NUMERIC 或 SHORT INTEGER |
| IntegerTypeHandler | java.lang.Integer, int | 數(shù)據(jù)庫兼容的 NUMERIC 或 INTEGER |
| LongTypeHandler | java.lang.Long, long | 數(shù)據(jù)庫兼容的 NUMERIC 或 LONG INTEGER |
| FloatTypeHandler | java.lang.Float, float | 數(shù)據(jù)庫兼容的 NUMERIC 或 FLOAT |
| DoubleTypeHandler | java.lang.Double, double | 數(shù)據(jù)庫兼容的 NUMERIC 或 DOUBLE |
| BigDecimalTypeHandler | java.math.BigDecimal | 數(shù)據(jù)庫兼容的 NUMERIC 或 DECIMAL |
| StringTypeHandler | java.lang.String | CHAR, VARCHAR |
| ClobReaderTypeHandler | java.io.Reader | - |
| ClobTypeHandler | java.lang.String | CLOB, LONGVARCHAR |
| NStringTypeHandler | java.lang.String | NVARCHAR, NCHAR |
| NClobTypeHandler | java.lang.String | NCLOB |
| BlobInputStreamTypeHandler | java.io.InputStream | - |
| ByteArrayTypeHandler | byte[] | 數(shù)據(jù)庫兼容的字節(jié)流類型 |
| BlobTypeHandler | byte[] | BLOB, LONGVARBINARY |
| DateTypeHandler | java.util.Date | TIMESTAMP |
| DateOnlyTypeHandler | java.util.Date | DATE |
| TimeOnlyTypeHandler | java.util.Date | TIME |
| SqlTimestampTypeHandler | java.sql.Timestamp | TIMESTAMP |
| SqlDateTypeHandler | java.sql.Date | DATE |
| SqlTimeTypeHandler | java.sql.Time | TIME |
| ObjectTypeHandler | Any | OTHER 或未指定類型 |
| EnumTypeHandler | Enumeration Type | VARCHAR-任何兼容的字符串類型,存儲枚舉的名稱(而不是索引) |
| EnumOrdinalTypeHandler | Enumeration Type | 任何兼容的 NUMERIC 或 DOUBLE 類型,存儲枚舉的索引(而不是名稱)。 |
你可以重寫類型處理器或創(chuàng)建你自己的類型處理器來處理不支持的或非標準的類型。 具體做法為:實現(xiàn) org.apache.ibatis.type.TypeHandler 接口, 或繼承一個很便利的類 org.apache.ibatis.type.BaseTypeHandler, 然后可以選擇性地將它映射到一個 JDBC 類型。
5. 對象工廠(objectFactory)(了解)
MyBatis 每次創(chuàng)建結(jié)果對象的新實例時,它都會使用一個對象工廠(ObjectFactory)實例來完成。默認的對象工廠需要做的僅僅是實例化目標類,要么通過默認構(gòu)造方法,要么在參數(shù)映射存在的時候通過參數(shù)構(gòu)造方法來實例化。默認情況下,我們不需要配置,mybatis會調(diào)用默認實現(xiàn)的objectFactory。從這個類的外部看,這個類的主要作用就是根據(jù)一個類的類型得到該類的一個實體對象,比如,我們給他一個User的type,他將會給我們一個Tiger的實體對象,我們給他一個java.lang.List對象,他將會給我們一個List的實體對象。類似于spring 工廠實例化bean
6. plugins 插件
MyBatis 允許你在已映射語句執(zhí)行過程中的某一點進行攔截調(diào)用。默認情況下,MyBatis 允許使用插件來攔截的方法調(diào)用包括:
· Executor (sql執(zhí)行時, update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
· ParameterHandler (參數(shù)的處理, getParameterObject, setParameters)
· ResultSetHandler (結(jié)果集的處理, handleResultSets, handleOutputParameters)
· StatementHandler (申明語句的處理, prepare, parameterize, batch, update, query)
這些類中方法的細節(jié)可以通過查看每個方法的簽名來發(fā)現(xiàn),或者直接查看 MyBatis 的發(fā)行包中的源代碼。 假設(shè)你想做的不僅僅是監(jiān)控方法的調(diào)用,那么你應(yīng)該很好的了解正在重寫的方法的行為。 因為如果在試圖修改或重寫已有方法的行為的時候,你很可能在破壞 MyBatis 的核心模塊。 這些都是更低層的類和方法,所以使用插件的時候要特別當(dāng)心。
通過 MyBatis 提供的強大機制,使用插件是非常簡單的,只需實現(xiàn) Interceptor 接口,并指定了想要攔截的方法簽名即可。
總配置添加
<!-- 插件 -->
<plugins>
<plugin interceptor="com.xxx.plugins.ExamplePlugin">
<property name="someProperty" value="100" />
</plugin>
</plugins>
插件demo:
@Intercepts({
@Signature(
type=Executor.class,
/**
* 攔截所有方法
*/
method="query",
/**
* 參數(shù)定義
*/
args={MappedStatement.class,Object.class,RowBounds.class,ResultHandler.class} )
})
public class ExamplePlugin implements Interceptor {
/**
* 每個插件必須實現(xiàn)以下三個方法
*/
/**
* Object intercept(Invocation invocation)是實現(xiàn)攔截邏輯的地方,
* 內(nèi)部要通過invocation.proceed()顯式地推進責(zé)任鏈前進,也就是調(diào)用下一個攔截器攔截目標方法。
*/
public Object intercept(Invocation invocation) throws Throwable { System.out.println("intercept");
return invocation.proceed();
}
/**
* Object plugin(Object target) 就是用當(dāng)前這個攔截器生成對目標target的代理,
* 實際是通過Plugin.wrap(target,this) 來完成的,把目標target和攔截器this傳給了包裝函數(shù)。
*/
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
/**
* setProperties(Properties properties)用于設(shè)置額外的參數(shù),參數(shù)配置在攔截器的Properties節(jié)點里。
*/
public void setProperties(Properties properties) { System.out.println(properties.get("hello"));
}
}
7. 配置環(huán)境(environments)(熟悉 配多個數(shù)據(jù)源)
MyBatis 可以配置成適應(yīng)多種環(huán)境,這種機制有助于將 SQL 映射應(yīng)用于多種數(shù)據(jù)庫之中, 現(xiàn)實情況下有多種理由需要這么做。例如,開發(fā)、測試和生產(chǎn)環(huán)境需要有不同的配置;或者共享相同 Schema 的多個生產(chǎn)數(shù)據(jù)庫, 想使用相同的 SQL 映射。許多類似的用例。
不過要記?。罕M管可以配置多個環(huán)境,每個 SqlSessionFactory 實例只能選擇其一。
所以,如果你想連接兩個數(shù)據(jù)庫,就需要創(chuàng)建兩個 SqlSessionFactory 實例,每個數(shù)據(jù)庫對應(yīng)一個。而如果是三個數(shù)據(jù)庫,就需要三個實例,依此類推,記起來很簡單:
· 每個數(shù)據(jù)庫對應(yīng)一個 SqlSessionFactory 實例
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
<environment id="test">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${driver2}" />
<property name="url" value="${url2}" />
<property name="username" value="${username2}" />
<property name="password" value="${password2}" />
</dataSource>
</environment>
</environments>
## development
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/mybatis?useUnicode=true&characterEncoding=utf8
username=root
password=root
## test
driver2=com.mysql.jdbc.Driver
url2=jdbc:mysql://127.0.0.1:3306/mybatis2?useUnicode=true&characterEncoding=utf8
username2=root
password2=root
測試sqlSessionFactory
public void test02() {
InputStream in;
try {
in = Resources.getResourceAsStream(this.getClass().getClassLoader()
, "config.xml");
// 默認開發(fā)庫
//SqlSessionFactory sqlSessionFactory= new SqlSessionFactoryBuilder().build(in); // 測試庫
SqlSessionFactory sqlSessionFactory= new SqlSessionFactoryBuilder().build(in,"test");
UserDao userDao=new UserDaoImpl(sqlSessionFactory);
User user= userDao.queryUserById(1);
System.out.println(user);
} catch (IOException e) {
e.printStackTrace();
}
}
8. 事務(wù)管理器(transactionManager)(了解)
在 MyBatis 中有兩種類型的事務(wù)管理器(也就type=”[JDBC|MANAGED]”):
JDBC – 這個配置就是直接使用了 JDBC 的提交和回滾設(shè)置,它依賴于從數(shù)據(jù)源得到的連接來管理事務(wù)范圍。
MANAGED – 這個配置幾乎沒做什么。它從來不提交或回滾一個連接,而是讓容器來管理事務(wù)的整個生命周期。 默認情況下它會關(guān)閉連接,然而一些容器并不希望這樣,因此需要將 closeConnection 屬性設(shè)置為 false 來阻止它默認的關(guān)閉行為。例如:
<transactionManager type="MANAGED">
<property name="closeConnection" value="false"/>
</transactionManager>
如果你正在使用 Spring + MyBatis,則沒有必要配置事務(wù)管理器, 因為 Spring 模塊會使用自帶的管理器來覆蓋前面的配置。(集成時會講到)
9.dataSource 數(shù)據(jù)源(了解)
dataSource 元素使用標準的 JDBC 數(shù)據(jù)源接口來配置 JDBC 連接對象的資源。
數(shù)據(jù)源類型有三種:UNPOOLED,POOLED,JNDI
UNPOOLED
這個數(shù)據(jù)源的實現(xiàn)只是每次被請求時打開和關(guān)閉連接。雖然有一點慢,它對在及時可用連接方面沒有性能要求的簡單應(yīng)用程序是一個很好的選擇。 不同的數(shù)據(jù)庫在這方面表現(xiàn)也是不一樣的,所以對某些數(shù)據(jù)庫來說使用連接池并不重要,這個配置也是理想的。
- driver – 這是 JDBC 驅(qū)動的 Java 類的完全限定名(并不是JDBC驅(qū)動中可能包含的數(shù)據(jù)源類)。
- url – 這是數(shù)據(jù)庫的 JDBC URL 地址。
- username – 登錄數(shù)據(jù)庫的用戶名。
- password – 登錄數(shù)據(jù)庫的密碼。
- defaultTransactionIsolationLevel – 默認的連接事務(wù)隔離級別。
作為可選項,你也可以傳遞屬性給數(shù)據(jù)庫驅(qū)動。要這樣做,屬性的前綴為“driver.”,例如:
- driver.encoding=UTF8
這將通過DriverManager.getConnection(url,driverProperties)方法傳遞值為 UTF8 的 encoding 屬性給數(shù)據(jù)庫驅(qū)動。
POOLED
? 這種數(shù)據(jù)源的實現(xiàn)利用“池”的概念將 JDBC 連接對象組織起來,避免了創(chuàng)建新的連接實例時所必需的初始化和認證時間。 這是一種使得并發(fā) Web 應(yīng)用快速響應(yīng)請求的流行處理方式。(一般選用這種)
poolMaximumActiveConnections – 在任意時間可以存在的活動(也就是正在使用)連接數(shù)量,默認值:10
poolMaximumIdleConnections – 任意時間可能存在的空閑連接數(shù)。
poolMaximumCheckoutTime – 在被強制返回之前,池中連接被檢出(checked out)時間,默認值:20000 毫秒(即 20 秒)
poolTimeToWait – 這是一個底層設(shè)置,如果獲取連接花費的相當(dāng)長的時間,它會給連接池打印狀態(tài)日志并重新嘗試獲取一個連接(避免在誤配置的情況下一直安靜的失?。J值:20000 毫秒(即 20 秒)。
poolPingQuery – 發(fā)送到數(shù)據(jù)庫的偵測查詢,用來檢驗連接是否處在正常工作秩序中并準備接受請求。默認是“NO PING QUERY SET”,這會導(dǎo)致多數(shù)數(shù)據(jù)庫驅(qū)動失敗時帶有一個恰當(dāng)?shù)腻e誤消息。
poolPingEnabled – 是否啟用偵測查詢。若開啟,也必須使用一個可執(zhí)行的 SQL 語句設(shè)置 poolPingQuery 屬性(最好是一個非??斓?SQL),默認值:false。
poolPingConnectionsNotUsedFor – 配置 poolPingQuery 的使用頻度。這可以被設(shè)置成匹配具體的數(shù)據(jù)庫連接超時時間,來避免不必要的偵測,默認值:0(即所有連接每一時刻都被偵測 — 當(dāng)然僅當(dāng) poolPingEnabled 為 true 時適用)。
JNDI
? 這個數(shù)據(jù)源的實現(xiàn)是為了能在如 EJB 或應(yīng)用服務(wù)器這類容器中使用,容器可以集中或在外部配置數(shù)據(jù)源,然后放置一個 JNDI 上下文的引用。
- initial_context – 這個屬性用來在 InitialContext 中尋找上下文(即initialContext.lookup(initial_context))。這是個可選屬性,如果忽略,那么 data_source 屬性將會直接從 InitialContext 中尋找。
- data_source – 這是引用數(shù)據(jù)源實例位置的上下文的路徑。提供了 initial_context 配置時會在其返回的上下文中進行查找,沒有提供時則直接在 InitialContext 中查找。和其他數(shù)據(jù)源配置類似,可以通過添加前綴“env.”直接把屬性傳遞給初始上下文。比如:
- env.encoding=UTF8
這就會在初始上下文(InitialContext)實例化時往它的構(gòu)造方法傳遞值為 UTF8 的 encoding 屬性。
10.mappers 映射器(四種配置)(熟悉)
這里是告訴mybatis去哪尋找映射SQL 的語句??梢允褂妙惵窂街械馁Y源引用,或者使用字符,輸入確切的URL 引用。
!— sqlmapper配置文件路徑 -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!—url絕對路徑形式-->
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
<mapper url="file:///var/mappers/BlogMapper.xml"/>
<mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
<!—接口 列表配置形式 注解sql-->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
<!—映射包下所有接口-->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
這些配置會告訴了 MyBatis 去哪里找映射文件,剩下的細節(jié)就應(yīng)該是每個 SQL 映射文件。
擴展
封裝Dao
1新建接口CustomerDao
接口定義:
public interface CustomerDao {
Customer queryCustomerByName(String userName);
}
2 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.xxx.dao.CustomerDao">
<!-- 查詢客戶-->
<select id="queryCustomerByName" parameterType="string" resultType="com.xxx.pojo.Customer">
SELECT id,user_name 'userName',user_balance 'userBalance' FROM yg_customer WHERE user_name=#{userName}
</select>
</mapper>
3 mappers映射器配置
<mappers>
<!-- <mapper resource="com/xxx/mapper/CustomerDao.xml" />-->
<package name="com.xxx.dao"/>
</mappers>
4 測試
public class App
{
public static void main( String[] args ) throws IOException {
//1 加載配置文件
InputStream is = Resources.getResourceAsStream("mybatis.xml");
//2 創(chuàng)建sqlsessionfactor工廠
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
//3 構(gòu)建數(shù)據(jù)庫會話
SqlSession session = factory.openSession();
/* Customer customer = session.selectOne("com.xxx.mapper.customerMapper.queryCustomerById", 2);
System.out.println(customer);*/
CustomerDao customerDao = session.getMapper(CustomerDao.class);
Customer customer = customerDao.queryCustomerByName("zhaoliying");
System.out.println(customer);
session.close();
}
}
onFactory factory = new SqlSessionFactoryBuilder().build(is);
//3 構(gòu)建數(shù)據(jù)庫會話
SqlSession session = factory.openSession();
/* Customer customer = session.selectOne(“com.xxx.mapper.customerMapper.queryCustomerById”, 2);
System.out.println(customer);*/
CustomerDao customerDao = session.getMapper(CustomerDao.class);
Customer customer = customerDao.queryCustomerByName(“zhaoliying”);
System.out.println(customer);
session.close();
}
}