MyBatis最關鍵的組成部分是SqlSessionFactory,咱們能夠從中獲取SqlSession, 並執行映射的SQL語句。
SqlSessionFactory對象能夠經過基於XML的配置信息或者JavaAPI建立。java
構建SqlSessionFactory最多見的方式是基於XML配置。myBatis的配置文件通常命名爲mybatis-config.xml,
下面的 mybatis-config.xml展現了一個典型的MyBatis配置文件的樣子:程序員
<?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="application.properties"> <property name="username" value="db_user" /> <property name="password" value="verysecurepwd" /> </properties> <settings> <setting name="cacheEnabled" value="true" /> </settings> <typeAliases> <typeAlias alias="Student" type="com.briup.pojo.Student" /> <package name="com.briup.pojo" /> </typeAliases> <typeHandlers> <typeHandler handler="com.mybatis3.typehandlers.PhoneTypeHandler" /> <package name="com.briup.typehandlers" /> </typeHandlers> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driverClassName}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </dataSource> </environment> <environment id="production"> <transactionManager type="MANAGED" /> <dataSource type="JNDI"> <property name="data_source" value="java:comp/jdbc/MyBatisDemoDS" /> </dataSource> </environment> </environments> <mappers> <mapper resource="com/briup/mappers/StudentMapper.xml" /> <mapper url="file:///D:/mybatisdemo/mappers/StudentMapper.xml" /> <mapper class="com.briup.mappers.StudentMapper" /> </mappers> </configuration>
environments是配置mybatis當前工做的數據庫環境的地方web
MyBatis支持配置多個dataSource環境,能夠將應用部署到不一樣的環境上,
好比:DEV(開發環境)、TEST(測試環境)、QA(質量評估環境)、UAT(用戶驗收環境)、PRODUCTION(生產環境),
不一樣的環境可能使用的數據庫環境不都同樣。這時候,咱們能夠經過將默認environments值(default屬性)設置成想要的environment的id值。sql
有時候,咱們可能須要在相同的應用下使用多個數據庫,
好比:咱們可能用一個shoppingcart數據庫來存儲全部的訂單明細,在使用一個reports數據庫存儲訂單明細的合計,用做報告。(也就是若是系統在運行期間若是有切換數據庫環境的需求,mybatis中也能夠很輕鬆的實現)。數據庫
若是你的應用須要鏈接多個數據庫,你須要將每一個數據庫配置成獨立的環境,而且爲每個數據庫建立一個SqlSessionFactory apache
例如,現有mybatis-config.xml文件中,配置有兩個數據庫信息,:編程
<environments default="shoppingcart"> <environment id="shoppingcart"> <transactionManager type="MANAGED" /> <dataSource type="JNDI"> <property name="data_source" value="java:comp/jdbc/ShoppingcartDS" /> </dataSource> </environment> <environment id="reports"> <transaction Managertype="MANAGED" /> <dataSource type="JNDI"> <property name="data_source" value="java:comp/jdbc/ReportsDS" /> </dataSource> </environment> </environments>
咱們能夠爲以上每一個環境建立一個SqlSessionFactory, java代碼:緩存
inputStream = Resources.getResourceAsStream("mybatis-config.xml"); //默認的環境 defaultSqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //統計明細的環境 cartSqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream, "shoppingcart"); //統計報表的環境 reportSqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream, "reports");
注意:對於environments,咱們能夠在其中配置多個environment子元素,同時還須要在environment中配置dataSource和transactionManager元素。服務器
dataSource表示的是數據源,至少會包括該鏈接數據庫的各類信息mybatis
<dataSource type="POOLED"> <property name="driver" value="${jdbc.driverClassName}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </dataSource>
dataSource的類型type屬性能夠配置成其內置類型之一,如:UNPOOLED,POOLED,JNDI。
UNPOOLED:MyBatis會爲每個數據庫操做建立一個新的鏈接,使用完了並關閉它,該方式適用於只有小規模數量併發用戶的簡單應用程序上。 POOLED:MyBatis會建立一個數據庫鏈接池,鏈接池中的一個鏈接將會被用做數據庫操做。一旦數據庫操做完成,MyBatis會將此鏈接返回給鏈接池。 JNDI(Java Naming and Directory Interface,Java命名和目錄接口,是SUN公司提供的一種標準的Java命名系統接口)MyBatis從在應用服務器向配置好的JNDI數據源dataSource獲取數據庫鏈接。
MyBatis支持兩種類型的事務管理器:JDBC 和 MANAGED.
JDBC事務管理器,是在【jdbc程序】負責管理數據庫鏈接的生命週期(提交、回退等等)的時候。若是將TransactionManager 屬性設置成JDBC,MyBatis內部將使用JdbcTransactionFactory類建立TransactionManager。
例如,部署到ApacheTomcat的應用程序,須要應用程序本身管理事務。由於ApacheTomcat不會幫咱們管理事務。
MANAGED 事務管理器,是在【應用服務器】負責管理數據庫鏈接生命週期的時候。若是將TransactionManager屬性設置成MANAGED時,MyBatis內部使用ManagedTransactionFactory 類建立事務管理器TransactionManager。
例如,當一個Java EE的應用程序部署在相似JBoss,WebLogic,GlassFish應用服務器上時,它們會使用 EJB 進行應用服務器的事務管理能力。在這些管理環境中,你可使用MANAGED事務管理器。
注:Managed 是託管的意思,即咱們編寫的應用程序自己不去管理事務,而是把事務管理交給應用所在的服務器進行管理。
簡單記憶:若是設置爲JDBC,則須要程序員本身設置事務提交,若是設置爲MANAGED,則會將事務提交委託給web容器,web容器會幫咱們事務提交。(不過這要看web容器是否支持,好比,Tomcat不能幫咱們手動提交,因此在使用Tomcat的時候,只能設置爲JDBC)
屬性配置元素properties能夠將配置值寫死到mybatis-config.xml中,
也能夠具體到一個屬性文件中,而且使用屬性文件的key名做爲佔位符。
在上述的配置中,咱們將數據庫鏈接屬性配置到了application.properties文件中,
而且爲driver,URL等屬性使用了佔位符.
在applications.properties文件中配置數據庫鏈接參數,以下所示:
jdbc.driverClassName=oracle.jdbc.driver.OracleDriver jdbc.url=jdbc:oracle:thin:@127.0.0.1:1521:XE jdbc.username=briup jdbc.password=briup
在mybatis-config.xml文件中,爲屬性使用application.properties文件中定義的佔位符:
<!-- 讀取application.properties文件中的數據key-value的形式 --> <properties resource="application.properties"> <!-- 注意:是applications.properties文件中的值優先級高 --> <property name="jdbc.username" value="briup" /> <property name="jdbc.password" value="briup" /> </properties> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driverClassName}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </dataSource> </environment> </environments>
在SQLMapper配置文件中,對於resultType和parameterType屬性值,咱們須要使用JavaBean 的徹底限定名。
例如:
<select id="findStudentById" parameterType="int" resultType="com.briup.pojo.Student"> SELECT STUD_ID AS ID, NAME, EMAIL, DOB FROM STUDENTS WHERE STUD_ID=#{Id} </select> <update id="updateStudent" parameterType="com.briup.pojo.Student"> UPDATE STUDENTS SET NAME=#{name}, EMAIL=#{email}, DOB=#{dob} WHERE STUD_ID=#{id} </update>
注:parameterType表示,未來調用這個sql語句的時候所傳的參數的類型,(參數值或者參數對象裏面的屬性值 用來替換sql語句中的佔位符)
resultType表示,未來調用這個sql語句的時候所返回的結果的類型(方便mybatis給咱們自動封裝結果集)
這裏咱們爲resultType和parameterType屬性值設置爲Student類型的徹底限定名:com.briup.com.Student
咱們能夠爲徹底限定名取一個別名(alias),而後就能夠在須要使用徹底限定名的地方使用別名,而不是處處使用徹底限定名。若是不取別名,會默認按類名去查找
以下例子所示,爲徹底限定名起一個別名:
<typeAliases> <typeAlias alias="Student" type="com.briup.pojo.Student" /> <typeAlias alias="Teacher" type="com.briup.pojo.Teacher" /> </typeAliases>
而後在SQLMapper映射文件中,,以下使用Student的別名:
<select id="findStudentById" parameterType="int" resultType="Student"> SELECT STUD_ID AS ID, NAME, EMAIL, DOB FROM STUDENTS WHERE STUD_ID=#{id} </select> <update id="updateStudent" parameterType="Student"> UPDATE STUDENTS SET NAME=#{name}, EMAIL=#{email}, DOB=#{dob} WHERE STUD_ID=#{id} </update>
咱們還能夠不用爲每個JavaBean單獨定義別名,能夠爲配置出須要取別名的類的所在的包(package),MyBatis會自動掃描包內定義的類,而後分別爲每一個類註冊一個小寫字母開頭的簡單類名形式的別名。
以下所示:
<typeAliases> <package name="com.briup.pojo" /> </typeAliases>
若是Student.java和 Teacher.java 定義在com.briup.pojo包中,
則 com.briup.pojo.Student的別名會被註冊爲student,而com.briup.pojo.Teacher別名將會被註冊爲teacher。
還有另一種方式爲JavaBeans起別名,使用註解 @Alias,
@Alias("stu") public class Student{ .... }
@Alias註解將會覆蓋配置文件中的<typeAliases>定義。
當MyBatis將一個Java對象做爲輸入參數執行INSERT語句操做時,它會建立一個PreparedStatement對象,而且使用setXXX()方法對佔位符設置相應的參數值 。這裏,XXX能夠是Int,String,Date 等 Java對象屬性類型的任意一個。
示例以下:
<insert id="insertStudent" parameterType="Student"> INSERT INTO STUDENTS(STUD_ID,NAME,EMAIL,DOB) VALUES(#{stud Id},#{name},#{email},#{dob}) </insert>
爲執行這個語句,MyBatis將採起如下一系列動做:
1)建立一個有佔位符的PreparedStatement接口,以下:
PreparedStatement ps = connection.prepareStatement ("INSERT INTO STUDENTS(STUD_ID,NAME,EMAIL,DOB) VALUES(?,?,?,?)");
2)檢查Student對象的屬性studId的類型,而後使用合適的setXXX方法去設置參數值。
這裏studId是integer類型,因此會使用setInt()方法:
ps.setInt(1,student.getStudId());
相似地,對於name和email屬性都是String類型MyBatis使用setString()方法設置參數。
至於dob屬性,MyBatis會使用setDate()方法設置dob處佔位符位置的值。
MyBaits會將java.util.Date類型轉換爲java.sql.Timestamp並設值:
ps.setTimestamp(4, new Timestamp((student.getDob()).getTime()));
但MyBatis是怎麼知道對於Integer類型屬性使用setInt()和String類型屬性使用setString()方法呢?
其實MyBatis是經過使用類型處理器typeHandlers來決定這麼作的。
MyBatis對於如下的類型使用內建的類型處理器:
全部的 基本數據類型、基本類型的包裝類型、 byte[]、java.util.Date、java.sql.Date、java,sql.Time、java.sql.Timestamp、java枚舉類型等。
因此當MyBatis發現屬性的類型屬於上述類型,他會使用對應的類型處理器將值設置到PreparedStatement中,
一樣地,當SQL結果集封裝成java類對象的時候,也有相似的過程。
那若是有一個自定義的類型,怎麼存儲存儲到數據庫呢?
示例以下:
假設表STUDENTS 有一個 PHONE 字段,類型爲 VARCHAR2(15),而 Student類有一個自定義類型屬性
java代碼:PhoneNumber 類定義類型的 phoneNumber 屬性。
public class PhoneNumber{ private String countryCode; private String stateCode; private String number; public PhoneNumber(){} public PhoneNumber(String countryCode, String stateCode, String number) { this.countryCode = countryCode; this.stateCode = stateCode; this.number = number; } public PhoneNumber(String str){ if(str!=null){ String[] args = str.split("-"); this.countryCode = args[0]; this.stateCode = args[1]; this.number = args[2]; } } public String getAsString() { return countryCode + "-" + stateCode + "-" + number; } // Setters and getters ... } //Student類中引入PhoneNumber對象 public class Student{ private Integer id; private String name; private String email; private PhoneNumber phone; // Setters and getters ... }
StudentMapper.xml配置:
<insert id="insertStudent" parameterType="Student"> insert into students(name,email,phone) values(#{name},#{email},#{phone}) </insert>
這裏,參數對象中的屬性phone的值須要傳遞給#{phone};參數對象的屬性phone是 PhoneNumber類型。
此時,MyBatis 並不知道該怎樣來處理這個類型的對象。爲了讓MyBatis明白怎樣處理這個自定義的Java對象類型,如PhoneNumber,咱們能夠建立一個自定義的類型處理器。
MyBatis提供了抽象類BaseTypeHandler<T> ,咱們能夠繼承此類建立自定義類型處理器。
代碼以下所示:
public class PhoneTypeHandler extends BaseTypeHandler<PhoneNumber>{ //遇到PhoneNumber參數的時候應該如何在ps中設置值 @Override public void setNonNullParameter(PreparedStatement ps, int i, PhoneNumber parameter, JdbcType jdbcType) throws SQLException { ps.setString(i, parameter.getAsString()); } //查詢中遇到PhoneNumber類型的應該如何封裝(使用列名封裝) @Override public PhoneNumber getNullableResult(ResultSet rs, String columnName) throws SQLException { return new PhoneNumber(rs.getString(columnName)); } //查詢中遇到PhoneNumber類型的應該如何封裝(使用列的下標) @Override public PhoneNumber getNullableResult(ResultSet rs, int columnIndex) throws SQLException { return new PhoneNumber(rs.getString(columnIndex)); } //CallableStatement使用中遇到了PhoneNumber類型的應該如何封裝 @Override public PhoneNumber getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { return new PhoneNumber(cs.getString(columnIndex)); } }
注意:使用ps.setString()和rs.getString()方法是由於在數據庫的表中,phone列是VARCHAR類型。
最後,一旦咱們實現了自定義的類型處理器,咱們須要在mybatis-config.xml中註冊它:
<?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> <typeHandlers> <typeHandler handler="com.briup.typehandlers.PhoneTypeHandler" /> </typeHandlers> </configuration>
註冊PhoneTypeHandler後,MyBatis就可以將Phone類型的對象值存儲到VARCHAR類型的列上。
注意:大多數狀況下,【這些參數使用它們的默認值便可】
爲知足應用特定的需求,MyBatis默認的全局參數設置能夠被覆蓋掉,以下所示:
<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="defaultExecutorType" value="SIMPLE" /> <setting name="defaultStatementTimeout" value="25000" /> <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,hash Code ,to String"/> <setting name="proxyFactory" value="JAVASSIST" /> <setting name="aggressiveLazyLoading" value="true" /> <setting name="logImpl" value="LOG4J " /> <setting name="logPrefix" value="LOG4J " /> <setting name="callSettersOnNulls" value="false " /> </settings>
<settings> <!-- 這個配置使全局的映射器啓用或禁用緩存 --> <setting name="cacheEnabled" value="true" /> <!-- 全局啓用或禁用延遲加載。當禁用時,全部關聯對象都會即時加載 --> <setting name="lazyLoadingEnabled" value="true" /> <!-- 容許或不容許多種結果集從一個單獨的語句中返回(須要適合的驅動) --> <setting name="multipleResultSetsEnabled" value="true" /> <!-- 使用列標籤代替列名。不一樣的驅動在這方便表現不一樣。參考驅動文檔或充分測試兩種方法來決定所使用的驅動 --> <setting name="useColumnLabel" value="true" /> <!-- 容許JDBC支持生成的鍵。須要適合的驅動。 --> <setting name="useGeneratedKeys" value="false" /> <!-- 指定MyBatis如何自動映射列到字段/屬性。PARTIAL只會自動映射簡單、沒有嵌套的結果。FULL會自動映射任意複雜的結果(嵌套的或其餘狀況) --> <setting name="autoMappingBehavior" value="PARTIAL" /> <!-- 配置默認的執行器。SIMPLE執行器沒有什麼特別之處。REUSE執行器重用預處理語句。BATCH執行器重用語句和批量更新 --> <setting name="defaultExecutorType" value="SIMPLE" /> <!-- 設置超時時間,它決定驅動等待一個數據庫響應的時間 --> <setting name="defaultStatementTimeout" value="25000" /> <!-- 容許在嵌套語句中使用分頁(RowBounds)默認false --> <setting name="safeRowBoundsEnabled" value="false" /> <!-- 是否開啓自動駝峯命名規則(camel case)映射,即從經典數據庫列名 A_COLUMN 到經典 Java 屬性名 aColumn 的相似映射。默認false --> <setting name="mapUnderscoreToCamelCase" value="false" /> <!-- MyBatis 利用本地緩存機制(Local Cache)防止循環引用(circular references)和加速重複嵌套查詢。 默認值爲 SESSION,這種狀況下會緩存一個會話中執行的全部查詢。 若設置值爲 STATEMENT,本地會話僅用在語句執行上,對相同 SqlSession 的不一樣調用將不會共享數據。 --> <setting name="localCacheScope" value="SESSION" /> <!-- 當沒有爲參數提供特定的 JDBC 類型時,爲空值指定 JDBC 類型。 某些驅動須要指定列的 JDBC 類型,多數狀況直接用通常類型便可,好比 NULL、VARCHAR 或 OTHER。 --> <setting name="jdbcTypeForNull" value="OTHER" /> <!-- 指定對象的哪一個方法觸發一次延遲加載。 --> <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode ,toString" /> <!-- CGLIB | JAVASSIST 默認JAVASSIST(MyBatis 3.3 or above) --> <!-- 指定 Mybatis 建立具備延遲加載能力的對象所用到的代理工具。 --> <setting name="proxyFactory" value="JAVASSIST" /> <!-- 當啓用時,對任意延遲屬性的調用會使帶有延遲加載屬性的對象完整加載;反之,每種屬性將會按需加載。 --> <setting name="aggressiveLazyLoading" value="true" /> <!-- 指定 MyBatis 所用日誌的具體實現,未指定時將自動查找。 --> <setting name="logImpl" value="LOG4J " /> <!-- 指定 MyBatis 增長到日誌名稱的前綴。值能夠是任意字符串 --> <setting name="logPrefix" value="LOG4J " /> <!-- 指定當結果集中值爲 null 的時候是否調用映射對象的 setter(map 對象時爲 put)方法,這對於有 Map.keySet() 依賴或 null 值初始化的時候是有用的。注意基本類型(int、boolean等)是不能設置成 null 的。 默認false--> <setting name="callSettersOnNulls" value="false " /> </settings>
SQLMapper文件中主要是對SQL語句的映射,代表這個sql語句對應哪一個方法的調用。
咱們須要在mybatis-config.xml文件中配置SQLMapper文件的位置。
<mappers> <mapper resource="com/briup/mappers/StudentMapper.xml" /> <mapper url="file:///D:/mybatisdemo/app/mappers/StudentMapper.xml" /> <mapper class="com.briup.mappers.StudentMapper" /> <package name="com.briup.mappers" /> </mappers>
以上每個<mapper> 標籤均可以從不一樣類型的資源中加載映射mapper:
resource屬性:用來指定在classpath中的mapper文件。 url屬性:用來經過徹底文件系統路徑或者web URL地址來指向mapper文件 class屬性:用來指向一個mapper接口 package屬性:用來指向能夠找到Mapper接口的包名
(屬於瞭解的內容,由於有了靈活的xml配置方法,這個方式幾乎不用)
MyBatis的SqlSessionFactory接口除了使用基於XML的配置建立外也能夠經過JavaAPI編程式地被建立。每一個在XML中配置的元素,均可以編程式的建立。
由於mybatis框架在讀取了咱們配置的mybatis-config.xml中配置信息以後,利用這些信息去執行代碼建立出咱們須要的SqlSessionFactory,再進一步獲得sqlSession,最後再進行各類數據庫操做。因此其實咱們徹底能夠不去配置任何信息直接把信息寫在代碼中。 只是這樣作再大多數時候都會下降代碼的靈活性,因此咱們基本上接觸的框架都是有相應的配置文件的.
例如:使用Java API建立SqlSessionFactory對象:
以前是讀取配置文件以後再建立,如今是本身把信息寫到代碼中,而後再建立該對象
public static SqlSessionFactory getSqlSessionFactory() { SqlSessionFactory sqlSessionFactory = null; try { DataSource dataSource = DataSourceFactory.getDataSource(); TransactionFactory transactionFactory = new JdbcTransactionFactory(); Environment environment = new Environment("development", transactionFactory, dataSource); Configuration configuration = new Configuration(environment); configuration.getTypeAliasRegistry().registerAlias("student",Student.class); configuration.getTypeHandlerRegistry().register(PhoneNumber.class, PhoneTypeHandler.class); configuration.addMapper(StudentMapper.class); sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration); } catch (Exception e) { throw new RuntimeException(e); } return sqlSessionFactory; }
相似的,每一個在XML中配置的元素,均可以編程式的建立.
注:這裏就不一一介紹了,由於絕大多數狀況下咱們仍是不會把配置信息直接寫到代碼中的
MyBatis使用其內部LoggerFactory做爲真正的日誌類庫使用的門面。其內部的LaggerFactory會將日誌記錄任務委託給以下的所示某一個日誌實現,
日誌記錄優先級由上到下順序遞減:
SLF4J Apache Commons Logging Log4j2 Log4j JDK logging
注意:查看org.apache.ibatis.logging.LogFactory源碼可知
若是MyBatis未發現上述日誌記錄實現,則MyBatis的日誌記錄功能無效,若是你的運行環境中,在classpath中有多個可用的日誌類庫,而且你但願MyBaits使用某個特定的日誌實現,你能夠在代碼中經過調用如下其中一個方法:
org.apache.ibatis.logging.LogFactory.useSlf4jLogging(); org.apache.ibatis.logging.LogFactory.useLog4JLogging(); org.apache.ibatis.logging.LogFactory.useLog4J2Logging(); org.apache.ibatis.logging.LogFactory.useJdkLogging(); org.apache.ibatis.logging.LogFactory.useCommonsLogging(); org.apache.ibatis.logging.LogFactory.useStdOutLogging();
注:若是你想自定義MyBatis日誌記錄,你應該在調用任何其它方法以前調用以上的其中一個方法