在介紹這兩個映射接口之前首先了解這兩個接口的目的是啥:
為了代替手工使用 SqlSessionDaoSupport 或 SqlSessionTemplate 編寫數據訪問對象(DAO)的代碼,MyBatis-Spring 提供了一個動態代理的實現——MapperFactoryBean。這個類可以讓你直接注入數據映射器接口到你的 service 層bean 中。當使用映射器時,你僅僅如調用你的 DAO 一樣調用它們就可以了,但是你不需要編寫任何 DAO 實現的代碼,因為 MyBatis-Spring將會為你創建代理。同樣,MapperFactoryBean創建的代理控制開放和關閉 session
也就是說dao層的對數據訪問對象被映射器直接注入到了service層,因此這個dao實現類就沒必要寫和注冊了,從而簡化操作,那么sqlsession也就不需要了吧。
先詳細回顧一下之前的spring的原生sqlsession方法,也就是使用到了dao實現層。
方法一:使用SqlSessionTemplate生成Mapper
需要先在spring-dao.xml里面注冊
<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/student?userSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="datasource"/>
<property name="configLocation" value="mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:com/bupt/dao/*.xml"/>
</bean>
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!-- 只能使用構造器注入sqlsessionfactory因為沒有set方法 -->
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
dao層里面創建實現UserMapper的類
package com.bupt.dao; import com.bupt.pojo.User; import org.mybatis.spring.SqlSessionTemplate; import java.util.List; public class UserMapperImpl implements UserMapper{ private SqlSessionTemplate sqlSessionTemplate; public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) { this.sqlSessionTemplate = sqlSessionTemplate; } @Override public List<User> selectUser() { return sqlSessionTemplate.getMapper(UserMapper.class).selectUser(); } @Override public int addUser(User user) { return 0; } @Override public int deleteUser(int id) { return 0; } }
可以看到此時sqlSessionTemplate因為已經被注冊到spring-dao.xml里面,通過set方法便可以直接獲取sqlSessionTemplate對象,通過該對象生成Mapper調用相關的數據操作方法。
方法二:繼承SqlSessionDaoSupport生成Mapper
該方法只需要繼承SqlSessionDaoSupport類便可以直接獲取sqlSession對象,因此不需要額外的注冊Bean
dao層里面創建實現UserMapper的類UserDaoImpl.java
package com.bupt.dao; import com.bupt.pojo.User; import org.mybatis.spring.support.SqlSessionDaoSupport; import java.util.List; public class UserDaoImpl extends SqlSessionDaoSupport implements UserMapper { // SqlSessionDaoSupport有一個getSqlSession方法可以直接獲取一個sqlsession對象 @Override public List<User> selectUser() { User user = new User(445,"小明","123456"); UserMapper mapper = getSqlSession().getMapper(UserMapper.class); mapper.addUser(user); mapper.deleteUser(444); return mapper.selectUser(); } @Override public int addUser(User user) { return getSqlSession().getMapper(UserMapper.class).addUser(user); } @Override public int deleteUser(int id) { return getSqlSession().getMapper(UserMapper.class).deleteUser(id); } }
通過這兩種方法在dao層里面封裝了sqlsession對dao的操作,因此可以在service層里面去直接調用就可以操作數據庫了,不過要先把上面的兩種方法注冊到spring里面ApplicationContext.xml
<bean id="userMapper" class="com.bupt.dao.UserMapperImpl"> <property name="sqlSessionTemplate" ref="sqlSession"/> </bean> <bean id="userDao" class="com.bupt.dao.UserDaoImpl"> <property name="sqlSessionFactory" ref="sqlSessionFactory" /> </bean>
先寫個測試看一下
@Test public void test04(){ ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml"); UserMapper userMapper = classPathXmlApplicationContext.getBean("userMapper", UserMapper.class); for (User user : userMapper.selectUser()) { System.out.println(user); } } @Test public void test05(){ ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("ApplicationContext.xml"); UserMapper userMapper = classPathXmlApplicationContext.getBean("userDao", UserMapper.class); for (User user : userMapper.selectUser()) { System.out.println(user); } }
可以看到這兩種方法都是spring的生成sqlsession獲取Mapper操作dao方法的兩種對策,但是spring也提供了進一步的封裝技術,也就是不需要顯示的去獲取sqlsession操作dao,MapperFactoryBean就是其中
一個技術。
方法三:MapperFactoryBean封裝sqlsession
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> <typeAliases> <package name="com.bupt.pojo"/> </typeAliases> <!-- 這個文件放別名和setting--> </configuration>
spring-dao.xml
<bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driver}"/> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> <property name="maxPoolSize" value="30"/> <property name="minPoolSize" value="10"/> <property name="autoCommitOnClose" value="false"/> <property name="checkoutTimeout" value="10000"/> <property name="acquireRetryAttempts" value="2"/> </bean> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="datasource"/> <property name="configLocation" value="classpath:mybatis-config.xml"/> </bean> <bean id="bookMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"> <property name="mapperInterface" value="com.bupt.dao.BookMapper"/> <property name="sqlSessionFactory" ref="sqlSessionFactory"/> </bean>
通過注冊MapperFactoryBean我們就不要去寫Mapper接口的實現類(也就是封裝了sqlsession的使用),就可以直接在service里面進行使用,dao里面只需要BookMapper接口和對應的sql操作的xml文件

在service層里面可以直接通過set方法注入dao里面的接口,通過接口對象直接使用操作數據庫的方法

BookService接口
package com.bupt.service; import com.bupt.pojo.Books; import org.apache.ibatis.annotations.Param; import java.util.List; public interface BookService { //增加一個Book int addBook(Books book); //根據id刪除一個Book int deleteBookById(int id); //更新Book int updateBook(Books books); //根據id查詢,返回一個Book Books queryBookById(int id); //查詢全部Book,返回list集合 List<Books> queryAllBook(); List<Books> queryBookByName(@Param("bookName") String bookname); }
BookServiceImpl實現類
package com.bupt.service; import com.bupt.dao.BookMapper; import com.bupt.pojo.Books; import java.util.List; public class BookServiceImpl implements BookService{ //調用dao層的操作,設置一個set接口,方便Spring管理 private BookMapper bookMapper; public void setBookMapper(BookMapper bookMapper) { this.bookMapper = bookMapper; } public int addBook(Books book) { return bookMapper.addBook(book); } public int deleteBookById(int id) { return bookMapper.deleteBookById(id); } public int updateBook(Books books) { return bookMapper.updateBook(books); } public Books queryBookById(int id) { return bookMapper.queryBookById(id); } public List<Books> queryAllBook() { return bookMapper.queryAllBook(); } @Override public List<Books> queryBookByName(String bookname) { return bookMapper.queryBookByName(bookname); } }
然后把service層進行注入到bean里面
在spring-service.xml里面(其中bookMapper已經被自動注冊)
<!-- 掃描service相關的bean --> <context:component-scan base-package="com.bupt.service" /> <!--BookServiceImpl注入到IOC容器中--> <bean id="BookServiceImpl" class="com.bupt.service.BookServiceImpl">
<property name="bookMapper" ref="bookMapper"/> </bean>
這樣就可以直接在control里面使用該service
@Resource(name = "BookServiceImpl") private BookService bookService; @RequestMapping("/allBook") public String list(Model model){ List<Books> books = bookService.queryAllBook(); model.addAttribute("list",books); return "allbook"; }
關於MapperFactoryBean底層的東西可以看這篇文章:https://www.cnblogs.com/Joe-Go/p/10256241.html
但是MapperFactoryBean的一個問題是每個接口我們都需要注冊一下,是不是很麻煩。需要用到的映射器較多的話,采用這種配置方式就會很低效。為了解決這個問題,我們可以使用MapperScannerConfigurer,讓它掃描特定的包,自動幫我們成批的創建映射器。這樣一來,就能大大減少配置的工作量。
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<property name="basePackage" value="com.bupt.dao"/>
</bean>
其他的相關操作就是和方法三一樣,但是由於掃描包的存在可以對包里面的所有接口直接注入,很是方便。