淺析mybatis和spring整合的實現過程

NO IMAGE
1 Star2 Stars3 Stars4 Stars5 Stars 給文章打分!
Loading...

根據官方的說法,在ibatis3,也就是Mybatis3問世之前,Spring3的開發工作就已經完成了,所以Spring3中還是沒有對Mybatis3的支援。因此由Mybatis社群自己開發了一個Mybatis-Spring用來滿足Mybatis使用者整合Spring的需求。下面就將通過Mybatis-Spring來整合Mybatis跟Spring的用法做一個簡單的介紹。

MapperFactoryBean

首先,我們需要從Mybatis官網上下載Mybatis-Spring的jar包新增到我們專案的類路徑下,當然也需要新增Mybatis的相關jar包和Spring的相關jar包。我們知道在Mybatis的所有操作都是基於一個SqlSession的,而SqlSession是由SqlSessionFactory來產生的,SqlSessionFactory又是由SqlSessionFactoryBuilder來生成的。但是Mybatis-Spring是基於SqlSessionFactoryBean的。在使用Mybatis-Spring的時候,我們也需要SqlSession,而且這個SqlSession是內嵌在程式中的,一般不需要我們直接訪問。SqlSession也是由SqlSessionFactory來產生的,但是Mybatis-Spring給我們封裝了一個SqlSessionFactoryBean,在這個bean裡面還是通過SqlSessionFactoryBuilder來建立對應的SqlSessionFactory,進而獲取到對應的SqlSession。通過SqlSessionFactoryBean我們可以通過對其指定一些屬性來提供Mybatis的一些配置資訊。所以接下來我們需要在Spring的applicationContext配置檔案中定義一個SqlSessionFactoryBean。

Xml程式碼


<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> 
<property name="dataSource" ref="dataSource" /> 
<property name="mapperLocations" 
value="classpath:com/tiantian/ckeditor/mybatis/mappers/*Mapper.xml" /> 
<property name="typeAliasesPackage" value="com.tiantian.ckeditor.model" /> 
</bean> 

       在定義SqlSessionFactoryBean的時候,dataSource屬性是必須指定的,它表示用於連線資料庫的資料來源。當然,我們也可以指定一些其他的屬性,下面簡單列舉幾個:

 mapperLocations:它表示我們的Mapper檔案存放的位置,當我們的Mapper檔案跟對應的Mapper介面處於同一位置的時候可以不用指定該屬性的值。

configLocation:用於指定Mybatis的配置檔案位置。如果指定了該屬性,那麼會以該配置檔案的內容作為配置資訊構建對應的SqlSessionFactoryBuilder,但是後續屬性指定的內容會覆蓋該配置檔案裡面指定的對應內容。

 typeAliasesPackage:它一般對應我們的實體類所在的包,這個時候會自動取對應包中不包括包名的簡單類名作為包括包名的別名。多個package之間可以用逗號或者分號等來進行分隔。
 typeAliases:陣列型別,用來指定別名的。指定了這個屬性後,Mybatis會把這個型別的短名稱作為這個型別的別名,前提是該類上沒有標註@Alias註解,否則將使用該註解對應的值作為此種型別的別名。

Xml程式碼


<property name="typeAliases"> 
<array> 
<value>com.tiantian.mybatis.model.Blog</value> 
<value>com.tiantian.mybatis.model.Comment</value> 
</array> 
</property> 

plugins:陣列型別,用來指定Mybatis的Interceptor。

 typeHandlersPackage:用來指定TypeHandler所在的包,如果指定了該屬性,SqlSessionFactoryBean會自動把該包下面的類註冊為對應的TypeHandler。多個package之間可以用逗號或者分號等來進行分隔。

 typeHandlers:陣列型別,表示TypeHandler。

接下來就是在Spring的applicationContext檔案中定義我們想要的Mapper物件對應的MapperFactoryBean了。通過MapperFactoryBean可以獲取到我們想要的Mapper物件。MapperFactoryBean實現了Spring的FactoryBean介面,所以MapperFactoryBean是通過FactoryBean介面中定義的getObject方法來獲取對應的Mapper物件的。在定義一個MapperFactoryBean的時候有兩個屬性需要我們注入,一個是Mybatis-Spring用來生成實現了SqlSession介面的SqlSessionTemplate物件的sqlSessionFactory;另一個就是我們所要返回的對應的Mapper介面了。

