mybatis-spring:mybatis在spring中的使用

原创
2019/01/08 17:54
阅读数 5.8K

当我们想在 spring 项目中使用 mybatis 的时候就需要 mybatis-spring 了,它可以让 spring 完美的整合 mybatis 代码。使用这个类库中的类,spring 将会加载必要的 mybatis 工厂类和 session 类。 这个类库也提供一个简单的方式来注入 mybatis 数据映射器和 SqlSession 到业务层的 bean 中。 而且它也会处理事务, 翻译 MyBatis 的异常到 Spring 的 DataAccessException 异常(数据访问异常)中

我们先走一个简单例子,再在基础上扩展

一、例子

1、添加依赖

使用 mybatis-spring 模块,需要添加 mybatis-spring-x.x.x.jar

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

同时加上 mybatis-x.x.x.jar 包和相关数据库连接包,spring 的依赖添加上 spring-context 和 spring-jdbc,如果是 web 项目,再加上 web 相关的 jar 包即可

2、创建 SqlSessionFactoryBean

我们在使用 mybatis 的时候,最关键的是去使用 SqlSession 去执行映射的 SQL 语句。而 SqlSession 是通过 SqlSesionFactory 来获取的。而 SqlSessionFactory 的实例则是由SqlSessionFactoryBuilder 从 XML 配置文件或一个预先定制的 Configuration 的实例构建出来的

现在,我们是要在 spring 上整合 mybatis,需要把 SqlSessionFactory 的创建和 注入交给 spring容器,在 mybatis-spring 中 SqlSessionFactory 的创建交给了 SqlSessionFactoryBean

我们在项目中创建一个 spring 的配置文件,添加相关配置,加上 SqlSessionFactoryBean 的配置
application-mybatis.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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 使用注解声明 -->
    <context:component-scan base-package="com.brave"/>

    <!-- 加载属性资源 -->
    <context:property-placeholder location="classpath*:conf/*.properties"></context:property-placeholder>

    <!-- 配置 SqlSessionFactoryBean  -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 数据源 -->
        <property name="dataSource" ref="dataSource" />
        <!-- mybatis 配置文件位置(默认配置的话,可以不用)-->
        <property name="configLocation" value="classpath:conf/mybatis/mybatis-config.xml"></property>
        <!-- 配置映射器文件 -->
        <property name="mapperLocations" value="classpath*:com/brave/dao/mapper/*Mapper.xml" />
    </bean>

    <!-- 配置数据源 -->
    <!-- 这里使用的是 druid 连接池,需要另外导入 druid.jar -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" 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="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
</beans>

要注意 SqlSessionFactoryBean 实现了 Spring 的 FactoryBean 接口。 这就说明了由 Spring 最终创建的 bean 不是 SqlSessionFactoryBean 本身。 而是工厂类的 getObject()返回的方法的结果。这种情况下,Spring 将会在应用启动时为你 创建 SqlSessionFactory 对象,然后将它以 SqlSessionFactory 为名来存储。在 Java 中, 相同的代码是:
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
SqlSessionFactory sessionFactory = factoryBean.getObject();
但是一般我们不直接使用 SqlSessionFactoryBean 或 SqlSessionFactory。因为 session 工厂将会被注入到映射器中 或其它扩展了 SqlSessionDaoSupport 的 DAO(Data Access Object,数据访问对象)中

SqlSessionFactory有三个属性

  • dataSource 属性是必须的,配置数据源信息
  • configLocation 属性用来指定 MyBatis 的 XML 配置文件路径,如果基本的 MyBatis 配置需要改变(通常这会是<settings> 或<typeAliases>的部分)
  • mapperLocations 属性用来指定映射器文件的资源位置

mapperLocations 可以配置多个位置

<property name="mapperLocations">
    <list>
        <value>classpath*:conf/mybatis/**/*Mapper.xml</value>
        <value>classpath*:conf/com/brave/**/*Mapper.xml</value>
    </list>
</property>

3、使用 SqlSessionTemplate

在 mybatis 中,我们使用 SqlSessionFactory 来创建 SqlSession。获取了一个 session 之后,使用它来执行映射的 SQL 语句、提交或回滚连接,最后当不再需要它的时候关闭 session。
使用 mybatis-spring 之后,就不需要直接使用 SqlSessionFactory 了,因为你的 bean 可以通过一个线程安全的 SqlSession 来注入,基于 spring 的事务配置来自动提交、回滚、关闭 session。

1)SqlSessionTemplate

SqlSessionTemplate 是 mybatis-spring 的核心。它负责管理 mybatis 的 SqlSession, 调用 mybatis 的 SQL 方法、翻译异常。它是线程安全的,可以被多个 DAO 所共享使用。
当调用 SQL 方法时,包含从映射器 getMapper()方法返回的方法,SqlSessionTemplate 将会保证使用的 SqlSession 是和当前 Spring 的事务相关的。它管理这 session 的生命周期,包含必要的关闭,提交或回滚操作。

SqlSessionTemplate 对象可以使用 SqlSessionFactory 作为构造方法的参数来创建

<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
  <constructor-arg index="0" ref="sqlSessionFactory" />
  <!-- 配置了BATCH 表示所有的语句可以批量操作 -->
  <constructor-arg index="1" value="BATCH" />
</bean>

SqlSessionTemplate 实现了 SqlSession 接口,不用再代码中对 mybatis 的 SqlSession 进行替换,直接在 Dao bean中直接注入这个 SqlSession 属性就可以了

@Repository
public class UpmsUserDaoImpl implements UpmsUserDao {

    @Autowired
    private SqlSession sqlSession;

    @Override
    public UpmsUser selectOne(Long userId) {
        return sqlSession.selectOne("com.brave.dao.UpmsUserDao.selectOne", userId);
    }

    @Override
    public List<UpmsUser> selectUser(UpmsUser upmsUser) {
        return sqlSession.selectList("com.brave.dao.UpmsUserDao.selectUser", upmsUser);
    }

    @Override
    public int insertUser(UpmsUser upmsUser) {
        return sqlSession.insert("com.brave.dao.UpmsUserDao.insertUser", upmsUser);
    }
}

这里附上我的映射文件 upmsUserMapper.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.brave.dao.UpmsUserDao">

    <resultMap type="com.brave.model.UpmsUser" id="upmsUser">
        <id column="user_id" property="userId"/>
        <result column="loginname" property="loginname"/>
        <result column="password" property="password"/>
        <result column="realname" property="realname"/>
        <result column="phone" property="phone"/>
        <result column="email" property="email"/>
        <result column="is_locked" property="locked"/>
        <result column="gmt_create" property="gmtCreate"/>
        <result column="gmt_modified" property="gmtModified"/>
    </resultMap>

    <select id="selectOne" resultMap="upmsUser">
         select * from upms_user where user_id = #{userId} 
    </select>

    <select id="selectUser" resultMap="upmsUser">
        select * from upms_user
        <where>
            <if test="loginname != null and loginname != '' ">
                loginname like #{loginname}
            </if>
            <if test="realname != null and realname != '' ">
                and realname like #{realname}
            </if>
        </where>
    </select>
    
    <insert id="insertUser">
        insert into upms_user (user_id,loginname,password,realname,is_locked)
        value(#{userId},#{loginname},#{password},#{realname},#{locked})
    </insert>

</mapper>

使用 Junit 生成测试类

@RunWith(SpringJUnit4ClassRunner.class)  //使用junit4进行测试  
@ContextConfiguration ("/conf/spring/applicationContext*.xml") 
public class UpmsUserDaoImplTest {
    
    @Autowired
    private UpmsUserDao upmsUserDao;

    @Test
    public void testSelectOne() {
        System.out.println(upmsUserDao.selectOne(10001L).toString());
    }

    @Test
    public void testSelectUser() {
        UpmsUser user = new UpmsUser();
        user.setLoginname("zou");
        user.setUserId(2L);
        List<UpmsUser> upmsUsers = upmsUserDao.selectUser(user);
        for (UpmsUser upmsUser : upmsUsers) {
            System.out.println(upmsUser.toString());
        }
    }

    @Test
    @Transactional //声明需要事务
    public void testInsertUser() {
        UpmsUser upmsUser = new UpmsUser();
        upmsUser.setUserId(10002L);
        upmsUser.setLoginname("zou");
        upmsUser.setPassword("123456");
        upmsUser.setLocked(false);
        int n = upmsUserDao.insertUser(upmsUser);
        System.out.println("插入" + n + "行");
    }
}

2) SqlSessionDaoSupport

