美文网首页
spring整合mybatis

spring整合mybatis

作者: 水煮鱼又失败了 | 来源:发表于2020-08-06 08:18 被阅读0次

1 场景

spring中整合mybatis。

mybatis官网:https://mybatis.org/mybatis-3/zh/index.html

spring-mybatis官网:http://mybatis.org/spring/zh/index.html

1.1 版本说明

jdk版本:1.8

spring版本:5.2.2.RELEASE

mysql版本:5.6.27 innoDb数据库引擎

1.2 代码地址

https://github.com/yjhcpdd/mymvc

1.3 项目结构

--java
--resources
    --conf
        -mybatis-config.xml*[1]
        -spring.xml*********[4]
        -spring-mvc.xml
        -sping-mybatis.xml**[2]
    --properties
        -system.properties
        -jdbc.properties****[3]

java外层包路径为:com.demo.cs

相关包路径如下:
com.demo.cs.template.bean
com.demo.cs.template.controller
com.demo.cs.template.mapper.auto.model
com.demo.cs.template.mapper.auto.xml
com.demo.cs.template.mapper.ext
com.demo.cs.template.mapper.ext.model
com.demo.cs.template.mapper.ext.xml
com.demo.cs.template.service
com.demo.cs.template.service.impl

1.4 建表语句

CREATE TABLE `temp_db_user` (
`id`  int UNSIGNED NOT NULL AUTO_INCREMENT ,
`user_name`  varchar(50) NULL DEFAULT '' ,
`age`  int NULL ,
PRIMARY KEY (`id`)
);

2 整合步骤

2.1 配置maven依赖

pom.xml中配置相关依赖包(完整配置,可参见源码):

 <properties>
     ......
     <mysql.connector.java>5.1.30</mysql.connector.java>
 </properties>
 
<dependencies>
    ....
    <!-- ==========【mybatis相关】========== -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>${mysql.connector.java}</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.5</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.5</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.23</version>
    </dependency>
</dependencies>

<build>
    <resources>
        <!-- 将src/main/java目录下的xml文件,也进行打包 -->
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.xml</include>
            </includes>
            <!-- 默认情况下使用false,不进行过滤替占位符。为true的情况下,将会使得编译后目录下的doc,excel等二进制文件受影响无法打开 -->
            <filtering>false</filtering>
        </resource>
    </resources>
</build>

2.2 配置数据库配置文件

创建数据库配置文件jdbc.properties[3],增加如下配置:

#mysql数据库连接配置
mysql.jdbc.driver=com.mysql.jdbc.Driver
mysql.jdbc.url=jdbc:mysql://localhost:3306/db_test
mysql.jdbc.username=root
mysql.jdbc.password=root

2.3 创建spring全局配置

创建文件mybatis-config.xml[1],配置spring全局参数:

<?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>
    <settings>
        <!-- 全局性地开启所有映射器配置文件中已配置的任何缓存 -->
        <setting name="cacheEnabled" value="true"/>
        <!-- 指定 MyBatis 所用日志的具体实现,未指定时将自动查找 -->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
</configuration>

2.4 spring整合mybatis

创建文件sping-mybatis.xml[2],在spring中整合mybatis。

<?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:tx="http://www.springframework.org/schema/tx"
       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/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- =====数据源===== -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <property name="driverClassName" value="${mysql.jdbc.driver}"/>
        <property name="url" value="${mysql.jdbc.url}"/>
        <property name="username" value="${mysql.jdbc.username}"/>
        <property name="password" value="${mysql.jdbc.password}"/>
    </bean>

    <!-- =====session工厂===== -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <!-- mybatis全局配置文件 -->
        <property name="configLocation" value="classpath:conf/mybatis-config.xml"/>
        <!-- 加载mapper配置文件
            (默认“src/main/java”路径下,只有.class文件会放到编译后的目录进行打包,其他xml等文件不会放到编译后目录,需在pom文件的build环节配置)
            (需用"classpath*:",而不是"classpath:",否则单元测试时,无法加载到Mapper.xml)
        -->
        <property name="mapperLocations" value="classpath*:com/demo/cs/**/*.xml"/>
    </bean>
    
    <!-- =====mapper包扫描器,将扫描到的接口注册为dao层的bean===== -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
        <!-- 包扫描路径 -->
        <property name="basePackage" value="com.demo.cs.template.mapper.auto,com.demo.cs.template.mapper.ext"/>
    </bean>

    <!-- =====事务管理器===== -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- =====事务支持一:支持式注解事务(@Transactional);注解式事务order为0,“注解事务”优先“声明式事务”===== -->
    <tx:annotation-driven transaction-manager="transactionManager" order="0" />
    
    <!-- =====事务支持二:支持声明式事务(方法名匹配);声明式事务order为1,“注解事务”优先“声明式事务”===== -->
    <!-- 事务传播特性(事务通知) -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!-- REQUIRED:如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务 -->
            <tx:method name="insert*" propagation="REQUIRED" rollback-for="Exception"/>
            <tx:method name="update*" propagation="REQUIRED" rollback-for="Exception"/>
            <tx:method name="delete*" propagation="REQUIRED" rollback-for="Exception"/>
            <!-- SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行 -->
            <tx:method name="find" propagation="SUPPORTS" read-only="true"/>
            <tx:method name="get" propagation="SUPPORTS" read-only="true"/>
        </tx:attributes>
    </tx:advice>
    <!-- 配置切面,使事务生效 -->
    <aop:config >
        <!-- 切点(配置增强业务点) -->
        <aop:pointcut id="txPointcut" expression="execution(* com.demo.cs..*Service.*(..))"/>
        <!-- 通知(增强) -->
        <aop:advisor id="txAdvisor" advice-ref="txAdvice" pointcut-ref="txPointcut" order="1" />
    </aop:config>
</beans>

同时,在web.xml文件中加载spring配置文件时,增加对sping-mybatis.xml文件的加载:

<!-- ============【spring配置】============ -->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        classpath:conf/spring.xml,
        classpath:conf/spring-mybatis.xml
    </param-value>
</context-param>

3 代码示例

在包com.demo.cs.template.mapper.ext中创建mapper的接口文件,在包com.demo.cs.template.mapper.ext.xml中创建mapper的xml配置文件。

数据库表temp_db_user对应实体类如下:

@Data
public class ExtTempDbUser {
    private Integer id;    
    private String userName;
    private Integer age;
}

3.1 xml配置

接口:

public interface ExtTempDbUserMapper {
    List<ExtTempDbUser> getRecordList(ExtTempDbUser model);
    void insertRecord(ExtTempDbUser model);
}

xml配置文件:

<mapper namespace="com.demo.cs.template.mapper.ext.ExtTempDbUserMapper">
    <select id="getRecordList" parameterType="com.demo.cs.template.mapper.ext.model.ExtTempDbUser" resultType="com.demo.cs.template.mapper.ext.model.ExtTempDbUser">
        select id,user_name,age from temp_db_user
        <where>
            <if test="id!=null">
                and id = #{id}
            </if>
            <if test="userName!=null and userName!=''">
                and user_name =#{userName}
            </if>
            <if test="age!=null">
                and age = #{age}
            </if>
        </where>
    </select>
    <insert id="insertRecord" parameterType="com.demo.cs.template.mapper.ext.model.ExtTempDbUser">
        insert into temp_db_user(id,user_name,age)value(
            #{id},#{userName},#{age}
        )
    </insert>
</mapper>

3.2 注解配置

接口:

public interface ExtTempDbUserMapper {
    @Delete("delete from temp_db_user where id=#{id}")
    void deleteRecordById(int id);
}

3.3 spring调用

@Autowired
private ExtTempDbUserMapper extTempDbUserMapper;

4 事务校验

通过spring-mybatis.xml文件中的事务切面通知配置,可以知道,aop通过对service中的方法名进行匹配后,进行了事务增强。

