【框架整合】--- Spring与MyBatis

前言

本章将Mybatis与Spring整合分为了: 整合 事务 两个方面,只是简单的列举了一些例子作为说明,创建本章的目的是备忘。更多技术内幕请参阅:MyBatis-Spring 官方文档

依赖准备

  1. Spring核心依赖
   <!--spring核心-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.3.5</version>
    </dependency>
  1. MyBatis相关依赖
  <!--mybatis整合spring专用-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>2.0.6</version>
    </dependency>
    <!--mybatis-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.6</version>
    </dependency>
  1. MySQL相关驱动
  <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.23</version>
    </dependency>
  1. 事务相关

使用注解方法所使用的的依赖,如果需要使用xml的形式则还需要其他依赖.请查看
本文章的【XML方式管理事务】章节。

  <!--Spring事务-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>5.3.2</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.3.2</version>
    </dependency>
  1. 数据库连接池

在使用Spring-MyBatis.jra包中的SqlSessionFactoryBean时需要一个DataSource类型的参数来创建SqlSession对象。

    <!--数据库连接池-->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.2.2</version>
    </dependency>

整合

以下分别列举了XML和注解两种Spring整合MyBatis的示例。

注解方式整合

XML文件方式比较适合小型项目,开发快速,代码书写快捷。

1. 首先创建Dao类与domain

//实体类
@Component
public class User {
    private long id;
    private String name;
    private int age;
    private String sxe;
	//...省略
}

2.创建DAO接口

此接口中是指mapper.xml的接口。 在此接口中使用注解来声明Sql语句。

@Repository//此注释不可缺省
public interface UserMapper {
   
    @Select("SELECT * FROM user WHERE sxe = #{sxe}")
    public List<User> selectUser(String sxe);
    @Insert("INSERT INTO user (name,age,sxe) VALUES (#{name},#{age},#{sex})")
    public int insertUser(User user);
}

3.声明Service类

@Service//声明此类为一个Service类
public class UserService {
//...省略内容
}

4.声明一个配置类

此配置类名称自定义,此配置类可以完全代替XML文件,此配置类是纯注解的核心,以下示例中的配置仅仅是Spring中使用配置类声明Spring项目可以进行声明设置内容的一小部分,此类使用上是广义的灵活的。

SqlSessionTemplate很必要说明记录:

SqlSessionTemplate 是 MyBatis-Spring 的核心。它实现了 SqlSession 并且旨在替代代码中任何现有的 SqlSession 使用。 SqlSessionTemplate 是线程安全的,可以被多个 DAO 或映射器共享。

当调用 SQL 方法时,包括 getMapper() 返回的 Mappers 中的任何方法,SqlSessionTemplate 将确保使用的 SqlSession 是与当前 Spring 事务关联的那个。此外,它还管理会话生命周期,包括根据需要关闭、提交或回滚会话。它还将 MyBatis 异常转换为 Spring DataAccessExceptions。

应该始终使用 SqlSessionTemplate 而不是默认的 MyBatis 实现 DefaultSqlSession,因为该模板可以参与 Spring 事务并且是线程安全的,可供多个注入的映射器类使用。在同一应用程序中的两个类之间切换可能会导致数据完整性问题

/* 声明这是一个核心配置类。*/
@Configuration

/*将其他子配置文件导入,将此配置类作为所有配置类的入口。*/
/*@Import()*/

/* 声明要创建组件对象的类,包的位置。*/
@ComponentScan({"com.ccnn.domain","com.ccnn.service"})

/*声明 数据源信息文件 的位置*/
@PropertySource("classpath:/jdbc.properties")

/*声明DAO层所在的包的位置*/
/*如果在此配置类中使用了MapperScannerConfigurer来将Mapper作为对象存进了容器中
* 则可以省略此注解,如果使用的是sqlSessionFactoryBean对象(不推荐使用)或者
* sqlSessionTemplate对象(推荐)则需要此注解*/
/*@MapperScan("com.ccnn.dao")*/

/*表示使用Spring中的JDK来代理并使用Spring AOP来处理事务(@Transaction注解的方式)*/
/*@EnableTransactionManagement*/

/*表示使用AspectJ中cglib来代理并使用AOP来处理事务
* 此方式可以与xml配置文件配合将事务处理的过程声明在xml文件中,
* 或正常使用AspectJ AOP。
*
*   proxyTargetClass属性:
*   指示是否要创建基于子类的 (CGLIB) 代理而不是
 *  到标准的基于 Java 接口的代理。默认值为 false。
 *  exposeProxy属性:
 *  指示代理应由 AOP 框架公开为 {@code ThreadLocal}
 *  通过 {@link org.springframework.aop.framework.AopContext} 类检索。
 *  默认关闭,即不保证 {@code AopContext} 访问会起作用
* */
/*@EnableAspectJAutoProxy*/

public class ApplicationConfiguration {
    /*使用SP EL表达式为属性赋值*/
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.maxActive}")
    private int maxActive;

    /*创建数据源*/
    @Bean
    public DataSource druidDataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setUrl(url);
        druidDataSource.setDriverClassName(driver);
        druidDataSource.setUsername(username);
        druidDataSource.setPassword(password);
        druidDataSource.setMaxActive(maxActive);
        return druidDataSource;
    }

    /*创建SqlSessionFactoryBean对象*/
    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(@Autowired DataSource dataSource){
        /*创建druid对象*/
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        /*为对象设置数据源*/
        sqlSessionFactoryBean.setDataSource(dataSource);
		/*指定mapper映射文件位置*/
        sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
        return sqlSessionFactoryBean;
    }
    /* 使用核心对象SqlSessionTemplate而不是SqlSessionFactoryBean。*/
    @Bean("sqlSessionTemplate")//有必要保证此对象一定是这个名称。
    public SqlSessionTemplate sqlSessionTemplate(@Autowired SqlSessionFactoryBean sqlSessionFactoryBean) throws Exception {
        /*关键的一行,请参考官方文档*/
        SqlSessionFactory sessionFactoryBean = (SqlSessionFactory) sqlSessionFactoryBean.getObject();
        assert sessionFactoryBean != null;
        return new SqlSessionTemplate(sessionFactoryBean);
    }
    /*使用sqlSessionTemplate对象和指定Mapper接口的位置将所有Mapper对象都加入
    * 到容器中。直接在容器中使用对象比直接使用sqlSessionTemplate对象要放方便许多。*/
    @Bean
    public static MapperScannerConfigurer mapperScannerConfigurer(){
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        /*声明sqlSessionTemplate对象在容器中的名称*/
        mapperScannerConfigurer.setSqlSessionTemplateBeanName("sqlSessionTemplate");
        /*指定Mapper接口的位置*/
        mapperScannerConfigurer.setBasePackage("com.ccnn.dao");
        return mapperScannerConfigurer;
    }

/*------------------------以上为整合内容以下为事务相关-----------------------------*/


    /*开启事务(创建事务管理器),无论使用的是使用 @Transactional 注解配合 AOP 来配置事务
    * 还是使用 xml 的方式 使用Aspectj中的AOP管理事务来处理事务都需要此创建
    * DataSourceTransactionManager对象*/
   /* @Bean
    public DataSourceTransactionManager DataSourceTransactionManager(@Autowired DataSource dataSource){
       return new DataSourceTransactionManager(dataSource);
    }*/
}

5.测试
以上内容已经完成了整合。

 @Test
    public void test(){


     ApplicationContext applicationContext =
               new AnnotationConfigApplicationContext(ApplicationConfiguration.class);
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String s: beanDefinitionNames){
            System.out.println(s);
        }
        /*
        获取的对象
        user
        userService
        druidDataSource
        sqlSessionFactoryBean
        sqlSessionTemplate
        mapperScannerConfigurer
        userMapper*/
    }

XML文件方式整合

XML文件方式比较适合多模块的大型项目,每个模块中使用自己的xml文件方便管理。

1. 首先创建Dao类与domain

//实体类
public class User {
    private long id;
    private String name;
    private int age;
    private String sxe;
	//...省略
}

2. 创建Mapper映射接口

在此接口中声明SQL语句。

//Mapper映射接口
public interface UserMapper {
    /**
     * 查询语句
     * @param sxe 用户性别
     * @return 性别为某个值的所有用户
     */
    public List<User> selectUser(String sxe);
}

3. 准备数据源信息

创建一个xxx.properties文件。此文件用来声明数据库连接信息以及Druid连接池的配置信息。Druid连接池的更多配置请参考官网。

jdbc.username=root
jdbc.password=123456
jdbc.url=jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Shanghai
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.maxActive=5
//.....省略


4. 创建MyBatis的Mapper映射文件。

<?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.ccnn.mapper.UserMapper">

    <select id="selectUser" resultType="com.ccnn.domain.User" parameterType="java.lang.String">
        SELECT * FROM user WHERE sxe = #{sxe}
    </select>

</mapper>

5. 创建Spring配置文件(重点)

此配置文件中将负责:

- 创建其他需要由Spring管理的对象
- 声明数据源
- 创建Druid连接池对象
- 创建sqlSessionFactoryBean对象
- 将所有Mapper映射对象放入容器中

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 https://www.springframework.org/schema/context/spring-context.xsd">
		
		<!--省略业务和逻辑对象-->

        <!--将数据源信息配置在外部文件中-->
        <context:property-placeholder location="classpath:jdbc.properties"/>

        <!--创建数据源对象并声明数据源值从上面的jdbc.properties中读取-->
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
                        init-method="init" destroy-method="close">
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
                <property name="driverClassName" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="maxActive" value="${jdbc.maxActive}"/>
        </bean>



        <!--
        在spring与mybatis整合中获取SqlSession对象的方式与基础版mybatis不同,
        需要使用Spring-mybatis中的SqlSessionFactoryBean来获取对象,而这个对
        象需要数据源信息,此对象是线程安全的。
        -->
        <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
                <property name="dataSource" ref="dataSource"/>
                <!--如果在MyBatis中除了数据源以及mapper映射文件外没有其他配置可以省略掉此属性-->
               <!-- <property name="configLocation" value="classpath:MyBatisConfiguration.xml"/>-->
                <property name="mapperLocations" value="mapper/*.xml"/><!--此处将mapper.xml声明在了resource目录下-->
                  <!-- 自 1.3.0 版本开始,新增的 configuration 属性能够在没有对应的 MyBatis XML 配置文件的情况下,直接设置 Configuration 实例-->
                <property name="configuration">
                        <bean class="org.apache.ibatis.session.Configuration">
                                <property name="mapUnderscoreToCamelCase" value="true"/>
                        </bean>
                </property>
        </bean>



        <!--
            获取SqlSession对象

                使用SqlSession的实现类SqlSessionTemplate来替换默认的DefaultSqlSession
                此类是安全的提供了多个映射器类,将此对象作为属性声明在类中并未此类的此属性赋值。
        -->
        <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
                <constructor-arg index="0" ref="sqlSessionFactoryBean"/>
        </bean>



        <!--
             一次性将所有dao对象创建出来,并交由容器管理。此操作等于使用SqlSession,getMapper(xx);
             将mapper包中的所有对象都创建出来。此时对象已在容器中请在容器中查找与mapper接口同名的对象。
        -->
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
                <!--声明sqlSessionFactory对象-->
                <property name="sqlSessionTemplateBeanName" value="sqlSessionTemplate"/>
                <!--设置mapper接口的位置-->
                <property name="basePackage" value="com.ccnn.mapper"/>
        </bean>

</beans>

  1. 测试
public void test(){

        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("ApplicationConfiguration.xml");
		//此时所有Mapper映射对象都已在容器中存在,可以直接使用对象来执行sql语句。                
        UserMapper userMapper = (UserMapper) applicationContext.getBean("userMapper");
        System.out.println(userMapper);
        List<User> userList = userMapper.selectUser("男");
        for (User user:userList){
            System.out.println(user.toString());//User{id=0001, name='张三', age=25, sxe='男'}
        }


    }

事务

以下将事务分为了使用注解声明事务和使用XML文件声明事务,两种方式各有优缺点,请根据业务需求选择。

注解方式管理事务

Spring 支持使用 @Transactional 注解配合 AOP 来配置事务。

在小型项目中使用xml的方式更合理。

@Transactional注解的常用属性值:

属性概述默认值
value/transactionManager当配置了多个事务管理器时,可以使用该属性指定选择哪个事务管理器null
propagation事务的传播行为Propagation.REQUIRED
isolation事务的隔离级别Isolation.DEFAULT
timeout事务的超时时间 ,如果超过该时间限制但事务还没有完成,则自动回滚事务-1(不指定超时时间)
readOnly指定事务是否为只读事务,为了忽略那些不需要事务的方法false
rollbackFor当触发这些异常时回滚,可以指定多个异常类型null
noRollbackFor抛出指定的异常类型不回滚事务,也可以指定多个异常类型null

配置Spirng AOP处理事务需要:

- 声明事务管理器
- 开启事务管理器
- 为事务管理类添加@Transactional注解

1. 整合,使用以上两种的任意一种。

2. 为XML文件添加关于事务处理的标签

!!!请在整合中的Spring.xml配置文件中内容的最后处追加

        <!--声明由Spirng处理事务并声明事务管理器-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
                <constructor-arg ref="dataSource" />
        </bean>

        <!--开启事务注解驱动(通知spring将使用注解的方式声明事务)-->
        <!--!!! 声明标签时注意使用 tx结尾的那个-->
        <!--transaction-manage属性值为上面的事务管理器id-->
        <tx:annotation-driven transaction-manager="transactionManager"/>

3.创建事务处理类

以下示例中为了节省时间,在测试类中使用了简单的例子进行了事务管理。

public class AppTest {

    UserMapper userMapper;

    @Test
    public void test(){
        ApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("ApplicationConfiguration.xml");
        userMapper = (UserMapper) applicationContext.getBean("userMapper");
        //添加
        User user = new User();
        user.setSex("女");
        user.setAge(66);
        user.setName("王花");
        TransactionalTest(user);
        //查询
        System.out.println(userMapper);
        List<User> userList = userMapper.selectUser("男");
        for (User u:userList){
            System.out.println(u.toString());
        }
    }
    //简陋的演示
    @Transactional(
            propagation = Propagation.REQUIRED,
            isolation = Isolation.DEFAULT,
            readOnly = false,
            rollbackFor = {RuntimeException.class}
    )
    public boolean TransactionalTest(User u){
        int i = -1;
        /*如果在添加操作发生了异常*/
        try {
            i = userMapper.insertUser(u);
        }catch (RuntimeException e){
            e.printStackTrace();
        }
        /*添加操作未发生异常但是添加了0条数据*/
        if (i == 0){
            throw new RuntimeException("添加失败");
        }else {
            System.out.println("成功添加了["+i+"]条数据");
            return true;
        }
    }

}

XML方式管理事务

如果有众多的类需要事务此时应该使用Aspectj中的AOP管理事务,这样可以使xml配置文件不臃肿,使得业务代码分离,使代码更加清晰。

使用Aspectj AOP管理事务需要:

- 整合,使用以上两种的任意一种
- 添加Aspectj依赖
- 声明事务管理器
- 声明事务属性
- 配置 AOP

1. 整合,使用以上两种的任意一种

2.添加Aspectj依赖

在以上原有依赖后追加此依赖

 		<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>

3.配置内容

!!!请在整合中的Spring.xml配置文件中内容的最后处追加


        <!--声明由Spirng处理事务并声明事务管理器-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
                <constructor-arg ref="dataSource" />
        </bean>

        <!--声明事务的方法的属性-->
        <!--!!! 声明标签时注意使用 tx结尾的那个-->
        <!--transaction-manage属性值为上面的事务管理器id-->
        <tx:advice id="myAdvice" transaction-manager="transactionManager">
                <tx:attributes>
                        <!--name:方法名称,可以使用通配符,isolation:隔离级别,propagation:传播行为
                        rollback-for:抛出的异常们,(全限定路径名)
                        -->
                        <tx:method name="*test" isolation="DEFAULT" propagation="REQUIRED"
                                   rollback-for="java.lang.RuntimeException"/>
                        <!--...更多方法-->
                </tx:attributes>
        </tx:advice>

        <!--以上并未指定方法们在哪个包下或者说那些包中的方法需要事务,所以需要使用以下配置来声明。-->
        <aop:config>
                <!--指定那些包需要使用事务-->
                <aop:pointcut id="test" expression="execution(* * .. *test(..))"/>
                <!--配置增强器:关联以上事务属性和上面的兄弟标签声明标签-->
                <aop:advisor advice-ref="myAdvice" pointcut-ref="test"/>
        </aop:config>
        

4.测试

不需要其他额外的操作,正常调用事务方法即可。

关于纯事务和纯XML

在初学Spring整合MyBatis时我内心总是对纯注解整合的方式充满冲动,认为纯注解的方式时最完美整洁的,后来遇到多种环境后发现,盲目的追求纯注解或者纯XML的方式都是不可取的。只有在根据当前项目的需求使用合适的方法才是正确的,注解和XML可以结合使用,没有非黑即白的必要,为了满足初心以下详细讲解了纯注解与纯XML的方式(都包含了事务的使用)。

纯注解

使用纯注解需要:

  1. 创建:Dao、Service、组件、Configuration类和一个存储jdbc信息的文件。
    分别使用@RepositoryService@Component@Configuration 注释与类之上。
    声明: Mapper接口中SQL语句(使用注解声明)。
    配置: Configuration类中(请查看【注解方式整合】小节)
  2. 使用Spring来处理事务: 为配置类添加@EnableTransactionManagement注解并创建DataSourceTransactionManager对象。使用@Transaction注释来声明事务内容。(请查看【注解方式管理事务】小节)
    使用AspcetJ来处理事务: 为配置类添加@EnableAspectJAutoProxy注解并创建DataSourceTransactionManager对象。正常使用AOP来声明事务内容(请查看此文章中的AOP小节)。

纯XML方式

使用纯XML方式需要:

  1. 创建:Dao、Service、组件类和 jdbc信息的文件、Mapper映射文件、config配置文件。
    分别使用<bean/>创建这些对象和读取这些文件(请查看【XML配置文件】小节)
  2. !使用Spring来处理事务: 正常使用方法即可。
    使用AspcetJ来处理事务: 使用 <tx:advice/><aop:config/>标签声明事务管理器和切面方法。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值