SqlSessionDaoSupport 是一个抽象的支持类,用来提供 SqlSession。getSqlSession()方法可以得到一个 SqlSessionTemplate

public class UpmsUserDaoImpl2 extends SqlSessionDaoSupport implements UpmsUserDao {
    @Override
    public UpmsUser selectOne(Long userId) {
        return getSqlSession().selectOne("com.brave.dao.UpmsUserDao.selectOne", userId);
    }
}

SqlSessionDaoSupport 需要设置一个 sqlSessionFactory 或 sqlSessionTemplate 属性
假如是 UpmsUserDaoImpl2 继承了 SqlSessionDaoSupport:

<bean id="upmsUserDaoImpl" class="com.brave.dao.UpmsUserDaoImpl2">
  <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

可以创建一个公用的 SuperDao 去继承 SqlSessionDaoSupport,为 SuperDao 设置 sqlSessionFactory 属性,然后让其他 dao 去继承 SuperDao,这样就不用每个 dao 都去设置这个属性了

public class SuperDao extends SqlSessionDaoSupport {
    @Autowired
    public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
       super.setSqlSessionFactory(sqlSessionFactory);
    }
}

不过通常我们更常用 MapperFactoryBean(只需要接口,不用实现类),因为它不需要额外的代码。但是如果需要在 DAO 中做其它非 MyBatis 的工作或需要具体的类,那么这个类就很有用了。

二、事务

mybatis-spring 允许 mybatis 参与到 spring 的事务管理中。利用了存在于 Spring 中的 DataSourceTransactionManager,而不是创建一个新的特定的事务管理器

一旦 Spring 的 PlatformTransactionManager 配置好了,可以在 spring 中以通常的做法来配置事务。@Transactional 注解和 AOP 样式的配置都是支持的。在事务处理期间,一个单独的 SqlSession 对象将会被创建和使用。当事务完成时,这个 session 会以合适的方式提交或回滚。

一旦事务创建之后,mybatis-spring 将会透明的管理事务。在你的 DAO 类中就不需要额外的代码了

1、标准配置

要 开 启 Spring 的 事 务 处 理 , 在 Spring 的 XML 配 置 文 件 中 简 单 创 建 一 个 DataSourceTransactionManager 对象:

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource" />
</bean>

三、注入映射器

在 mybatis 中,我们可以创建一个来绑定映射的语句的接口映射器(实际上也就是我们的 dao 接口),在映射文件的命名空间与我们的映射器完全限定名一致,映射语句id名就是映射器的方法名,这样我们可以不用实现这个映射器,通过 sqlSession 获取映射器,直接使用 sql 方法

UpmsUserDao upmsUserDao = sqlSession.getMapper(UpmsUserDao.class);
UpmsUse upmsUse = upmsUserDao.selectOne(10002L);