定義好相應Mapper介面對應的MapperFactoryBean之後,我們就可以把我們對應的Mapper介面注入到由Spring管理的bean物件中了,比如Service bean物件。這樣當我們需要使用到相應的Mapper介面時,MapperFactoryBean會從它的getObject方法中獲取對應的Mapper介面,而getObject內部還是通過我們注入的屬性呼叫SqlSession介面的getMapper(Mapper介面)方法來返回對應的Mapper介面的。這樣就通過把SqlSessionFactory和相應的Mapper介面交給Spring管理實現了Mybatis跟Spring的整合。

Spring的applicationContext.xml配置檔案:

Xml程式碼


<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" 
xmlns:mvc="http://www.springframework.org/schema/mvc" 
xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context-3.0.xsd 
http://www.springframework.org/schema/mvc 
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"> 
<context:component-scan base-package="com.tiantian.mybatis"/> 
<context:property-placeholder location="classpath:config/jdbc.properties"/> 
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" 
destroy-method="close"> 
<property name="driverClassName" value="${jdbc.driver}" /> 
<property name="url" value="${jdbc.url}" /> 
<property name="username" value="${jdbc.username}" /> 
<property name="password" value="${jdbc.password}" /> 
</bean> 
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> 
<property name="dataSource" ref="dataSource" /> 
<property name="mapperLocations" value="classpath:com/tiantian/mybatis/mapper/*.xml"/>
<property name="typeAliasesPackage" value="com.tiantian.mybatis.model" /> 
</bean> 
<bean id="blogMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"> <property name="mapperInterface" 
value="com.tiantian.mybatis.mapper.BlogMapper" /> 
<property name="sqlSessionFactory" ref="sqlSessionFactory" /> 
</bean> 
</beans> 

BlogMapper.xml檔案:

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.tiantian.mybatis.mapper.BlogMapper"> 
<!-- 新增記錄 --> 
<insert id="insertBlog" parameterType="Blog" useGeneratedKeys="true" keyProperty="id"> 
insert into t_blog(title,content,owner) values(#{title},#{content},#{owner}) 
</insert> 
<!-- 查詢單條記錄 --> 
<select id="selectBlog" parameterType="int" resultMap="BlogResult"> 
select * from t_blog where id = #{id} 
</select> 
<!-- 修改記錄 --> 
<update id="updateBlog" parameterType="Blog"> 
update t_blog set title = #{title},content = #{content},owner = #{owner} where id = #{id} 
</update> 
<!-- 查詢所有記錄 --> 
<select id="selectAll" resultType="Blog"> 
select * from t_blog 
</select> 
<!-- 刪除記錄 --> 
<delete id="deleteBlog" parameterType="int"> 
delete from t_blog where id = #{id} 
</delete> 
</mapper> 

BlogMapper.java:

Java程式碼


package com.tiantian.mybatis.mapper; 
import java.util.List; 
import com.tiantian.mybatis.model.Blog; 
publicinterface BlogMapper { 
public Blog selectBlog(int id); 
publicvoid insertBlog(Blog blog); 
publicvoid updateBlog(Blog blog); 
publicvoid deleteBlog(int id); 
public List<Blog> selectAll(); 
} 

BlogServiceImpl.java:

Java程式碼


package com.tiantian.mybatis.service.impl; 
import java.util.List; 
import javax.annotation.Resource; 
import org.springframework.stereotype.Service; 
import com.tiantian.mybatis.mapper.BlogMapper; 
import com.tiantian.mybatis.model.Blog; 
import com.tiantian.mybatis.service.BlogService; 
@Service 
publicclass BlogServiceImpl implements BlogService { 
private BlogMapper blogMapper; 
publicvoid deleteBlog(int id) { 
blogMapper.deleteBlog(id); 
} 
public Blog find(int id) { 
returnblogMapper.selectBlog(id); 
} 
public List<Blog> find() { 
returnblogMapper.selectAll(); 
} 
publicvoid insertBlog(Blog blog) { 
blogMapper.insertBlog(blog); 
} 
publicvoid updateBlog(Blog blog) { 
blogMapper.updateBlog(blog); 
} 
public BlogMapper getBlogMapper() { 
returnblogMapper; 
} 
@Resource 
publicvoid setBlogMapper(BlogMapper blogMapper) { 
this.blogMapper = blogMapper; 
} 
} 

 MapperScannerConfigurer

利用上面的方法進行整合的時候,我們有一個Mapper就需要定義一個對應的MapperFactoryBean,當我們的Mapper比較少的時候,這樣做也還可以,但是當我們的Mapper相當多時我們再這樣定義一個個Mapper對應的MapperFactoryBean就顯得速度比較慢了。為此Mybatis-Spring為我們提供了一個叫做MapperScannerConfigurer的類,通過這個類Mybatis-Spring會自動為我們註冊Mapper對應的MapperFactoryBean物件。

如果我們需要使用MapperScannerConfigurer來幫我們自動掃描和註冊Mapper介面的話我們需要在Spring的applicationContext配置檔案中定義一個MapperScannerConfigurer對應的bean。對於MapperScannerConfigurer而言有一個屬性是我們必須指定的,那就是basePackage。basePackage是用來指定Mapper介面檔案所在的基包的,在這個基包或其所有子包下面的Mapper介面都將被搜尋到。多個基包之間可以使用逗號或者分號進行分隔。最簡單的MapperScannerConfigurer定義就是隻指定一個basePackage屬性,如:

Xml程式碼


<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> 
<property name="basePackage" value="com.tiantian.mybatis.mapper" /> 
</bean> 

這樣MapperScannerConfigurer就會掃描指定基包下面的所有介面,並把它們註冊為一個個MapperFactoryBean物件。當使用MapperScannerConfigurer加basePackage屬性的時候,我們上面例子的applicationContext配置檔案將變為這樣:

Xml程式碼


<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" 
xmlns:mvc="http://www.springframework.org/schema/mvc" 
xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context-3.0.xsd 
http://www.springframework.org/schema/mvc 
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"> 
<context:component-scan base-package="com.tiantian.mybatis" /> 
<context:property-placeholder location="classpath:config/jdbc.properties" /> 
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" 
destroy-method="close"> 
<property name="driverClassName" value="${jdbc.driver}" /> 
<property name="url" value="${jdbc.url}" /> 
<property name="username" value="${jdbc.username}" /> 
<property name="password" value="${jdbc.password}" /> 
</bean> 
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> 
<property name="dataSource" ref="dataSource" /> 
<property name="mapperLocations" value="classpath:com/tiantian/mybatis/mapper/*.xml" /> 
<property name="typeAliasesPackage" value="com.tiantian.mybatis.model" /> 
</bean> 
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> 
<property name="basePackage" value="com.tiantian.mybatis.mapper" /> 
</bean> 
</beans> 

 有時候我們指定的基包下面的並不全是我們定義的Mapper介面,為此MapperScannerConfigurer還為我們提供了另外兩個可以縮小搜尋和註冊範圍的屬性。一個是annotationClass,另一個是markerInterface。

annotationClass:當指定了annotationClass的時候,MapperScannerConfigurer將只註冊使用了annotationClass註解標記的介面。

markerInterface:markerInterface是用於指定一個介面的,當指定了markerInterface之後,MapperScannerConfigurer將只註冊繼承自markerInterface的介面。

如果上述兩個屬性都指定了的話,那麼MapperScannerConfigurer將取它們的並集,而不是交集。即使用了annotationClass進行標記或者繼承自markerInterface的介面都將被註冊為一個MapperFactoryBean。

現在假設我們的Mapper介面都繼承了一個SuperMapper介面,那麼我們就可以這樣來定義我們的MapperScannerConfigurer。

Xml程式碼


<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> 
<property name="basePackage" value="com.tiantian.mybatis.mapper" /> 
<property name="markerInterface" value="com.tiantian.mybatis.mapper.SuperMapper"/> 
</bean> 

      如果是都使用了註解MybatisMapper標記的話,那麼我們就可以這樣來定義我們的MapperScannerConfigurer。

Xml程式碼


<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> 
<property name="basePackage" value="com.tiantian.mybatis.mapper" /> 
<property name="annotationClass" value="com.tiantian.mybatis.annotation.MybatisMapper"/> 
</bean> 

除了用於縮小注冊Mapper介面範圍的屬性之外,我們還可以指定一些其他屬性,如:

sqlSessionFactory:這個屬性已經廢棄。當我們使用了多個資料來源的時候我們就需要通過sqlSessionFactory來指定在註冊MapperFactoryBean的時候需要使用的SqlSessionFactory,因為在沒指定sqlSessionFactory的時候,會以Autowired的方式自動注入一個。換言之當我們只使用一個資料來源的時候,即只定義了一個SqlSessionFactory的時候我們就可以不給MapperScannerConfigurer指定SqlSessionFactory。

sqlSessionFactoryBeanName:它的功能跟sqlSessionFactory是一樣的,只是它指定的是定義好的SqlSessionFactory對應的bean名稱。

sqlSessionTemplate:這個屬性已經廢棄。它的功能也是相當於sqlSessionFactory的,因為就像前面說的那樣,MapperFactoryBean最終還是使用的SqlSession的getMapper方法取的對應的Mapper物件。當定義有多個SqlSessionTemplate的時候才需要指定它。對於一個MapperFactoryBean來說SqlSessionFactory和SqlSessionTemplate只需要其中一個就可以了,當兩者都指定了的時,SqlSessionFactory會被忽略。

sqlSessionTemplateBeanName:指定需要使用的sqlSessionTemplate對應的bean名稱。
注意:由於使用sqlSessionFactory和sqlSessionTemplate屬性時會使一些內容在PropertyPlaceholderConfigurer之前載入,導致在配置檔案中使用到的外部屬性資訊無法被及時替換而出錯,因此官方現在新的Mybatis-Spring中已經把sqlSessionFactory和sqlSessionTemplate屬性廢棄了,推薦大家使用sqlSessionFactoryBeanName屬性和sqlSessionTemplateBeanName屬性。

Xml程式碼 


<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" 
xmlns:mvc="http://www.springframework.org/schema/mvc" 
xmlns:mybatis="http://www.mybatis.org/schema/mybatis" 
xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context-3.0.xsd 
http://www.mybatis.org/schema/mybatis 
http://www.mybatis.org/schema/mybatis/mybatis-spring.xsd 
http://www.springframework.org/schema/mvc 
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"> 
<context:component-scan base-package="com.tiantian.mybatis" /> 
<context:property-placeholder location="classpath:config/jdbc.properties" /> 
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" 
destroy-method="close"> 
<property name="driverClassName" value="${jdbc.driver}" /> 
<property name="url" value="${jdbc.url}" /> 
<property name="username" value="${jdbc.username}" /> 
<property name="password" value="${jdbc.password}" /> 
</bean> 
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> 
<property name="dataSource" ref="dataSource" /> 
<property name="mapperLocations" value="classpath:com/tiantian/mybatis/mapper/*.xml" /> 
<property name="typeAliasesPackage" value="com.tiantian.mybatis.model" /> 
</bean> 
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> 
<property name="basePackage" value="com.tiantian.mybatis.mapper" /> 
<property name="markerInterface" value="com.tiantian.mybatis.mapper.SuperMapper"/> 
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> 
</bean> 
</beans> 

 SqlSessionTemplate

除了上述整合之後直接使用Mapper介面之外,Mybatis-Spring還為我們提供了一種直接使用SqlSession的方式。Mybatis-Spring為我們提供了一個實現了SqlSession介面的SqlSessionTemplate類,它是執行緒安全的,可以被多個Dao同時使用。同時它還跟Spring的事務進行了關聯,確保當前被使用的SqlSession是一個已經和Spring的事務進行繫結了的。而且它還可以自己管理Session的提交和關閉。當使用了Spring的事務管理機制後,SqlSession還可以跟著Spring的事務一起提交和回滾。

使用SqlSessionTemplate時我們可以在Spring的applicationContext配置檔案中如下定義:


<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory" />
</bean>

       這樣我們就可以通過Spring的依賴注入在Dao中直接使用SqlSessionTemplate來程式設計了,這個時候我們的Dao可能是這個樣子:

Java程式碼


package com.tiantian.mybatis.dao; 
import java.util.List; 
import javax.annotation.Resource; 
import org.mybatis.spring.SqlSessionTemplate; 
import org.springframework.stereotype.Repository; 
import com.tiantian.mybatis.model.Blog; 
@Repository 
publicclass BlogDaoImpl implements BlogDao { 
private SqlSessionTemplate sqlSessionTemplate; 
publicvoid deleteBlog(int id) { 
sqlSessionTemplate.delete("com.tiantian.mybatis.mapper.BlogMapper.deleteBlog", id); 
} 
public Blog find(int id) { 
returnsqlSessionTemplate.selectOne("com.tiantian.mybatis.mapper.BlogMapper.selectBlog", id); 
} 
public List<Blog> find() { 
returnthis.sqlSessionTemplate.selectList("com.tiantian.mybatis.mapper.BlogMapper.selectAll"); 
} 
publicvoid insertBlog(Blog blog) { 
this.sqlSessionTemplate.insert("com.tiantian.mybatis.mapper.BlogMapper.insertBlog", blog); 
} 
publicvoid updateBlog(Blog blog) { 
this.sqlSessionTemplate.update("com.tiantian.mybatis.mapper.BlogMapper.updateBlog", blog); 
} 
public SqlSessionTemplate getSqlSessionTemplate() { 
returnsqlSessionTemplate; 
} 
@Resource 
publicvoid setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) { 
this.sqlSessionTemplate = sqlSessionTemplate; 
} 
} 

 注:
  本文是基於Mybatis3.2.1、Mybatis-Spring1.1.0和Spring3.1寫的。

相關文章

程式語言 最新文章