項目路徑:https://share.weiyun.com/5oetQPG
MyBatis配置項的順序不能顛倒,如果顛倒了它們的順序,則啓動階段就會發生異常,導致程序無法運行。
使用property子元素:
這樣定義一次就可以到處引用了,如${database.username},但要定義的參數太多,則使用properties文件。
使用properties文件:
定義jdbc.properties文件
使用properties的屬性resource來引入properties文件:
解密用戶名和密碼後創建SqlSessionFactory
滿足運維人員對用戶名和密碼,保密的需求。
配置的優先級:程序傳遞方式 > properties文件的方式 > 使用property子元素的方式。
settings設置:
是MyBatis中最複雜的配置,能深刻影響MyBatis底層的運行,經常修改的一些規則:
自動映射、駝峯命名映射、級聯規則、是否啓動緩存、執行器類型。
配置是否啓動緩存:
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
typeAliases別名:
系統定義別名:
在MyBatis中別名由類TypeAliasRegistry去定義。
一般對基本類型int定義的別名爲,_int;類或包裝器類定義的別名爲,String爲string、List爲list、Long爲long。
通過Configuration獲取TypeAliasRegistry類對象
其中的,registerAlias方法去註冊別名;getTypeAliasRegistry方法獲取別名。
自定義別名:
可以支持掃描別名,自動將類名的第一個字母變爲小寫,作爲別名。
若出現衝突,則使用註解進行區分:
typeHandler類型轉換器:
在JDBC中,需要在PreparedStatement對象中設置那些,已經預編譯過的SQL語句的參數。
執行SQL後,通過ResultSet對象,獲取得到數據庫的數據。
在typeHandler中,分爲jdbcType和javaType,typeHandler的作用使其兩個類型相互轉換。
系統定義的typeHandler:
一般無須顯式聲明jdbcType和javaType,MyBatis會自己探測。
但一般枚舉類需要自己去編寫規則。
在MyBatis中typeHandler都要實現接口:org.apahe.ibatis.type.TypeHandler
系統註冊typeHandler:
一般自定義的typeHanlder不用代碼註冊,而是通過配置或掃描。
自定義typeHandler:
在xml中配置typeHandler:
啓用typeHandler的方式:
要麼指定了與typeHandler一致的jdbcType和javaType,要麼直接指定typeHandler具體實現類。
若一些數據從數據返回爲空,則採用指定與typeHandler一致的jdbcType和javaType的方法,避免系統不知採用哪個typeHandler處理,從而產生異常。
若typeHandler採用包掃描,則無法指定具體的jdbcType和javaType,可使用註解的方式配置:
枚舉typeHandler:
絕大多數情況下,typeHandler因爲枚舉而使用。
MyBatis已經定義了兩個類來支持,枚舉類型,但一般作用不大:
EnumOrdinalTypeHandler是根據,枚舉數組小標索引的方式,進行匹配的。
它要求數據庫返回一個整數(可以是以varchar作爲類型的整數)作爲其下標,根據下標找到對應的枚舉類型。
EnumTypeHandler會把使用的名稱轉化爲對應的枚舉。
如,數據庫返回的字符串“MALE”,進行Enum.valueOf(SexEnum.class,"MALE");轉換。
但是使用是上述兩種方式,會帶來很大的侷限性,一般自定義枚舉typeHandler。
文件操作:
若數據庫數據類型爲blog,java數據類型爲byte[],則使用BlogTypeHandler。
在現實中,一次性地將大量數據加載到JVM中,會給服務器帶來很大壓力。
因此,一般使用文件流的形式,所以,
數據庫數據類型爲blog,java數據類型爲InputStream,則使用BlogInputStreamTypeHandler
因爲性能不佳,大型互聯網的網站會採用文件服務器的形式。
ObjectFactory(對象工廠):
創建結果集時,會使用一個對象工廠來完成創建這個結果集實例。
一般情況,MyBatis會使用其定義的對象工廠——DefaultObjectFactory。
若要自定義對象工廠,則繼承DefaultObjectFactory:
public class MyObjectFactory extends DefaultObjectFactory {
Logger log = Logger.getLogger(MyObjectFactory.class);
private Object temp = null;
@Override
public void setProperties(Properties properties) {
super.setProperties(properties);
log.info("初始化參數:【" + properties.toString() + "】");
}
//方法二
@Override
public <T> T create(Class<T> type) {
T result = super.create(type);
log.info("創建對象:" + result.toString());
log.info("是否和上次創建的是同一個對象:【" + (temp == result) + "】");
return result;
}
//方法一
@Override
public <T> T create(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
T result = super.create(type, constructorArgTypes, constructorArgs);
log.info("創建對象:" + result.toString());
temp = result;
return result;
}
@Override
public <T> boolean isCollection(Class<T> type) {
return super.isCollection(type);
}
}
最後在配置文件對對象工廠進行配置:
運行結果是,先調用方法一,後調用方法二。
插件:
插件是MyBatis中最強大和靈活的組件,同時也是最複雜、最難以使用的組件,而且它十分危險。
應用它之前,一定要掌握底層的構成和運行原理。
environment(運行環境):
主要的作用是,配置數據庫信息,可配置多個數據庫。
下面又分爲兩個可配置的元素:事務管理器、數據源。
實際工作中,會採用Spring對數據源和數據庫的事務進行管理。
transactionManager(事務管理器):
transactionManager提供了兩個實現類,需要實現接口Transaction(提交、回滾、關閉等數據庫事務方法)
因此也對應兩個相應的工廠類,需實現TransactionFactory接口。
於是可把事務管理器配置成如下方式:
JDBC:以JDBC的方式對數據庫的提交和回滾進行操作。
MANAGED:把事務交給容器處理,可對closeConnection屬性設置爲false,來阻止它默認關閉。
自定義事務工廠:需實現TransactionFactory接口
自定義了事務工廠,還需通過實現Transaction接口,自定義事務類,就能夠通過自定義事務規則,滿足需要。
environment數據源環境:
存在三個數據源工廠:
PooledDataSourceFactory、UnpooledDataSourceFactory、JndiDataSourceFactory。
JndiDataSourceFactory會根據JNDI的信息,拿到外部容器實現的數據庫連接對象。
三個數據源工廠,最後生成的產品都會是一個實現了DataSource接口的數據庫連接對象。
UNPOOLED:採用非數據庫池的管理方式,每次請求都會打開一個新的數據庫連接,所以創建比較慢。傳遞屬性給數據庫驅動是個可選項,且屬性的前綴爲“driver”。
POOLED:利用“池”的概念將JDBC的Connection對象組織起來,省去了創建新的連接實例時的初始化和認證時間。
JNDI:爲了能在如EJB或應用服務器這類容器中使用,容器可以集中或在外部配置數據源,然後放置一個JNDI上下文的引用。
該數據源有兩個屬性可配置:
initial_context:用來在InitialContext中尋找上下文,如initialContext.lookup(initial_context)。
data_source:引用數據源實例位置上下文的路徑。
可通過添加前綴“env.”直接把屬性傳遞給初始化上下文InitialContext。
MyBatis也支持第三方數據源,例如使用DBCP數據源,則需提供一個自定義DataSourceFactory:
在配置文件中,進行相應的配置:
databaseIdProvider數據庫廠商標識:
使用系統默認的databaseIdProvider:
name是數據庫名稱,可通過connection.getMetaData().getDatabaseProductName()獲取。
value是一個別名,可在mapper文件中,標識一條SQL語句適用於哪種數據庫。
當databaseIdProvider屬性被配置時,系統會優先取到和數據庫配置一致的SQL,若沒有databaseId的SQL,則把它當作默認值。如果還是取不到,則會拋出異常。
不使用系統規則:
自定義DatabaseIdProvider:
public class MyDatabaseIdProvider implements DatabaseIdProvider {
private static final String DATEBASE_TYPE_DB2 = "DB2";
private static final String DATEBASE_TYPE_MYSQL = "MySQL";
private static final String DATEBASE_TYPE_ORACLE = "Oralce";
private Logger log = Logger.getLogger(MyDatabaseIdProvider.class);
@Override
public void setProperties(Properties props) {
log.info(props);
}
@Override
public String getDatabaseId(DataSource dataSource) throws SQLException {
Connection connection = dataSource.getConnection();
String dbProductName = connection.getMetaData().getDatabaseProductName();
if (MyDatabaseIdProvider.DATEBASE_TYPE_DB2.equals(dbProductName)) {
return "db2";
} else if (MyDatabaseIdProvider.DATEBASE_TYPE_MYSQL
.equals(dbProductName)) {
return "mysql";
} else if (MyDatabaseIdProvider.DATEBASE_TYPE_ORACLE
.equals(dbProductName)) {
return "oracle";
} else {
return null;
}
}
}
setProperties方法可以讀取配置的參數;getDatabaseId方法的返回值,返回去配置相應的SQL語句。
引入映射器的方法:
用文件路徑引入:
用包名引入:
用類註冊引入: