1. 程式人生 > 其它 >(五)Spring-spring和mybatis的整合

(五)Spring-spring和mybatis的整合

(五)Spring-spring和mybatis的整合

一、整合要點

1.1 準備工作

spring和mybatis的官網整合地址為:

http://www.mybatis.cn/archives/769.html

需要匯入依賴:

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis-spring</artifactId>
  <version>2.0.3</version>
</dependency>

1.2 資料來源替換

spring配置檔案的資料來源替換mybatis配置檔案的資料來源

1 原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核心配置檔案-->
<configuration>

    <properties resource="db.properties" >
        <property name="" value=""/>
    </properties>
    <typeAliases>
        <package name="com.happy.pojo"/>
    </typeAliases>
    
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
        <environment id="uat">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!--        每一個mapper.xml都需要在mybatis核心配置檔案中註冊-->
        <!--        <mapper resource="org/mybatis/example/BlogMapper.xml"/>-->
<!--        <mapper resource="com/happy/dao/UserMapper.xml"></mapper>-->
        <package name="com.happy.mapper.user"/>
    </mappers>
</configuration>

2 用spring.xml替換為:

 <context:property-placeholder location="db.properties"/>

<!--註冊一個datasource,使用spring的datasource替換mybatis的配置,c3p0,dbcp,druid-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="${driver}"></property>
    <property name="url" value="${url}"></property>
    <property name="username" value="${username}"></property>
    <property name="password" value="${password}"></property>
</bean>

1.3 sqlSessionFactory替換

1 原mybatis實現為工具類

原來mybatis框架需要程式碼用工具類實現獲取SqlSessionFactory,主要是通過讀取原來mybatis的配置檔案,獲取資料來源資訊,生成SqlSessionFactory物件

如下

package com.happy.utils;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;
import java.sql.DriverManager;

public class MybatisUtils {

    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
			//使用mybatis第一步:獲取sqlSessionFactory物件
            String resource = "mybatis-config.xml";
			//InputStream inputStream = MybatisUtils.class.getClassLoader().getResourceAsStream(resource);
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
			//使用uat環境資料庫
			//sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream,"uat");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static SqlSession getSqlSession() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        return sqlSession;
    }

    public static void release(SqlSession sqlSession){

    }
}

2 用spring.xml替換為:

在 MyBatis-Spring 中,可使用 SqlSessionFactoryBean 來建立 SqlSessionFactory。 要配置這個工廠 Bean,只需要把下面程式碼放在 Spring 的 XML 配置檔案中:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="dataSource" ref="dataSource" />
</bean>

1.4 獲取Mapper方式替換

1 原mybatis實現為用工具類獲取MybatisUtils.getSqlSession()

之前為在service層,通過在方法類使用工具類分兩步獲取mapper:

  • MybatisUtils.getSqlSession()獲取SqlSession,實際工具類為通過SqlSessionFactory獲取
  • 然後通過getSqlSession獲取mapper
package com.happy.service.user.impl;

import com.happy.mapper.user.UserMapper;
import com.happy.pojo.User;
import com.happy.service.user.UserService;
import com.happy.utils.MybatisUtils;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class UserServiceImpl implements UserService {
    UserMapper userMapper;

    @Override
    public List<User> getUserList() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = userMapper.getUserList();

        return userList;
    }

    @Override
    public User getUserById(int id) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        userMapper = sqlSession.getMapper(UserMapper.class);
        User user = userMapper.getUserById(id);

        return user;
    }

    @Test
    public void test(){
        List<User> userList = getUserList();
        System.out.println(userList);
    }
    
    @Test
    public void testGetUserById(){
        User user = getUserById(3);
        System.out.println(user);
    }
}

2 用spring.xml配置mapper

<!--3.註冊一個MapperFactoryBean 用於獲取mapper-->
<!--需要關聯UserMapper 相當於原來的sqlSession.getMapper(UserMapper.class)-->
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
    <property name="mapperInterface" value="com.happy.mapper.user.UserMapper" />
    <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

3 測試使用

用spring.xml配置mapper後,這樣獲取和使用:

package com.happy.service.user.impl;

import com.happy.mapper.user.UserMapper;
import com.happy.pojo.User;
import com.happy.service.user.UserService;
import com.happy.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Service;

