MyBatis的設計思路java
ORM(Object Relation Mapping)模型將數據庫存儲數據與POJO對象進行映射,從而簡化數據轉化的複雜度;若是說Hibernate是徹底封裝的ORM框架,則myBatis則是半徹底封裝的ORM框架,由於myBatis須要手動映射SQL返回結果與POJO對象的映射;mysql
java鏈接mysql通常有四種方式,不基於鏈接池的jdbc和基於鏈接池的dbcp, c3p0, jndi:
#1 jdbc:不使用鏈接池,每次進行DB操做都經過java.sql.DriverManager.getConnection獲取一個新的connection,並經過openSession()獲取一個交互session;
#2 dbcp:基於org.apache.commons.dbcp.BasicDataSource並建立connection pool,BasicDataSourceFactory.createDataSource獲取DBCP數據源,而後獲取可重複使用的connection;
#3 c3p0:基於DataSource並建立connection pool,ComboPooledDataSource.getConnection獲取可重複使用的connection。
#4 jndi:基於DataSource並建立connection pool,InitialContext.getConnection獲取connection。spring
myBatis解決了原生JDBC訪問DB的幾大問題:sql
#1 DB Connection頻繁的開啓和關閉會形成資源的浪費,因此使用DB Connection Pool經過重複利用Connection能夠極大下降DB資源的消耗;connection建立session並開啓transaction,session結束後transaction也關閉,並將connection歸還給pool;
#2 使用可配置的方式兼容多種DataSource(jndi, c3p0, dbcp)的鏈接池;
#3 愈來愈多的業務須要根據數據來動態生成sql語句,傳統的preparedStatement都是基於固定的sql來填充參數,mybatis提供if-else等標籤根據業務數據動態生成並組裝sql;
#4 mybatis提供ResultMap等自動映射的方式對查詢結果進行解析,並提供[sql + params]做爲key的方式將查詢結果進行緩存;
#5 mybatis提供<sql />標籤將一些共用的sql片斷抽取出來,供多個地方引用;數據庫
對比MyBatis和Hibernateapache
#1 myBatis中的SQL是在開發的時候就已經寫好的,而且能夠細粒度的優化SQL語句,hibernate則是徹底根據Object生成SQL,性能上會有一些影響;但同時hibernate的DB關聯性低,可移植性高,myBatis因爲定製化了大量的SQL,則在遷移DB的時候須要考慮兼容性;緩存
Mybatis可接編寫原生態sql,可嚴格控制sql執行性能,靈活度高,很是適合對關係數據模型要求不高的軟件開發;但缺點是mybatis沒法作到數據庫無關性,若是須要實現支持多種數據庫則須要自定義多套sql映射文件,myBatis一樣支持經過java bean定義逆向生成CRUD操做對應的SQL。安全
#2 Hibernate提供的是一種全表映射的模型,所以在作關聯查詢的時候hibernate會將相關表的全部字段都加載到內存,而後再將數據封裝成須要的對象;而myBatis會根據resultMap僅僅將須要的數據加載到內存,並自動轉化成須要的對象,能夠極大提高效率。session
#3 Hibernate有一整套DAO對象的狀態管理機制,myBatis則沒有完整的DAO管理機制,須要手動維護DAO對象的數據更新操做;mybatis
#4 Hibernate的ORM映射關係是固定的,若是某些字段或者某些查詢條件須要動態生成則只能經過HQL實現(性能較差),而myBatis自然支持SQL的動態生成,能夠支持table名字或者column名字動態變化的場景;
#5 Hibernate不能有效支持存儲過程,myBatis自然支持存儲過程,store procedure的優點在於將業務邏輯封裝到DB端,更安全穩定、執行性能也高,但劣勢在於bug tracking和可移植性;
在spring中集成myBatis
首先在spring配置文件service.xml中配置 DBCP數據源,TxManager 和SqlSession的封裝。
1 <beans xmlns="http://www.springframework.org/schema/beans"> 2 <bean id="dbcpDataSource" 3 class="org.apache.commons.dbcp.BasicDataSource"> 4 <property name="driverClassName"> 5 <value>com.mysql.jdbc.Driver</value> 6 </property> 7 <property name="url"> 8 <value>jdbc:mysql://localhost:3306/ychenDemo</value> 9 </property> 10 <property name="username"> 11 <value>root</value> 12 </property> 13 <property name="password"> 14 <value>password</value> 15 </property> 16 </bean> 17 18 <bean id="mybatisTxManager" 19 class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 20 <property name="dataSource" ref="dbcpDataSource" /> 21 </bean> 22 23 <bean id="sqlSessionFactory" 24 class="org.mybatis.spring.SqlSessionFactoryBean"> 25 <property name="dataSource" ref="dbcpDataSource" /> 26 <property name="configLocation" 27 value="mybatis/mybatis-config.xml"></property> 28 </bean> 29 30 <bean id="myBatisBaseMapper" 31 class="org.mybatis.spring.mapper.MapperFactoryBean" abstract="true" 32 lazy-init="true"> 33 <property name="sqlSessionFactory" ref="sqlSessionFactory" /> 34 </bean> 35 36 <bean id="userMapper" parent="myBatisBaseMapper"> 37 <property name="mapperInterface" 38 value="ychen.demo_mybatis.mapper.UserMapper" /> 39 </bean> 40 41 <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"> 42 <constructor-arg index="0" ref="sqlSessionFactory" /> 43 </bean> 44 </beans>
mybatis提供兩種DB操做的接口:
-1 經過sqlSessionTemplate提供統一接口,並在參數中指定statementID和parameterList的方式;
1 public List<Person> getPersonById(Long personId) { 2 Map<String, Long> params = Maps.newHashMap(); 3 params.put("personId", personId); 4 List<Person> result = template.selectList("getPersonById", params); 5 return result; 6 } 7 8 >>>>>>>>>>>>> 9 <mapper namespace="personMapper"> 10 <select id="getPersonById" resultType="com.ychen.Person"> 11 SELECT * FROM person WHERE id = #{personId} 12 </select> 13 </mapper>
-2 經過定義mapper interface,並使用SqlSessionFactoryBean和MapperFactoryBean動態代理的方式生成mapper實現類,mapper interface中能夠自定義多個DB訪問接口,內部實現依舊是轉換成sqlSessionTemplate統一接口的方式,只是封裝性更好。
1 @Component 2 public interface UserMapper { 3 void insert(UserEntity user); 4 UserEntity getOne(Long id); 5 } 6 7 >>>>>>>>> 8 <mapper namespace="ychen.demo_mybatis.mapper.UserMapper"> 9 <select id="getOne" parameterType="Long" resultMap="BaseResultMap"> 10 SELECT <include refid="Base_Column_List" /> 11 FROM payment_session 12 WHERE id = #{id} 13 </select> 14 </mapper> 15 16 >>>>>>>>> 17 UserMapper userMapper = 18 applicationContext.getBean("userMapper", UserMapper.class); 19 UserEntity userEntity = userMapper.getOne(1L);
構建sqlSessionFactory所需的myBatis-config.xml配置
1 <configuration> 2 <!-- resource屬性引入外部定義的key/value變量,也可經過property標籤訂義內部變量 --> 3 <properties resource="org/mybatis/example/mybatis-config.properties"> 4 <property name="username" value="dev_user"/> 5 <property name="password" value="F2Fa3!33TYyg"/> 6 </properties> 7 <!-- 定義mybatis的運行變量 --> 8 <settings> 9 <setting name="cacheEnabled" value="true"/> 10 <setting name="lazyLoadingEnabled" value="true"/> 11 <setting name="multipleResultSetsEnabled" value="true"/> 12 <setting name="useColumnLabel" value="true"/> 13 <setting name="useGeneratedKeys" value="false"/> 14 <setting name="autoMappingBehavior" value="PARTIAL"/> 15 <!-- SIMPLE|REUSE|BATCH --> 16 <setting name="defaultExecutorType" value="SIMPLE"/> 17 <setting name="defaultStatementTimeout" value="25"/> 18 <setting name="defaultFetchSize" value="100"/> 19 <setting name="safeRowBoundsEnabled" value="false"/> 20 <setting name="mapUnderscoreToCamelCase" value="false"/> 21 <setting name="localCacheScope" value="SESSION"/> 22 <setting name="jdbcTypeForNull" value="OTHER"/> 23 <setting name="lazyLoadTriggerMethods" 24 value="equals,clone,hashCode,toString"/> 25 </settings> 26 <!-- 定義經常使用類型的簡寫別名,同時mybatis爲java經常使用類型提供了缺省別名 --> 27 <typeAliases> 28 <typeAlias type="leo.chen.domain.UserAccount" alias="UserAccount" /> 29 <typeAlias type="leo.chen.domain.SpecialCar" alias="SpecialCar" /> 30 </typeAliases> 31 <!-- 處理參數和返回結果在java-type和db-type間的轉換,同時myBatis提供經常使用類型的handler --> 32 <!-- 經過繼承BaseTypeHandler類或者實現TypeHandler接口,能夠定製化轉換方法 --> 33 <typeHandlers> 34 <typeHandler handler="com.active.services.endurance.mybatis.UUIDTypeHandler" 35 javaType="java.util.UUID" jdbcType="VARCHAR"/> 36 </typeHandlers> 37 <!-- myBatis建立結果對象實例時使用默認的工廠類實現,經過objectFactory能夠替換默認的工廠 --> 38 <objectFactory type="leo.chen.manager.CustomizedObjectFactory"> 39 <property name="property1" value="value1"> 40 </objectFactory> 41 <!-- 用於對mybatis處理流程中某些方法的擴展處理,如緩存一致性,如分頁 --> 42 <plugins> 43 <plugin interceptor="org.mybatis.example.validationPlugin"> 44 <property name="isThrowExp" value="true"/> 45 </plugin> 46 </plugins> 47 <!-- 定義mybatis的執行環境,包括事務管理、數據源等配置 --> 48 <environments default="development"> 49 <environment id="development"> 50 <transactionManager type="JDBC"> </transactionManager> 51 <dataSource type="POOLED"> 52 <property name="driver" value="${driver}"/> 53 <property name="url" value="${url}"/> 54 <property name="username" value="${username}"/> 55 <property name="password" value="${password}"/> 56 <property name="defaultTransactionlsoltionLevel" value="${txLevel}"/> 57 <property name="poolMaximumActiveConnection" value="10"/> 58 <property name="poolMaximumldleConnection" value="10"/> 59 <property name="poolMaximumCheckoutTime" value="20000"/> 60 <property name="poolTimeToWait" value="20000"/> 61 <property name="poolPingQuery" value="NOPINGQUERYSET"/> 62 <property name="poolPingEnabled" value="false"/> 63 <property name="poolPingConnectionsNotUsedFor" value="0"/> 64 </dataSource> 65 </environment> 66 </environments> 67 <!-- 數據庫廠商標識 --> 68 <databaseIdProvider type=""></databaseIdProvider> 69 <!-- 定義mapper映射文件 --> 70 <mappers> 71 <mapper resource="mybatis/productMapper.xml" /> 72 </mappers> 73 </configuration>
#1 mybatis提供兩種事務管理配置,JDBC和MANAGED,前者使用正常的JDBC的事務管理,也就是對java.sql.Connection事務管理的封裝,依賴於從data source獲取的鏈接來管理實務;後者將事務管理交由WEB容器進行管理,也就是說調用ManagedTransaction的commit和rollback並不會有任何動做;若是myBatis跟spring集成,則不須要配置此項。
#2 mybatis提供三種數據源的的配置,POOLED, UNPOOLED和JNDI,POOLED是在UNPOOLED的封裝上添加了connection緩存管理的實現,UNPOOLED的實現僅僅是打開和關閉鏈接;而JNDI則是經過jndi服務查找代理的data source實現;若是myBatis跟spring集成,則也不須要配置此項。
#3 localCacheScope表示設置一級緩存的使用範圍,缺省爲SESSION,若是設置爲STATEMENT則表示一級緩存僅限於一次statement使用,也就是禁用緩存。鑑於mybatis一級緩存實現不完整,容易形成數據一致性問題,所以建議使用STATEMENT。
#4 <plugins>標籤容許在mybatis內部的四個大的處理流程中插入自定義的處理方法:
-1 Executor:處理mybatis的整個流程和二級緩存的使用
-2 ParameterHandler:處理mybatis對sql傳入參數的賦值,
-3 StatementHandler:處理mybatis與db進行交互的規則和一級緩存的修改,
-4 ResultSetHandler:處理mybatis對結果集的映射規則;
具體的實現類須要實現Interceptor接口及對應的方法。
1 public interface Interceptor { 2 //經過invocation.getTarget()能夠定製不一樣階段的plugin 3 Object intercept(Invocation invocation) throws Throwable; 4 Object plugin(Object target); 5 void setProperties(Properties properties); 6 }