<!-- 事务传播特性(事务通知) -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <!-- REQUIRED:如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务 -->
        <tx:method name="insert*" propagation="REQUIRED" rollback-for="Exception"/>
        <tx:method name="update*" propagation="REQUIRED" rollback-for="Exception"/>
        <tx:method name="delete*" propagation="REQUIRED" rollback-for="Exception"/>
        <!-- SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行 -->
        <tx:method name="find" propagation="SUPPORTS" read-only="true"/>
        <tx:method name="get" propagation="SUPPORTS" read-only="true"/>
    </tx:attributes>
</tx:advice>

如果以bean的形式调用service方法时(非内部的this调用),如果方法前缀满足要求(insert开头、update开头、delete开头、find开头、find开头),则会进行相应的事务控制事务传播属性的控制。如果service方法不满足前缀要求,此service方法,则不会受spring的事务管理

此章节主要通过mybatis执行日志的形式,查看:当事务管理器管理的方法调用非事务管理器管理的方法的影响。

4.1 带事务批量操作

调用:

tempDbUserService.insertBatch();

service代码:

@Override
public void insertBatch() {
    ExtTempDbUser model1=new ExtTempDbUser();
    model1.setUserName("测试1");
    extTempDbUserMapper.insertRecord(model1);
    ExtTempDbUser model2=new ExtTempDbUser();
    model2.setUserName("测试2");
    extTempDbUserMapper.insertRecord(model2);
}

日志:

Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@23d1e5d0]
JDBC Connection [com.mysql.jdbc.JDBC4Connection@315f43d5] will be managed by Spring
==>  Preparing: insert into temp_db_user(id,user_name,age)value( ?,?,? )
==> Parameters: null, 测试1(String), null
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@23d1e5d0]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@23d1e5d0] from current transaction
==>  Preparing: insert into temp_db_user(id,user_name,age)value( ?,?,? )
==> Parameters: null, 测试2(String), null
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@23d1e5d0]
Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@23d1e5d0]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@23d1e5d0]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@23d1e5d0]

结论:

开启事务,service内的每个数据库操作,共用一个JDBCConnection315f43d5共用一个session连接23d1e5d0(session的id都一致),一起提交。

4.2 无事务批量操作

调用:

tempDbUserService.noTransInsertBatch();

service代码:

public void noTransInsertBatch() {
    ExtTempDbUser model1=new ExtTempDbUser();
    model1.setUserName("测试1");
    extTempDbUserMapper.insertRecord(model1);
    ExtTempDbUser model2=new ExtTempDbUser();
    model2.setUserName("测试2");
    extTempDbUserMapper.insertRecord(model2);
}

日志:

Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2cc3ad05] was not registered for synchronization because synchronization is not active
JDBC Connection [com.mysql.jdbc.JDBC4Connection@3569fc08] will not be managed by Spring
==>  Preparing: insert into temp_db_user(id,user_name,age)value( ?,?,? )
==> Parameters: null, 测试1(String), null
<==    Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2cc3ad05]
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7ac2e39b] was not registered for synchronization because synchronization is not active
JDBC Connection [com.mysql.jdbc.JDBC4Connection@3569fc08] will not be managed by Spring
==>  Preparing: insert into temp_db_user(id,user_name,age)value( ?,?,? )
==> Parameters: null, 测试2(String), null
<==    Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@7ac2e39b]

结论:

service内的每个方法,共用一个connection都会使用新的session连接(非事务控制的session,session的id都不一致2cc3ad05/7ac2e39b,但是共用一个数据库连接3569fc08),自己单独提交。

4.3 多个带事务的方法

调用:

System.out.println("----------第一个事务调用----------");
tempDbUserService.insertBatch();
System.out.println("----------第二个事务调用----------");
tempDbUserService.insertBatch();

代码:

@Override
public void insertBatch() {
    ExtTempDbUser model1=new ExtTempDbUser();
    model1.setUserName("测试1");
    extTempDbUserMapper.insertRecord(model1);
    ExtTempDbUser model2=new ExtTempDbUser();
    model2.setUserName("测试2");
    extTempDbUserMapper.insertRecord(model2);
}

日志:

----------第一个事务调用----------
Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@23d1e5d0]
JDBC Connection [com.mysql.jdbc.JDBC4Connection@315f43d5] will be managed by Spring
==>  Preparing: insert into temp_db_user(id,user_name,age)value( ?,?,? )
==> Parameters: null, 测试1(String), null
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@23d1e5d0]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@23d1e5d0] from current transaction
==>  Preparing: insert into temp_db_user(id,user_name,age)value( ?,?,? )
==> Parameters: null, 测试2(String), null
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@23d1e5d0]
Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@23d1e5d0]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@23d1e5d0]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@23d1e5d0]
----------第二个事务调用----------
Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@435fb7b5]
JDBC Connection [com.mysql.jdbc.JDBC4Connection@315f43d5] will be managed by Spring
==>  Preparing: insert into temp_db_user(id,user_name,age)value( ?,?,? )
==> Parameters: null, 测试1(String), null
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@435fb7b5]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@435fb7b5] from current transaction
==>  Preparing: insert into temp_db_user(id,user_name,age)value( ?,?,? )
==> Parameters: null, 测试2(String), null
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@435fb7b5]
Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@435fb7b5]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@435fb7b5]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@435fb7b5]

结论:

调用两个事务管理的批量操作,每个事务均会单独提交。

共用一个connection315f43d5,每个事务使用独立的被spring管理的sqlSession(带事务)23d1e5d0/435fb7b5

4.4 事务方法内调用非事务方法

调用:

tempDbUserService.testNestTrasnAndNoTrans();

代码:

@Override
public void insertNestTrasnAndNoTrans() {
    ExtTempDbUser model1=new ExtTempDbUser();
    model1.setUserName("测试1 for trans");
    extTempDbUserMapper.insertRecord(model1);
    ExtTempDbUser model2=new ExtTempDbUser();
    model2.setUserName("测试2 for trans");
    extTempDbUserMapper.insertRecord(model2);
    System.out.println("--------调用非事务管理方法--------");
    tempDbUserService.noTransInsertBatch();
}

@Override
public void noTransInsertBatch() {
    ExtTempDbUser model1=new ExtTempDbUser();
    model1.setUserName("测试1-not trasn");
    extTempDbUserMapper.insertRecord(model1);
    ExtTempDbUser model2=new ExtTempDbUser();
    model2.setUserName("测试2-not trasn");
    extTempDbUserMapper.insertRecord(model2);
}

日志:

Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@704f1591]
JDBC Connection [com.mysql.jdbc.JDBC4Connection@68fa0ba8] will be managed by Spring
==>  Preparing: insert into temp_db_user(id,user_name,age)value( ?,?,? )
==> Parameters: null, 测试1 for trans(String), null
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@704f1591]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@704f1591] from current transaction
==>  Preparing: insert into temp_db_user(id,user_name,age)value( ?,?,? )
==> Parameters: null, 测试2 for trans(String), null
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@704f1591]
--------调用非事务管理方法--------
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@704f1591] from current transaction
==>  Preparing: insert into temp_db_user(id,user_name,age)value( ?,?,? )
==> Parameters: null, 测试1-not trasn(String), null
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@704f1591]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@704f1591] from current transaction
==>  Preparing: insert into temp_db_user(id,user_name,age)value( ?,?,? )
==> Parameters: null, 测试2-not trasn(String), null
<==    Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@704f1591]
Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@704f1591]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@704f1591]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@704f1591]

结论:

此结论很重要,当前受事务管理的service方法,调用非事务管理的service方法时,非事务管理的service方法,也会受事务管理。

相关文章

网友评论

      本文标题:spring整合mybatis

      本文链接:https://www.haomeiwen.com/subject/vnbprktx.html