import java.util.List;
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    @Qualifier("userMapper")
    UserMapper userMapper;

    @Override
    public List<User> getUserList() {
        List<User> userList = userMapper.getUserList();
        return userList;
    }

    @Override
    public User getUserById(int id) {
        User user = userMapper.getUserById(id);
        return user;
    }

    @Test
    public void testGetUserList(){
        ApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml");
        UserService userService = context.getBean("userServiceImpl", UserService.class);
        List<User> userList =userService.getUserList();
        for (User user : userList) {
            System.out.println(user);
        }
    }

    @Test
    public void testGetUserById(){
        ApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml");
        UserService userService = context.getBean("userServiceImpl", UserService.class);
        User user = userService.getUserById(3);
        System.out.println(user);
    }
}

1.5 小結

一般,最終結合後的專案總結構如下:

1 一個總配置檔案application-context.xml用來配置spring總的配置

  • application-context.xml如下,負責開啟註解,包掃描等
  • 注意import其他spring.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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--總配置-->
    <!--匯入其他元件配置-->
    <import resource="spring-mybatis.xml"></import>
    <!--<import resource="spring-mvc.xml"></import>-->


    <!--開啟註解支援-->
    <context:annotation-config></context:annotation-config>
    <context:component-scan base-package="com.happy"></context:component-scan>
    <aop:aspectj-autoproxy proxy-target-class="false"></aop:aspectj-autoproxy>
</beans>

2 總配置下匯入其他元件配置(如spring-mybatis.xml,spring-mvc.xml)和業務bean(如spring-user.xml)

  • spring-mybatis.xml如下,負責spring整合mybatis的所有配置,主要包括資料來源sqlSessionFactory
  • 資料來源可以引用外部properties檔案。
  • 註冊mapper,通過 MapperFactoryBean 將介面加入到 Spring 中,需要注意的是:所指定的對映器類必須是一個介面,而不是具體的實現類。在這個示例中,通過註解來指定 SQL 語句,但是也可以使用 MyBatis 對映器的 XML 配置檔案
  • MapperFactoryBean在這裡註冊mapper,實際為mapper介面的一個動態代理(已經注入了sqlSession等屬性)
  • MapperFactoryBean 將會負責 SqlSession 的建立和關閉。
<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

    <context:property-placeholder location="db.properties"/>

    <!--註冊bean-->

    <!--1.註冊一個datasource,使用spring的datasource替換mybatis的配置,c3p0,dbcp,druid-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driver}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>


    <!--2.註冊一個sqlSessionFactory 用於生成sqlSession-->
    <!-- String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation" value="classpath:Mybatis-config.xml"></property>
    <!--<property name="mapperLocations" value="classpath:com/happy/mapper/user/UserMapper.xml"></property>-->
    </bean>

    <!--3.註冊一個MapperFactoryBean 用於獲取mapper-->
    <!--需要關聯UserMapper介面 相當於原來的sqlSession.getMapper(UserMapper.class)-->
    <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
        <property name="mapperInterface" value="com.happy.mapper.user.UserMapper" />
        <property name="sqlSessionFactory" ref="sqlSessionFactory" />
    </bean>
</beans>

3 mybatis-config.xml原生配置檔案

  • mybatis-config.xml,mybatis原生配置檔案將資料來源、sqlSessionFactory等去掉(已在spring中配置)
  • 注意在spring中配置中配置sqlSessionFactory的時候引用mybatis配置檔案
  • mybatis原生配置檔案,一般保留配置如下(也可以全部放到spring中配置):
    • typeAliases
    • mappers,負責mybatis的beans.xml檔案和mapper介面對映
    • settings配置
<?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核心配置檔案-->
<configuration>
    <!--個人習慣在mybatis原生配置檔案裡儲存typeAliases,mappers,和settings配置-->
    <!--其餘都放在spring裡配置-->
    <typeAliases>
        <package name="com.happy.pojo"/>
    </typeAliases>
    
    <mappers>
        <!--        每一個mapper.xml都需要在mybatis核心配置檔案中註冊-->
        <!--        <mapper resource="org/mybatis/example/BlogMapper.xml"/>-->
        <!--        <mapper resource="com/happy/dao/UserMapper.xml"></mapper>-->
        <package name="com.happy.mapper.user"/>
    </mappers>
</configuration>

4 編寫mapper介面和mapper.xml檔案

UserMapper.java

package com.happy.mapper.user;

import com.happy.pojo.User;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface UserMapper {

    @Select("select * from user")
    List<User> getUserList();

    User getUserById(@Param("id") int id);
}

UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.happy.mapper.user.UserMapper">
<!--    <select id="getUserList" resultType="user">-->
<!--        select * from user;-->
<!--    </select>-->


    <select id="getUserById" resultType="user">
        select * from user where id=#{id};
    </select>
</mapper>

5 service層呼叫mapper介面

  • 可以使用spring.xml註冊service層的bean,也可以使用@Service註解等注入容器
  • 註冊service的bean時,注意屬性注入依賴mapper
  • 使用時,如controller直接從容器中獲取service的bean即可以實現業務。
  • 配置好之後,你就可以像 Spring 中普通的 bean 注入方法那樣,將對映器注入到你的業務或服務物件中。MapperFactoryBean 將會負責 SqlSession 的建立和關閉。 如果使用了 Spring 的事務功能,那麼當事務完成時,session 將會被提交或回滾。最終任何異常都會被轉換成 Spring 的 DataAccessException 異常。
package com.happy.service.user.impl;

import com.happy.mapper.user.UserMapper;
import com.happy.pojo.User;
import com.happy.service.user.UserService;
import com.happy.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Service;

import java.util.List;
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    @Qualifier("userMapper")
    UserMapper userMapper;

    @Override
    public List<User> getUserList() {
        List<User> userList = userMapper.getUserList();
        return userList;
    }

    @Override
    public User getUserById(int id) {
        User user = userMapper.getUserById(id);
        return user;
    }

    @Test
    public void testGetUserList(){
        ApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml");
        UserService userService = context.getBean("userServiceImpl", UserService.class);
        List<User> userList =userService.getUserList();
        for (User user : userList) {
            System.out.println(user);
        }
    }

    @Test
    public void testGetUserById(){
        ApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml");
        UserService userService = context.getBean("userServiceImpl", UserService.class);
        User user = userService.getUserById(3);
        System.out.println(user);
    }
}

二、整合方式二-使用 SqlSession

在 MyBatis 中,你可以使用 SqlSessionFactory 來建立 SqlSession。 一旦你獲得一個 session 之後,你可以使用它來執行映射了的語句,提交或回滾連線,最後,當不再需要它的時候,你可以關閉 session。 使用 MyBatis-Spring 之後,你不再需要直接使用 SqlSessionFactory 了,因為你的 bean 可以被注入一個執行緒安全的 SqlSession,它能基於 Spring 的事務配置來自動提交、回滾、關閉 session。第二種方式又包括以下兩種方式:

2.1 使用SqlSessionTemplate

SqlSessionTemplate 是 MyBatis-Spring 的核心。作為 SqlSession 的一個實現,這意味著可以使用它無縫代替你程式碼中已經在使用的 SqlSessionSqlSessionTemplate 是執行緒安全的,可以被多個 DAO 或對映器所共享使用。

當呼叫 SQL 方法時(包括由 getMapper() 方法返回的對映器中的方法),SqlSessionTemplate 將會保證使用的 SqlSession 與當前 Spring 的事務相關。 此外,它管理 session 的生命週期,包含必要的關閉、提交或回滾操作。另外,它也負責將 MyBatis 的異常翻譯成 Spring 中的 DataAccessExceptions

由於模板可以參與到 Spring 的事務管理中,並且由於其是執行緒安全的,可以供多個對映器類使用,你應該總是SqlSessionTemplate 來替換 MyBatis 預設的 DefaultSqlSession 實現。在同一應用程式中的不同類之間混雜使用可能會引起資料一致性的問題。

可以使用 SqlSessionFactory 作為構造方法的引數來建立 SqlSessionTemplate 物件。

2.2 SqlSessionDaoSupport

SqlSessionDaoSupport 是一個抽象的支援類,用來為你提供 SqlSession。呼叫 getSqlSession() 方法你會得到一個 SqlSessionTemplate,之後可以用於執行 SQL 方法,就像下面這樣:

2.3 小結

  • 詳細方法見官網:

    http://mybatis.org/spring/zh/sqlsession.html#

  • 注入對映器(參照方式一),與其在資料訪問物件(DAO)中手工編寫使用 SqlSessionDaoSupportSqlSessionTemplate 的程式碼,還不如讓 Mybatis-Spring 為你建立一個執行緒安全的對映器,這樣你就可以直接注入到其它的 bean 中了,如下面使用構造器注入,也可以使用屬性注入。

    <bean id="fooService" class="org.mybatis.spring.sample.service.FooServiceImpl">
      <constructor-arg ref="userMapper" />
    </bean>