为了代替手工使用 SqlSessionDaoSupport 或 SqlSessionTemplate 编写数据访问对象 (DAO)的代码,mybatis-spring 也提供了一个动态代理的实现:MapperFactoryBean。这个类可以让你直接注入 数据映射器接口 到你的 service 层 bean 中。当使用映射器时,直接调用就可以了,不需要实现 DAO接口,因为 mybatis-spring 将会为你创建代理。

使用注入的映射器代码,在 mybatis、spring 或 mybatis-spring 上面不会有直接的依赖。 MapperFactoryBean 创建的代理控制开放和关闭 session,会翻译任意的异常到 spring 的 DataAccessException 异常中。此外,如果需要或参与到一个已经存在活动事务中,代理将会开启一个新的 spring 事务。

1、MapperFactoryBean

想要直接使用 数据映射器接口,先添加 MapperFactoryBean 到 spring 中:

<bean id="upmsUserMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
    <property name="mapperInterface" value="com.brave.mapper.UpmsUserMapper" />
    <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

MapperFactoryBean 创建的代理类实现了 UpmsUserMapper 接口,并且注入到应用程序中。 因为代理创建在运行时环境中,那么指定的映射器必须是一个接口,而不是一个具体的实现类。

如果 XML 映射器文件在类路径的位置和映射器类相同时,它会被 MapperFactoryBean 自动解析,否则你需要在 SqlSessionFactoryBean 的 mapperLocations 或是在 mybatis 的配置文件中指明映射文件的位置

这里附上映射文件,这里的命名空间一定要是映射器的完全限定名

<?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.brave.mapper.UpmsUserMapper">
    <!-- 这里的id与映射器的方法一致 -->
    <select id="selectUser" resultType="com.brave.model.UpmsUser">
        select * from upms_user
    </select>
</mapper>

接口映射器 UpmsUserMapper.java

public interface UpmsUserMapper {
    List<UpmsUser> selectUser();
}

然后我们在应用程序逻辑中可以直接使用

@Service
public class UpmsUserServiceImpl implements UpmsUserService {
    @Autowired
    private UpmsUserMapper upmsUserMapper;

    @Override
    public List<UpmsUser> listUser() {
         return upmsUserMapper.selectUser();
    }
}

2、MapperScannerConfigurer

我们没有必要在 spring 的 XML 配置文件中注册所有的映射器。只用使用一个 MapperScannerConfigurer 即可,它会查找类路径下的映射器并自动将它们创建成 MapperFactoryBean

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

这样就不用每个 mapper 都配置一个 MapperFactoryBean 了

basePackage 属性是让你为映射器接口文件设置基本的包路径。 可以使用 分号 或 逗号 作为分隔符设置多于一个的包路径。每个映射器将会在指定的包路径中递归地被搜索到

3、@MapperScan 和 mybatis:scan

另外还有两种扫描映射器的方法

  • <mybatis:scan> 元素
  • @MapperScan 注解

1) <mybatis:scan> 元素

<mybatis:scan> 元素将在特定的以逗号分隔的包名列表中搜索映射器 mapper 接口。 要使用这个元素需要添加以下的 schema 声明

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:mybatis="http://mybatis.org/schema/mybatis-spring"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://mybatis.org/schema/mybatis-spring
        http://mybatis.org/schema/mybatis-spring.xsd">
    
    <mybatis:scan base-package="com.brave.mapper" />

</beans>

2) @MapperScan

如果使用基于java的配置,可以使用@MapperScan 注解来扫描映射器 Mapper 接口。 @MapperScan 和 <mybatis:scan/> 工作方式 相同,并且也提供了对应的自定义选项
在 spring-boot 项目中可能会使用到

@SpringBootApplication  
@MapperScan("com.brave.mapper")  
public class App {  
    public static void main(String[] args) {  
       SpringApplication.run(App.class, args);  
    }  
} 
展开阅读全文
加载中

作者的其它热门文章

打赏
0
2 收藏
分享
打赏
0 评论
2 收藏
0
分享
返回顶部
顶部
返回顶部
顶部